Azure DocumentDB Users in a multi tenant application - azure-active-directory

I am playing around with the Azure Document DB because we are planning to create a multi tenant application.
For the multi tenant application, my idea would be to create 1 db user per tenant. This gives me the advantage that tenant data would be completely separated: When creating a document, a permission is added to the tenant user. (Read/Write) This means when querying, the data will always be scoped to the current tenant.
I was also playing around with 1 DB user per end-user. But this gives me a lot of overhead to manage the security on documents. When user x from tenant z adds a document, all users from tenant z need to be updated with an extra permissions for that document. This seems unfeasible.
Is my assumption correct? Or would you suggest another approach for this? Are there any downside to this approach?

For our multi-tenant solution we chose to not use DocumentDB's controls at all and do all of our authorization in the middle tier mostly because we wanted it to be predicate based and different per tenant. That said, your approach of using DocumentDB's authorization capabilities at the tenant level makes sense. That will give your tenants added assurance that other tenants can't see their data.
My one thought is that if you have some cross-tenant functionality (maybe in the form of tenant groups) then it would break the model so you may want to consider that.
I assume tenants are hundreds and users are thousands but whatever they are, you should confirm that the DocumentDB authorization capability scales to that level. Maybe one of the DocumentDB product managers that monitor this can chime in?

Related

Linking External Identity Users With Existing Users

I'm adding an external identity provider, Azure multi-tenant, as a login option. I have local accounts right now and they know nothing about Azure AD users.
I want to create an Azure Enterprise App that other tenants can use to set up SSO using OpenID Connect. Also I want the app to support User Provisioning by setting up a SCIM API.
I can't really find any documents on how to handle linking Azure AD users with the existing accounts in my IDP. I've seen examples where users can login using their local account, authenticate with Azure, and then their local account is updated to have the Azure AD User ID. This approach still seems pretty manual. Another thought was to have a step in the login journey, where if no local account has the Azure AD User ID then find a local account with the same email. I don't like this approach either since the emails might not always match. Is there an approach where an admin can automatically link all accounts with a sync or upload?
SYSTEMS
First it's worth clarifying roles:
Role
Details
Authorization Server (AS)
Your UIs and APIs receive tokens from this. It is where accounts and linked accounts are stored. It is where you use SCIM to update account records. It is where you apply account linking logic.
Identity Provider (IDP)
There can be multiple of these. When your apps call the AS it manages connections to them, and exchanges IDP tokens for AS tokens that are returned to apps. It is not usual to use SCIM against an IDP.
You are using IdentityServer as the AS so your UIs and APIs will continue to use IdentityServer tokens and remain simple. Meanwhile Azure AD will become an alternative IDP. So on the data side of things your architecture is in a good place.
AUTHENTICATION ACTIONS
I would aim to solve your problems via custom authentication actions, and to design this in a vendor agnostic way. Not all providers support these concepts, but IdentityServer has some pretty good extensibility features, so hopefully it has what you need.
A bit of code, configuration and technical investigations in IdentityServer feel like the correct direction, with no complexity added to your applications. I will describe techniques in terms of Curity (where I work), but the same principles can apply to any system.
USERNAME AUTHENTICATOR
A great way to deal with user specific differences is to make the initial screen prompt only for an email. See this example for how that looks. Later, when authentication has completed, you could set a cookie so that this screen is not shown on subsequent logins.
Then, before asking for credentials, apply some scripted logic, eg to look up existing account attributes, and decide how the user should authenticate. You might decide to route unknown users to Azure AD or do something based on business partner email suffixes.
DATA UPDATES
Something simple that might work in advance of adding Azure AD support is to assign all users a Tenant ID, and perhaps existing users get a Tenant ID of 1. Only those users are allowed to sign in with Identity Server - all others have to use Azure AD.
SCRIPTED LOGIC AND ACCOUNT LINKING
For a worked example of how this looks, see this Account Linking with Facebook tutorial. In this example the objective is to update the main account with a new linked account. This account linking doc may give you some additional ideas for your scenario. It should be possible to run custom logic before triggering authentication or once your have the Azure IDP attributes.
INVOLVE THE USER IF NEEDED
It may also be useful to present a custom screen to ask the user if they have an existing account when they first login via Azure AD. If not then an Azure AD login can create the primary account in IdentityServer data in addition to a linked account.
USERS AND PARTNERS
How users onboard is interesting, and discussed in this detailed article. I always start by getting a feel for the type of assets involved:
Type
Description
Personal Assets
You allow any user to sign up and they only have access to their own assets
Corporate Assets
Users are provisioned by an administrator, eg a banker is granted access to financial data according to business rules
In your case it feels like users are from the second category, so to enable a user to fully sign up you need data from the partner, either fed in manually or by getting them to call your API, before you can assign the user the correct tenant ID. This might eventually result in TenantID=23, but there is nothing to stop you initially allowing users to onboard and placing them in a default TenantID=0 bucket.
Ultimately this all comes down to data, claims and API authorization. Eg APIs could return certain data to TenantID=0 users but only return privileged data to users whose tenant ID has been asserted by an administrator. Not sure if these thoughts of mine match your scenario but hopefully they provide a useful hint or two.
SUMMARY
Reliable account linking is tricky, but it should be solvable via the building blocks of the Authorization Server, using the above techniques. The end result should be deterministic user data, with no duplicate users.

Azure AD multi-tenant app, Who should be responsible of creating a tenant when a new customer subscribe to the service?

I am reading this docs that talks about security for a multi tenant application. https://learn.microsoft.com/en-us/azure/architecture/multitenant-identity/.
Let's say that my application is Tailspin. At least 2 companies, Contoso and Fabrikam, decide to use my application.
Those are my questions
Do I need to create a tenant for each customer that decide to start using my service?
Let's say Fabrikam already use a provider other than Azure Active Directory. If Fabrikam wants to use Tailspin, am I going force them to create a tenant?
EDIT
This short video shows how to start using Slack.
The first person to join Slack will enter all the information to create the space.
After that, that person will enter emails, inviting people to join the organization in Slack.
What I have noticed is that, they invitees don't need to belong to an organization [tenant] as they can have gmail, yahoo, etc. Yet, when user is logged in a space, he/she only sees what's in user's space.
I don't know how slack works, but if you have to implement something similar using Azure Active Directory as Identity provider:
Are you going to create a tenant for each customer [you said I shouldn't do that]
Should I create a security group for each customer that join so that its members can be part of that group?
Thanks for helping
You shouldn’t create a separate tenant for these companies. if in case those companies are hosted on different Identity provider. You can federate those Companies identity provider with your application IDP, and you will be accessing the application from their company’s identity itself.
Note: Your application should have capabilities to Federate with other IDP.
You can refer this document how to Microsoft federate with other IDP.
Note: For multi-Tenant, tenants share physical resources (such as VMs or storage), each tenant gets its own logical instance of the app.
For Single Tenant Architecture where each tenant has a dedicated physical instance

In Multi Tenancy with separate databases for each - How to create Centralised Service for User Login?

I am revamping an existing product, it has multi tenancy with separate database for each tenant. Now we need a single API to authenticate user without the information of tenant, as that is common login portal. What is the best approach for this problem ?
There are below given approaches
Case 1 Use a shared collection of tables that contain some data about the tenant's, their users etc.
In this case you will have a scalable admin service (can be a microservice) that talks to this database and can authenticate the users, tenants
Case 2 If the application is on large corporates and uses user's email address in the company domain's (as like in AD), steps are below.
you get the email address,
identify the domain
choose the tenant based on the identified domain
resolve the connection string based on the tenant
identify the database based on the identified tenant
Route to the DB and do the authentication
Case 3 when there are user's that can work in multiple tenants (like financial auditors), the idea of having a global users table is a good option. I get myself authenticated, then choose my tenant based on my mapping. Get into the tenant, do the tasks.
You can read more on this in my blog post https://dsaravanan.wordpress.com/2021/05/02/user-authentication-schemes-in-a-multi-tenant-saas-application/

Access to Multiple tenants on Azure AD using single sign on

I have multiple tenants on azure. I want to access them using a single sign-on from my app. e.g I want to get all subscriptions related to all tenants by tenantId with a single hit. I tried the below api and it gives me one tenant information at a time. It requires the access_token for each tenant separately.
https://learn.microsoft.com/en-us/rest/api/resources/subscriptions/get
I am able to get all tenant's information using (https://learn.microsoft.com/en-us/rest/api/resources/tenants/list), but after that is there any option to pass the tenantId and get the other information like subscriptions and other detail based on passing tenantId.
You need to provide different access token for different tenants.
So it's impossible to list all the subscriptions for multiple tenants in one call.
PowerShell cmd Get-AzureRmSubscription can list subscriptions for all tenants. But it still needs to get an access token for each tenant and then get it's subscriptions.
See a similar post here.
This is achievable through Azure Lighthouse, but may not scale or be the correct solution depending on the scenario that your app is trying to fulfill.
https://learn.microsoft.com/en-us/azure/lighthouse/overview
This is mainly used by managed service providers to manage their Azure resources cross tenant, but you could also use it to manage your own internal Azure resources cross tenant.
https://learn.microsoft.com/en-us/azure/lighthouse/concepts/azure-delegated-resource-management
The managed services is comprised of two parts the definitions and assignment (you can kind of think of it similar to role assignment). The definition defines the tenant and users that will be able to see the other projections. The assignment gives the users and tenant defined in the definition access to the subscription.
How-To: https://learn.microsoft.com/en-us/azure/lighthouse/how-to/onboard-customer
There are some limitations to this:
https://learn.microsoft.com/en-us/azure/lighthouse/concepts/cross-tenant-management-experience#current-limitations

Permission Based instead of Role Based

In my application, a User is assigned multiple Roles, and a Role is assigned(granted) multiple Permissions.
So in my code, I never check against a Role, but always against a fine grained Permission.
Here is described why I think Permissions based access is better than Role based:
https://softwareengineering.stackexchange.com/a/299732
Within Azure AD, I can assign roles to a user.
But I see no way of creating Permissions and associate them to Roles, so I guess this part must stay in my app ?
Then how should I link the Azure Application Roles to my app's Permissions ?
My assumption is I need to build an UI for doing this, using the Graph API to retrieve the list of roles defined in Azure for the application.
If that is the case, then I don't see much benefits using the built-in roles function in Azure vs keeping the role definition in my app...
Am I missing something ?
The key point of using Azure AD claims is to keep users information in the Active Directory rather than in the application.
In you case, you need to create permissions mapped to roles in your application.
Then theses roles can be mapped to Azure AD AppRoles or Groups.
I suggest you not to map directly users to roles.
If you deals with Group, you don't need to add/remove users to/from applications: Roles and permissions are inherited from groups users belong to.
Mapping directly to Groups
For the moment, it would be my preferred scenario. Users are assigned to groups and your customs roles are mapped to these groups.
When you create a new user, you just need to add it in some groups and there is no action required in your application (same things when you delete the user).
If you are not afraid of preview (and have an Azure AD Premium license), Azure Ad provides a way to dynamically assign users to group.
Just keep in mind that for the moment nested group memberships aren't currently supported.
So if a Group A is in Group B and Group B has some permissions in your application, Users from Group A will not have permission inherited from Group B.
Mapping Groups to application roles
This option seems to be an overkill because it requires one more step: Map Azure Ad Group to Azure Application Roles and Map theses roles to your custom roles.
You need to implement all this logic using the AAD Graph API and your UI will be more complex.
Only reason to use this option in your scenario is if you have a large directory with lots of groups and applications : If a user is in more than 200 groups so the Jwt token returned by the Azure AD will not contain the groups and you will have to query one more time the Azure AD to get the user groups (see).
In this scenario, it could make sense to map groups to application roles because when a user authenticates to an application, Azure Ad will always provides you the roles of the users (or the roles of the group that the user belong to)
you can find interesting code sample here:
active-directory-dotnet-graphapi-console.
At this point in time, Azure Active Directory application roles are meant primarily for the scenario where each user can only have one role and thise roles are mapped to a simple authorization model.
While it is technically possible to support multiple roles per user, that can only be managed via the Graph API and would require you to build a UI for your user admin / users to manage.
As you've noted, your scenario is more complex than this with multiple roles per user and multiple (potentially customizeable and overlapping) set of permissions.
Given these two points, your approach of implementing all of the authorization yourself is a sound one.
Check out this article which outlines in more details the authorization scenarios Azure AD is best suited for:
https://azure.microsoft.com/en-us/documentation/articles/guidance-multitenant-identity-app-roles/

Resources