Access Control Lists for Data Items

Stefan WeberStefan Weber
10 min read

In Part 1, we synchronized OutSystems application data with Microsoft Search & Intelligence using the Microsoft Graph External Data Connections API. This, along with a search vertical and result display template, made our data available to users in the search console.

During synchronization, we gave permission to the ingested data records to the "everyone" group, allowing all organization users to search and view the data. In a real application, you will likely need to restrict who can search and view the ingested data. In this tutorial, we will explore how to manage access control lists for ingested data records to ensure that only authorized users have access.

Demo Application

This article series includes a demo application called "ODC with Graph Demo," available on ODC Forge. Be sure to download the version of the application that matches this article.

For this article, you need to install Version 0.2 from ODC Forge.

  • In the ODC Portal, go to Forge - All Assets.

  • Search for "ODC with Graph Demo".

  • Click on the Asset (Do not click on Install on the tile!).

  • Switch to the Version tab and click on Install next to Version 0.2.

Version 0.2 depends on other Forge components:

  • OAuthTokenExchange - An external logic library that helps retrieve access tokens easily. In this tutorial however we use an action to retrieve the discovery document from Microsoft Entra only.

  • Graph External Data Connections API - A connector library that integrates with Microsoft Graph API for external data connections.

  • Graph Users API - A connector library that integrates with Microsoft Graph API users endpoint to retrieve user details.

What we build

In this part of the tutorial series, we will add specific access control list entries to ingested testimonials, allowing access only to designated users. This involves the following steps:

  • Mapping User Accounts - Map OutSystems application users to Microsoft Entra users.

  • Access Control List - Add access control list entries during data ingestion to Microsoft Graph.

Prerequisites

Before we begin, please reset the existing external data connection configurations in your Microsoft 365 tenant by following the cleanup steps and recreating the external data connection schema as described in part one of the series.

Entra Application Permissions

Our application registration we are using to ingest data requires one additional permission to retrieve Entra user details. In the Entra admin center, go to Applications - App Registrations and select the “Graph External Data Connection ODC” registration.

In the API permissions menu, click Add permission.

  • Select Microsoft Graph and Application permission.

  • Search for and select User.ReadBasic.All permission.

  • Click Add permission.

This permission requires an administrator to grant admin consent.

  • Click Grant admin consent <your domain> and confirm the dialog.
💡
Instead of User.ReadBasic.All, you can also select User.Read.All permission, which grants access to all user details, whereas ReadBasic only allows retrieval of limited user attributes. However, for the demo, this is sufficient.

Before we try the demo application, let's explore Access Control List entries for external data in Microsoft Graph a bit more in depth.

Access Control List Entries

Access Control List entries in Microsoft Graph for external data specify who can access certain ingested data records and the level of access they have.

Entries are defined by a type attribute that identifies the identity you want to grant permissions to. The type can have one of the following values:

  • user - Indicates that you want to grant permission to an individual Entra user account.

  • group - Indicates that you want to grant permission to an individual Entra group.

  • externalGroup - A non-Entra group that your application manages. We will discuss external groups shortly.

  • everyone - A special type that indicates public access.

  • application - Grants permission to a specific Entra application registration.

Next, a value must be provided that corresponds to the type you specified:

  • user - The Entra user's object identifier.

  • group - The Entra group's object identifier.

  • externalGroup - The external group identifier.

  • everyone - Must be set to “everyone”.

  • application - The Application (client) ID of the Entra application registration.

Finally, the accessType attribute defines the level of permission:

  • grant - Grants access to the record.

  • deny - Denies access to the record. Deny Access Control List entries take precedence over grant entries.

A sample JSON representation of a single Access Control List entry that grants a specific Entra user access to a record looks like this.

{
  "accessType": "grant",
  "type": "user",
  "value": "381a61cf-7d4e-40a3-a225-83c5bc36fbf0"
}

A Graph ingested data record can have multiple Access Control List entries with different types.

💡
It's important to note that Access Control List entries must always be included in the Graph_CreateOrUpdateItem operation, even when you're just updating an item. There is no separate way of managing ACLs for items.

Mapping User Accounts

Microsoft 365 users are authenticated through Microsoft Entra, and Entra does not automatically recognize OutSystems user accounts. Therefore, to manage authorizations, we need to identify which Entra user account matches an OutSystems user.

Even if OutSystems users log in through Entra, we, as of today, cannot directly access the login identification data within our application. The only information we have is the user data from the User entity. This means we have to use the user's email address to identify the corresponding Entra user.

There are two ways to do this. If the email address of an OutSystems user matches the Universal Principal Name (UPN) of the Entra user, we can easily get the Entra user details using the Graph_GetUser action from the Graph Users API connector library.

💡
In Microsoft Entra, the User Principal Name (UPN) is the unique sign-in name for a user and is formatted like an email address.

If the OutSystems user's email address does not match Entra's UPN, you can use the Graph_ListUsers action from the Graph Users API connector library. This allows you to filter for the user whose mail attribute matches the OutSystems user's email address. The filter would look like this

mail eq 'mail@domain.com'

Read more on OData filters in the Microsoft Documentation.

💡
The demo application includes a test screen where you can try out filter and search criteria.

External Groups

External Groups represent group entities from systems outside of Microsoft Entra. These groups are used to reflect the access control structures of external data sources.

When developing an OutSystems application with record-level permissions (Entity records), it's better to manage permissions at the group or role level instead of individual user accounts. This makes permission management easier over time.

External Groups for Microsoft Graph External Data let you sync your application's group or role structures and use them in Access Control List entries for item permissions.

💡
Syncing here means you need to manage the group. It is your responsibility to add and remove external group members whenever there is a change in your application.

An external group is identified by a unique identifier that you need to specify when creating an external group in Microsoft Graph. This identifier can be any alphanumeric string without special characters. The external identifier is then used in all future member management operations.

The Graph External Data Connections API connector library offers the actions you need to create, update, and delete external groups, as well as add and remove group members.

Creating an External Group

With the Graph_CreateExternalGroup action you can create a new external group in Microsoft Graph by providing the following information.

  • ExternalGroupId - The unique identifier of the external group. Can be any alphanumeric string without special characters.

  • DisplayName - Optional display name

  • Description - Optional description

Adding and Removing External Group Members

The actions Graph_CreateIdentity and Graph_DeleteIdentity let you add and likewise remove members from an external group. Members can be one of the following types

  • user - A Microsoft Entra user account identified by its object identifier.

  • group - A Microsoft Entra group identified by its object identifier.

  • externalGroup - Another, already existing, external group that you want to nest.

💡
Please note that it may take up to 30 seconds after creating a new external group before you can add members to it.

Adding an External Group Item Access Control List Entry

Using an external group in an ACL is straight forward. The JSON representation of an external group ACL would look like this.

{
  "accessType": "grant",
  "type": "externalGroup",
  "value": "externalGroupIdentifier"
}
💡
When adding an external data item to Microsoft Graph with ACLs based on new external groups, it may take some time for Microsoft 365 to evaluate group memberships. From my own observations up to 60 minutes.

Now that we have covered the basics, let's explore the implementation of the demo application.

Demo Application Walkthrough

In this walkthrough, we will explore the key implementation details. Be sure to check the comments in the various server actions as well.

The demo application assigns Access Control List entries based only on user accounts, without using external groups. As a small challenge, try implementing a group permission structure in the demo application on your own.

In ODC Studio, open the ODC with Graph Demo application.

Saving a Testimonial

In the Logic tab, open the SaveTestimonial action under Server Actions - Actions. This action runs when a user creates or updates a testimonial on the Testimonial screen.

This action first performs a check if it is a new testimonial or an existing one and depending on the outcome executed either the Testimonial_Create or Testimonial_Update CRUD wrappers.

The AddPermission server action is executed when creating a new and is responsible for creating the initial record permission for the creator of the testimonial.

  • GetUserDetails - Reads the current user's email from the User entity.

  • GetEntraAccessToken - Retrieves an access token using the application credentials to access Microsoft Graph.

  • Graph_GetUser - Queries Microsoft Graph using the user's email address to obtain Entra user details with the Universal Principal Name.

  • TestimonialMember_Create - A CRUD wrapper to create a record in the TestimonialMember entity with the OutSystems User Identifier and the Entra user's object identifier.

💡
If your OutSystems user email address does not match your Entra Universal Principal Name, you should replace Graph_GetUser with Graph_ListUsers and use filter criteria to find the correct Entra user.

Back in the SaveTestimonial action, whether creating or updating a testimonial, the IngestContent finally syncs the testimonial with Microsoft Graph.

Most of the action flow was already explained in part 1. The new addition is the GetTestimonialAccessList action, which retrieves the current permissions from the TestimonialMember entity and returns a list of ItemAccessControlList and assigned to the Graph_CreateOrUpdateItem request structure.

Modifying Permissions

You can modify testimonial permissions in the demo application for existing testimonials. In the Permissions tab of a testimonal you can add or remove OutSystems users.

Adding a new member with permissions to a testimonial triggers the AddTestimonialMember action under Server Actions - Actions. Removing a member triggers the RemoveTestimonialMember action.

Both actions first execute the AddPermission or DeletePermission actions, followed by the IngestContent action to update the record with the new ACL entries in Microsoft Graph.

This wraps up the demo application walkthrough. Try using the demo application with different user accounts to see the search results in Microsoft 365. As an extra challenge, try adding external group management to the application.

Notes and Recommendations

The demo application performs all actions synchronously, triggered from the frontend. In a real use case, you should offload data ingestion to Microsoft Graph to a workflow.

In addition, I recommend implementing a queue that stores an entry for each data item (testimonial) to create, update, and delete, and removes the entry from the queue once the data ingestion operation succeeds. This way, you minimize the risk of application data and graph data becoming inconsistent.

Summary

In this tutorial, we explored how to define Access Control List entries for ingested data items to limit access for specific user accounts. We also discussed how the Graph External Data Connections API and Graph Users API connector libraries can be used to manage external groups and their memberships.

I hope you enjoyed it and would appreciate your feedback.

1
Subscribe to my newsletter

Read articles from Stefan Weber directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Stefan Weber
Stefan Weber

As a seasoned Senior Director at Telelink Business Services EAD, a leading IT full-service provider headquartered in Sofia, Bulgaria, I lead the charge in our Application Services Practice. In this role, I spearhead the development of tailored software solutions using no-code/low-code platforms and cutting-edge cloud-ready/cloud-native solutions based on the Microsoft .NET stack. Throughout my diverse career, I've accumulated a wealth of experience in various capacities, both technically and personally. The constant desire to create innovative software solutions led me to the world of Low-Code and the OutSystems platform. I remain captivated by how closely OutSystems aligns with traditional software development, offering a seamless experience devoid of limitations. While my managerial responsibilities primarily revolve around leading and inspiring my teams, my passion for solution development with OutSystems remains unwavering. My personal focus extends to integrating our solutions with leading technologies such as Amazon Web Services, Microsoft 365, Azure, and more. In 2023, I earned recognition as an OutSystems Most Valuable Professional, one of only 80 worldwide, and concurrently became an AWS Community Builder.