Skip to main content
Announcements
Introducing Qlik Answers: A plug-and-play, Generative AI powered RAG solution. READ ALL ABOUT IT!
Michael_Tarallo
Employee
Employee

Let's see how it is possible to control sheet and object-level access in Qlik Cloud, specifically when organizations want to show/hide specific assets in an application based on the group membership of the current user that is accessing the application. 

 

2023-06-05_13-06-48.pngHey guys, it's been awhile since we had a guest blogger on, so today I am pleased to introduce you to Daniel Pilla. Daniel is a Master Principal Analytics Platform Architect at Qlik and is part of the Presales organization. He has been with Qlik for 8 years, and specializes in integration, architecture, embedding, and security. Take it away Dan!

 

 

 

Sheet and object-level access control in Qlik Cloud

This is a relatively common request, especially from customers coming from Qlik Sense Enterprise Client-Managed. The use case is when organizations want to show/hide specific assets in an application based on the group membership of the current user that is accessing the application. Note that this is in no way a strategy or solution for data security (which is handled with section access), but rather serves as a potential design pattern for custom tailoring apps for specific groups of users.

Example Scenario

Let’s assume a customer has a global sales application. That application contains sheets that are designed for specific product group sales that not every sales representative sells. The customer wants to show the product-specific sheets only to the sales representatives that sell those respective products. If the user contains the group “Product Group A” then they should see the “Product Group A Analysis” sheet, and likewise if the user contains the group “Product Group B” then they should contain the “Product Group B Analysis” sheet.

Michael_Tarallo_0-1685984516021.png

 

Solution

To achieve this in Qlik Cloud, we can use the Advanced Analytics connector, which in essence is a RESTful server-side extension. This connector offers the ability to connect to RESTful services in real-time from both the load script and from the front-end (charts and expressions). We can use this connector to connect directly to the Qlik Cloud APIs to fetch the groups of the current user, return those groups as a pipe-delimited string, and then use those groups in a show condition expression.

Michael_Tarallo_1-1685984516061.png

 

Setup

Prerequisites:

  • The Advanced Analytics connector is going to be making API calls to Qlik Cloud on behalf of the logged in user. This means that you must have a user with the “Developer” role assigned as well as an API key issued to that user.
  • The Creation of groups setting must be enabled in the Console under Settings > Feature control

Michael_Tarallo_2-1685984516085.png

 

  • Ensure that there are groups available to the user that you are testing for in the tenant. To check this, you can enter the following into the browser, replacing {tenant} and {region} accordingly: https://{tenant}.{region}.qlikcloud.com/api/users/me -- There, you will find the assignedGroups array which contains the groups that are assigned to the logged in user.

Connector Setup:

  1. Import the sample application attached to this page.
  2. Open the application and navigate to the load script.
  3. Under Data connections, select Create new connection and select Advanced Analytics.
  4. For URL, fill in your own tenant for URL followed by ‘/api/v1/users’
    1. https://{tenant}.{region}.qlikcloud.com/api/v1/users
  5. Change the Method to GET.
  6. Under Query Parameters, add a parameter with the Name of ‘filter’ and the Value should resemble the following, where {subject} is an existing user subject for the filter so you can test whether the connection is operational:
    1. {subject co “{subject}”}
    2. In this example, the user I am using has a REALM value. Note that you will have to escape the backslash with an extra backslash, e.g., QLIK-POC\dpi needs to be QLIK-POC\\dpi

Michael_Tarallo_3-1685984516111.png

 

Michael_Tarallo_4-1685984516135.png

 

  1. Within Authorization, change the Authorization Method to Bearer Token.
  2. Under Token Scheme, select Bearer.
  3. For Bearer Token, enter in the API key mentioned as a prerequisite above.

Michael_Tarallo_5-1685984516148.png

 

  1. Within Response Table, for Name of Returned Table enter the value of ‘data’. Note that this value is only really relevant for the load script, but the field is required to be populated nonetheless.
  2. Under Table Path (JMESPath), enter in the value of ‘data’. Note that this is the name of the JSON object containing the data returned from `api/v1/users` and contains source of data that we require from the payload.
  3. Within Response Fields, deselect Load all available fields. This is so we can customize the value that is returned.
  4. Within Response Table, under Table Fields (JMESPath), enter a new Name value as ‘groups’, then enter the Value of ‘join(‘|’,assignedGroups[*].name)’. This will concatenate all of the values of the ‘assignedGroups’ array returned by the API into a pipe delimited string. This function is a part of the JMESPath query language that is supported by the Advanced Analytics connector. To learn more, you can refer to: https://jmespath.org/tutorial.html.

Michael_Tarallo_6-1685984516198.png

 

  1. Leave the remaining settings untouched.
  2. Set the Name of the connection as ‘Get Groups’. Note in this case this is important because the name of the connection is directly referenced in the expression of the accompanying sample app.

Michael_Tarallo_7-1685984516212.png

 

  1. Test the connection and ensure that it is operational.

 

Sample App Testing:

The sample application includes three sheets:

  1. Get Current User Groups – this sheet displays the current groups of the logged in user.
  2. Product Group A Analysis – this sheet has a commented out calculation condition to only show the sheet if the user contains the group ‘Product Group A’.
  3. Product Group B Analysis – this sheet has a commented out calculation condition to only show the sheet if the user contains the group ‘Product Group B’.

The application transforms the OsUser() result into the subject format, looks up the user, gets the groups, and returns them as a pipe-delimited string. You can find this process defined in the vUserSub and vUserGroups variables.

To test the application, first confirm that the first sheet returns your user groups. If it does, you can modify the sheet calculation conditions on the latter two sheets to your desired group names that you want to show based on.

Michael_Tarallo_8-1685984516312.png

 

Modify the expression by uncommenting it and adding in your desired group name (ensured it is enclosed by pipes so as to not partially match another group name):

Michael_Tarallo_9-1685984516333.png

 

In my example, I am a member of the group `Product Group A’ and not `Product Group B’, so while in edit mode, I see the following, confirming the ‘Product Group B Analysis’ is hidden from my view:

Michael_Tarallo_10-1685984516354.png

 

Exiting edit mode, I now see:

Michael_Tarallo_11-1685984516371.png

Additional Notes

  • If users have edit-level access or greater to the application where this method is deployed, when in “Edit” mode, they will be able to see that the hidden sheet(s) exist. The user could then duplicate that sheet and remove/alter the show condition so that they could see the sheet. This is not a data security risk, as this technique only focuses on cosmetic app design, however it should be noted that if it is desired that the users cannot have access to these sheets then they must not have any roles that allow for edit-level access including “Can manage”, “Can contribute”, and “Can edit”.
  • This solution relies on API calls being made by the owner of the API key.
    • This user must:
      • Continue to be exist
      • Continue to have the “Developer” role
      • Ensure that the API key does not expire and/or is rotated to prevent downtime

  •  As this solution is making calls on behalf of a single user as users are leverage the application, there is the potential for rate-limiting at the Users API. The current rate limit of the Users API is 1,000 calls per minute.

  • The Advanced Analytics connector function call in the sample app leverages the "ShouldCache":"False" setting in the vUserGroups variable. This ensures that the user’s groups are not cached by the engine, however it makes more calls to the APIs. If you are experiencing or are concerned about rate limiting, this setting can be removed.
Tags (2)
8 Comments