Skip to content

Multi tenant: Admin access tenant data

Jon P Smith edited this page Mar 23, 2022 · 1 revision

Version 2.2.0 and above of the AuthP library contain a feature called link to tenant data that allows a suitably approved user to obtain the DataKey of a tenant and make that DataKey adds or replaces the user's DataKey while the user is linked. A linked user can now access the other tenant's data.

The main use of this feature is to allow an app user (see definition of an app user in the NOTE) to get access to tenant's data. Typically a customer support user would use this feature to help tenant users who have problems, where seeing the data and features in the same way as the tenant user.

NOTE: There is also second usage in hierarchical multi-tenant applications where users at a higher level can link to the data in one of the layer below them. But at this time I am not going to describe this use at the moment.

To use the link to tenant data feature you need to:

  1. Turn on the feature during the registration of the AuthP library.
  2. Add features to your application:
    1. Code to start linking to a tenant's data
    2. Code to stop linking to a tenant's data
    3. Code to tell the user is linked to a tenant
  3. Set up a AuthP customer support user.

NOTE: Example3 uses the link to tenant data feature and provides an excellent example of how you might add this feature to your own application.

1. Turn on the feature during registration

You have to set up two AuthPermissionsOptions parameters:

  • Set the LinkToTenantType parameter to LinkToTenantTypes.OnlyAppUsers
  • Set the EncryptionKey parameter with a string of at least 16 characters to use when encrypting / decrypting data used in the link to tenant data feature. This should be private so its typically taken from your appsettings so that your production encryption key can be set by the production system.

The code below shows this part of your regionalisation of the AuthP's library.

services.RegisterAuthPermissions<Example3Permissions>(options =>
    {
        options.TenantType = TenantTypes.SingleLevel;
        options.LinkToTenantType = LinkToTenantTypes.OnlyAppUsers;
        options.EncryptionKey = _configuration[nameof(AuthPermissionsOptions.EncryptionKey)];
        options.AppConnectionString = connectionString;

        options.PathToFolderToLock = _env.WebRootPath;
    })
    // ... other registration code left out

2. Add Link to tenant data feature to your application

2i. Start linking to a tenant's data

You need to add commands to turn on the data linking, with the tenantId of the tenant you want to link to, and another to turn off the linking when the user has finished, or they log out.

Typically, the customer support will have access to the list of tenants, and each tenant has a “Access Data” link that starts linking when clicked. The screenshot below was taken from Example3 with the "AppSupport@g1.com" user logged in.

ListTenantsCustomerSupportAccessData

You then have to create an ASP.NET Core action to call the ILinkToTenantDataService's StartLinkingToTenantDataAsync method. This action code below will start the linking to the tenant who's primary key is equal to the id.

[HasPermission(Example3Permissions.TenantAccessData)]
public async Task<IActionResult> StartAccess([FromServices] ILinkToTenantDataService service, int id)
{
    var currentUser = User.GetUserIdFromUser();
    var status = await service.StartLinkingToTenantDataAsync(currentUser, id);

    return status.HasErrors
        ? RedirectToAction(nameof(ErrorDisplay),
            new { errorMessage = status.GetAllErrors() })
        : RedirectToAction(nameof(Index), new { message = status.Message });
}

2ii. Stop linking to a tenant's data

You also need a way to stop linking to a tenant's data. The ILinkToTenantDataService's method for that is called StopLinkingToTenant. The action code below shows what this would look like.

public IActionResult StopAccess([FromServices] ILinkToTenantDataService service, bool gotoHome)
{
    var currentUser = User.GetUserIdFromUser();
    service.StopLinkingToTenant();

    return gotoHome 
        ? RedirectToAction(nameof(Index), "Home") 
        : RedirectToAction(nameof(Index), new { message = "Finished linking to tenant's data" });
}

NOTE: the gotoHome is used when someone logs out - see the next section.

2iii. Code to tell the user is linked to a tenant

The user needs to know that they are linked to a tenant's data, especially if their Roles allow them to create, update or delete data in that tenant (see next section on this). There is a method called GetNameOfLinkedTenant, which returns the name of the tenant the user is linked to, or null if the user isn't linked to the tenant's data. You can use this to tell the user if they are linked.

In the Example3 ASP.NET Core MVC design I injected the ILinkToTenantDataService into the _Layout.cshtml file and added some Razor code to tell the user they are linked to a tenant's data, and provide link that will stop the linking to a tenant's data (plus code to stop linked if the user logs out).

NOTE: For this to work you need to add the code @inject ILinkToTenantDataService LinkToTenantDataService at the top of the "_Layout.cshtml" file.

<div class="container">
    <main role="main" class="pb-3">
        <div class="text-danger">
            @{
                var tenantName = LinkToTenantDataService.GetNameOfLinkedTenant();
                if (tenantName != null)
                {
                    if (!User.Identity.IsAuthenticated)
                    {
                        <script>
                           window.location.replace(
                               "@Url.Action("StopAccess", "Tenant", new { gotoHome = true }) ");
                        </script>
                    }
                    <div>
                        Be careful! You are currently linked to the <strong>@tenantName</strong> tenant's data.
                        <a class="btn btn-outline-primary btn-sm" 
                            asp-area="" asp-controller="Tenant" asp-action="StopAccess">Stop Linking</a>
                    </div>
                }
            }
        </div>
        @RenderBody()
    </main>
</div>

Note the code that detects that a) the user is linking to a tenant's data AND b) that user has logged out. In that case it calls the StopAccess action with gotoHome set to true. This will stop the linking on log out.

This figure below shows the customer support user with email "AppSupport@g1.com` logged in and is linked to the 4U Inc. tenant data. Note the "be careful..." banner and the "Stop Linking" button.

ListTenantsCustomerSupportAccessData

3. Set up a AuthP user to access a tenant's data

Any app-level (i.e. user not linked to a tenant) can use the link to tenant data as long as they have the correct Roles / Permissions to start and stop methods in the ILinkToTenantDataService service. Having said that its useful for the user linking to the tenant's data also has the Roles / Permissions that the tenant users have, so that the user can use the tenant's features, otherwise linking to the data isn't very useful.

If you have a small team, you might add access to the tenant features to the App Admin users. In larger applications, where you need dedicated customer support team you could set up a customer support user which access to some of the AuthP admin services, but maybe not admin features that could break things, plus the tenant features.

For instance in the Example3 application I created a user called "AppSupport@g1.com" which had the following Roles / Permission

  • A Role called "App Support", with Permissions that are read-only views or Roles, Tenants and Users, plus the Permission to start / stop linking to a tenant's data.
  • Added the "Tenant User" Role, which allows the user to use the features that the tenant user's have. This means the "AppSupport@g1.com" user can access all the features that a tenant user would use.

Additional resources

Articles / Videos

Concepts

Setup

Usage

Admin

SupportCode

Clone this wiki locally