Exercise - Ensure secure access with access control list

Completed

In this exercise, you update the code responsible for importing local markdowns files with configuring ACLs on selected items.

Before you start

Before you do this exercise, be sure to complete the previous exercise in this module.

Import content that's available to everyone in the organization

When you implemented the code for importing external content in the previous exercise, you configured it to be available to everyone in the organization. Here's the code that you used:

static IEnumerable<ExternalItem> Transform(IEnumerable<DocsArticle> content)
{
  var baseUrl = new Uri("https://learn.microsoft.com/graph/");

  return content.Select(a =>
  {
    var docId = GetDocId(a.RelativePath ?? "");

    return new ExternalItem
    {
      Id = docId,
      Properties = new()
      {
        AdditionalData = new Dictionary<string, object> {
            { "title", a.Title ?? "" },
            { "description", a.Description ?? "" },
            { "url", new Uri(baseUrl, a.RelativePath!.Replace(".md", "")).ToString() }
        }
      },
      Content = new()
      {
        Value = a.Content ?? "",
        Type = ExternalItemContentType.Html
      },
      Acl = new()
      {
          new()
          {
            Type = AclType.Everyone,
            Value = "everyone",
            AccessType = AccessType.Grant
          }
      }
    };
  });
}

You configured the ACL to grant access to everyone. Let's adjust it for selected markdown pages that you're importing.

Import content available to select users

First, configure one of the pages that you're importing to be accessible only to a specific user.

In the web browser:

  1. Navigate to the Azure portal at https://portal.azure.com and sign in with your work or school account.

  2. From the sidebar, select Microsoft Entra ID.

  3. From the navigation, select Users.

  4. From the list of users, open one of the users by selecting their name.

  5. Copy the value of the Object ID property.

    Screenshot of the Azure portal with a user profile open.

Use this value to define a new ACL for a specific markdown page.

In the code editor:

  1. Open the ContentService.cs file, and locate the Transform method.

  2. Inside the Select delegate, define the default ACL that applies to all imported items:

    var acl = new Acl
    {
      Type = AclType.Everyone,
      Value = "everyone",
      AccessType = AccessType.Grant
    };
    
  3. Next, override the default ACL for the markdown file with name ending in use-the-api.md:

    if (a.RelativePath!.EndsWith("use-the-api.md"))
    {
      acl = new()
      {
        Type = AclType.User,
        // AdeleV
        Value = "6de8ec04-6376-4939-ab47-83a2c85ab5f5",
        AccessType = AccessType.Grant
      };
    }
    
  4. Finally, update the code that returns the external item to use the defined ACL:

    return new ExternalItem
    {
      Id = docId,
      Properties = new()
      {
        AdditionalData = new Dictionary<string, object> {
          { "title", a.Title ?? "" },
          { "description", a.Description ?? "" },
          { "url", new Uri(baseUrl, a.RelativePath!.Replace(".md", "")).   ToString() }
        }
      },
      Content = new()
      {
        Value = a.Content ?? "",
        Type = ExternalItemContentType.Html
      },
      Acl = new()
      {
        acl
      }
    };
    
  5. The updated Transform method looks as follows:

    static IEnumerable<ExternalItem> Transform(IEnumerable<DocsArticle>    content)
    {
      var baseUrl = new Uri("https://learn.microsoft.com/graph/");
    
      return content.Select(a =>
      {
        var acl = new Acl
        {
          Type = AclType.Everyone,
          Value = "everyone",
          AccessType = AccessType.Grant
        };
    
        if (a.RelativePath!.EndsWith("use-the-api.md"))
        {
          acl = new()
          {
            Type = AclType.User,
            // AdeleV
            Value = "6de8ec04-6376-4939-ab47-83a2c85ab5f5",
            AccessType = AccessType.Grant
          };
        }
    
        var docId = GetDocId(a.RelativePath ?? "");
    
        return new ExternalItem
        {
          Id = docId,
          Properties = new()
          {
            AdditionalData = new Dictionary<string, object> {
              { "title", a.Title ?? "" },
              { "description", a.Description ?? "" },
              { "url", new Uri(baseUrl, a.RelativePath!.Replace(".md", "")).   ToString() }
            }
          },
          Content = new()
          {
            Value = a.Content ?? "",
            Type = ExternalItemContentType.Html
          },
          Acl = new()
          {
            acl
          }
        };
      });
    }
    
  6. Save your changes.

Import content available to a select group

Now, let's extend the code so that another page is only accessible by a select group of users.

In the web browser:

  1. Navigate to the Azure portal at https://portal.azure.com and sign in with your work or school account.
  2. From the sidebar, select Microsoft Entra ID.
  3. From the navigation, select Groups.
  4. From the list of groups, open one of the groups by selecting their name.
  5. Copy the value of the Object Id property.

Screenshot of the Azure portal with a group page open.

Use this value to define a new ACL for a specific markdown page.

In the code editor:

  1. Open the ContentService.cs file, and locate the Transform method

  2. Extend the previously defined if clause, with an extra condition to define the ACL for the markdown file with name ending in traverse-the-graph.md:

    if (a.RelativePath!.EndsWith("use-the-api.md"))
    {
      acl = new()
      {
        Type = AclType.User,
        // AdeleV
        Value = "6de8ec04-6376-4939-ab47-83a2c85ab5f5",
        AccessType = AccessType.Grant
      };
    }
    else if (a.RelativePath.EndsWith("traverse-the-graph.md"))
    {
      acl = new()
      {
        Type = AclType.Group,
        // Sales and marketing
        Value = "a9fd282f-4634-4cba-9dd4-631a2ee83cd3",
        AccessType = AccessType.Grant
      };
    }
    
  3. The updated Transform method looks as follows:

    static IEnumerable<ExternalItem> Transform(IEnumerable<DocsArticle>    content)
    {
      var baseUrl = new Uri("https://learn.microsoft.com/graph/");
    
      return content.Select(a =>
      {
        var acl = new Acl
        {
          Type = AclType.Everyone,
          Value = "everyone",
          AccessType = AccessType.Grant
        };
    
        if (a.RelativePath!.EndsWith("use-the-api.md"))
        {
          acl = new()
          {
            Type = AclType.User,
            // AdeleV
            Value = "6de8ec04-6376-4939-ab47-83a2c85ab5f5",
            AccessType = AccessType.Grant
          };
        }
        else if (a.RelativePath.EndsWith("traverse-the-graph.md"))
        {
          acl = new()
          {
            Type = AclType.Group,
            // Sales and marketing
            Value = "a9fd282f-4634-4cba-9dd4-631a2ee83cd3",
            AccessType = AccessType.Grant
          };
        }
    
        var docId = GetDocId(a.RelativePath ?? "");
    
        return new ExternalItem
        {
          Id = docId,
          Properties = new()
          {
            AdditionalData = new Dictionary<string, object> {
                { "title", a.Title ?? "" },
                { "description", a.Description ?? "" },
                { "url", new Uri(baseUrl, a.RelativePath!.Replace(".md",    "")).ToString() }
            }
          },
          Content = new()
          {
            Value = a.Content ?? "",
            Type = ExternalItemContentType.Html
          },
          Acl = new()
          {
              acl
          }
        };
      });
    }
    
  4. Save your changes.

Apply the new ACLs

The final step is to apply the newly configured ACLs.

  1. Open a terminal and change the working directory to your project.
  2. Build the project by running the dotnet build command.
  3. Start loading the content by running the dotnet run -- load-content command.