For a Windows Azure Multi-Tenant Application
For our Cloud Panel identity platform, we need to authenticate two non-browser client applications to our multi-tenant MVC 6 cloud application via Windows Azure. One of these is a simple console application; the other is a Windows service.
We have the following core requirements:
- The applications must be easy to setup, preferably by downloading an msi installer from the cloud app, possibly with a couple configuration steps, provided those steps are simple.
- The client application must be able to authenticate to the cloud without user interaction in a daemon mode.
- The client application must be strongly authenticated, and credentials must be kept safe.
- It must be possible to revoke access to the cloud application.
We have the following nice-to have requirements:
- Our application assigns built-in and custom security roles based on group membership in Azure AD. It should be possible to assign these security roles to the client application.
- The same authentication mechanism should be usable with ADFS for on-premise installations.
OAuth Implicit Grant Flow via ADAL
This flow, works by popping up a browser window and having the user authenticate to Azure. This produces an OAuthBearer token which is submitted to the cloud application.
For an example of this flow see:
- Easy to use, and implement as an app developer.
- Very little end user configuration required.
- Does not support daemon application architecture, which is a hard requirement.
- Vulnerable to CSRF attacks.
OAuth Client Credential Flow via ADA
This flow works by registering the application in Azure, and assigning a secret key, which functions as a “password” to allow the client application to obtain a trusted login token for the cloud application.
For an example of this flow see:
- Supported by ADAL, so easy to implement as a developer.
- Typical industry standard for this sort of scenario.
- Requires painful setup by Azure admins for each tenant. The end user is forced to register a web application (because the client application type does not support the necessary private key/pair functionality), and go through a massive configuration process, which is easy to get wrong.
- You cannot assign security roles for the application.
- End user is required to manage key/pair expiration/rollover, potentially on many servers
- Secure key storage in the application is a challenge that is not solved by ADAL
Our solution meets the core and optional requirements by combining the interactive Implicit Grant flow via ADAL with a variation on forms authentication, plus a secret API Key.
Our solution requires an initial interactive login. In the case of configuring the Windows service, the user must launch our console application running as the intended service account. Next the user authenticates to our cloud application, and chooses the “remember me” option. This establishes a secure credential pair, which can later be used by the Windows service.
Setup and Authentication Experience
Setting the API Key
A user starts in the settings or setup section of our cloud application on the “Install Tools” screen.
The user is guided through the process of generating a random API key, which is unique for their tenant on our application. This API key is combined with the Implicit Grant flow to provide CSRF protection.
The user has the option to come back later and reset the API Key. If they do so, they have the option to force immediate expiration or allow a week to update.
API Key updates are applied with the downloadable MSI installer, allowing a company to push an updated to multiple servers at once.
Running the Installer
Once an API key is generated, the user may press the Download button at any time to acquire the installer. If a user enters the domain and account name of their intended service account, the web application will construct an msiexec command including all the required settings. This prevents user error when copying URIs and keys.
Pairing the Application
After the application is installed, the user must launch PanelTool to pair with the cloud application. The user is presented with the option to establish remembered credentials, or to perform interactive authentication with Azure every time.
If the user chooses not to be remembered, then the client tool will always use ADAL authentication via Azure, in conjunction with the API key for CSRF protection.
If the user chooses remember me, then the first thing the application does once it’s authenticated is POST a username to api/tenant/register. This username consists of the tenant id, current thread identity, and server hostname. This ensures each user gets a unique identity per client tools installation.
The registration method generates a cryptographically random 32 byte (256 bit) password, saves a uniquely salted SHA256 hash for later forms authentication, and returns the result.
The PanelTool agent then protects the user/password pair using the Windows Data Protection API (DPAPI) in CurrentUser mode, and writes it to the local config.json file.
This user/password pair is then used for forms authentication until it is reset from PanelTool or revoked from the web application.
It is apparent that although security role claims are available to Identity Panel when using the implicit grant flow, they are not present for the forms authentication. For this reason, Identity Panel role claims are copied to the forms authentication user when the register method is called. If a user’s roles are changed, then the user will have to run the Reset command in PanelTool and go through the interactive login again.