Organizational Authentication without a SQL Dependency

If you’ve created a web site that uses Organizational Accounts for authenticating users in Azure Active Directory, you may have also noticed the SQL Database that the ASP.NET project template adds to your project.   If your project needs a SQL database already, then using it store some additional information needed for authentication is no big deal.  But if you don’t otherwise need a database in your application, then carrying the dependency can be a burden, especially when it come to deploying to Azure.  In this post, I’ll show you how to remove the dependency for applications that use Single Organization Authentication.   If your application is doing multi-organizational authentication then this technique will not apply.

The SQL database added to your project is used to store the Id of the tenant where the application is registered as well as the thumbprint of the certificate(s) used to validate and process the tokens used during the authentication process.  These two pieces of information are stored in the Tenants table and the IssuingAuthorityKeys table in the database.   Rick Rainey does a nice job of explaining the contents of the database and how they are used in his post – Deep Dive: Azure Websites and Organizational Authentication using Azure AD.

For applications that support multi-organizational scenarios, these table are very important because the application uses the tables to store the tenant Id and certificate thumbprint for new tenants that “signup” or enrolled to use the application.  This enrollment process typically takes place through the Common Consent Framework and requires a administrator to provide consent for the application to use the tenants directory for authentication.  Once consent is provided, the application is registered in the tenants directory and the tenant is added to the SQL database thereby enabling the application to authenticate users from that tenant (as long as the certificate is valid and the consent remains in effect).

However, for most single-tenant, line of business style applications, it’s a bit simpler because there is only ever one tenant involved in the process.  Moreover, the tenant Id and certificate thumbprints are readily available form the tenants federated metadata.  In fact, as you’ll see, the database is actually initialized with values provided by the federated metadata API when the application is started.  So, if your application only needs to authenticate users with a single organization, the metadata API provides everything you need.  So why carry a dependency on a SQL database that’s not even needed?

In this post, I’ll show you how to remove the database dependency so you can simplify the development and deployment or applications using single organizational authentication.

Creating an ASP.NET Web Application with Organization Authentication

Start by creating a new ASP.NET Web Application in Visual Studio.   From the new project template, click Change Authentication and choose Organizational Accounts as the type of authentication.

ASP.NET Project Wizard

Choose Cloud – Single Organization to use Azure Active Directory as the identity provider. Be sure to choose single organization not multi-organization.  Enter the domain name of the Azure Active Directory tenant that you want to use for authentication.  You can choose whichever access level is appropriate for your application.

Change Authentication

When you click OK, the wizard will prompt you to sign in with an administrative account from the Azure Active Directory tenant specified by the domain.  The credentials are needed in order to register the application with the tenant.  Once the application is registered, you can click OK and finish the wizard.

Once the project is created, you’ll notice that a connection string was added to your project.

Connection String

The connection string is used by the TenantDbContext which holds the collection of IssuingAuthorityKeys and Tenants loaded from the database.  These fields contain the Thumbprints and Tenant Ids I mentioned earlier.TenantDbContext

The TenantDbContext is used by the methods of the DatabaseIssuerNameRegistry class to determine if a given tenantId or thumbprint are registered with the application when a user is being authenticated.  If the user attempting to access the site is from an unregistered tenant, the authentication fails.

DatabaseIssuerNameRegistry

The collections are initialized in RefreshKeys by retrieving values directly from the issuing authority metadata and adding them to the TenantDbContext.

RefreshKeys Refresh Keys is called by IdentityConfig when the application is started

IdentifyConfig

Removing the database dependency

As you can see above, there’s really no need to persist the keys and Ids in a database since they are available directly from the issuing authority.  So lets remove the database dependency and just maintain the collections in memory.  We’ll reinitialize the collections each time the application starts

Lets start by creating an new class MemoryIssuerNameRegistry to replace the DatabaseIssuerNameRegistry.  This new class is very similar to the original DatabaseIssuerNameRegistry except it uses an internal class to store the tenant data rather than the TenantDbContext.  The TenantData class maintains a private List<Tenant> and List<IssuingAuthorityKey> and provides getters for accessing each.  The ContainsTenant and ContainsKey methods use the internal data structure to check for a specific tenantId and thumbprint.

MemoryIssureNameRegistry

We’ll also change RefreshKeys to initialize the TenantData.

RefreshKeys2

Next we’ll modify the IdentityConfig to use the new MemoryIssuerNameRegistry

IdentifyConfig2

And finally, we’ll remove the default connection string and change the IssuerNameRegistry in the web.config file.

WebConfig

Now you should be able to run the project and sign in as any user in the registered tenant.

RunningApp

And perhaps best of all, you can publish the application to Azure without having to publish a database.

WebPublish

As one final clean up step, you can remove the TenantDbContext.cs and DatabaseIssuerNameRegistry.cs files from the project or you can leave them in place in case you ever need to support multi-organizational authentication.

ProjectLayout

You can get all the code for this project on GitHub.