Using AD for authentication between Web app and Web API

In my earlier post about the problem with ACS I promised to blog about how to configure Microsoft Azure Active Directory (MaaD) to support a client app calling a Web API using a client secret (as opposed to presenting an authentication dialogue to an interactive user).

To get started (and save me a lot of typing) I suggest you get started by reading Johan Danforth’s great blog post on how to do this for an interactive login as this is where I started)

If you follow the instructions carefully you will have a Web API published and registered with AD and you will have updated the application’s manifest file in AD to allow you to configure permissions to it in other applications in the directory)

You will also have a client app, also configured in AD (as a ‘native application’) in which you have configured permission to access the Web API and the relevant call to issue the request to AD to get the token and to the Web API bearing that token.

Crucially – you will have written very little code to do this. AD, the ADAL Nuget Package and the OWIN library (on the server side) will have done all the heavy lifting for you.

What I wanted to do is to remove the interactive user from the equation – in my scenario a user uses a web app, which in turn uses my Web API, but this is not a delegation scenario, the web app can call the web api on its own right.

To achieve this, I needed to make two changes from Johan’s example –

Firstly I needed to register my web app as a client app which isn’t a native client as a native client app in AD does not have configuration for client secret. so I’ve added a new app to my directory, made sure to select the ‘web application and/or web api application’ for the type and configured a name, APP ID and (in my case a mock) sign-on url.

I had also set the permission from my web client application to the web-api, in the same way that I did earlier for my native client.

And finally – I added a new key by selecting a duration and copied the secret (important: the key cannot be accessed after its creation, make sure to copy it)

With the AD configuration done I make the relevant changes to the client code to use the client secret rather than the interactive sign on

The original code includes the following line - 

var ar1 = ac.AcquireToken(“https://. . . WEB Api APP ID URI. . .”,
              "e9b5d821-. . .Native Client’s Client Id",
              new Uri("http:// . .  Native Client’s APP ID URI"));

so support authenticating using client secret, this needed to change to

ClientCredential cc = new ClientCredential("e9b5d821-Web Client Client ID",
"Qxc49i. . .client secret generated in AD portal"); var ar1 = ac.AcquireToken(https://. . . WEB Api APP ID URI. . .”, cc);

and with this done (the rest of the code remains unchanged), when I now run the client, rather than being prompt to authenticate the call to the web api is made and authentication is done using the client secret.

In closing, for completeness, the interaction really translates to two web requests – the first is to AD to retrieve the access token, and in my case this looks like this –

POST https://login.windows.net/[1db093b3-…AD tenant ID]/oauth2/token HTTP/1.1

Host: login.windows.net

Content-Type: application/x-www-form-urlencoded

Content-Length: 212

grant_type=client_credentials&client_id=[e9b5d821-…client app client id]&client_secret=[Qxc49iXn…client secret]&resource=[https%3A%2F%2F…..protected resource app ID]

This request, if successful, returns a JSON response which includes a JWT token from AD that can be used in subsequent requests to the application. That subsequent requests looks like this (token trimmed for readability) –

GET http://localhost/WebApplication1/api/Values HTTP/1.1

Host: localhost

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJh……..

Finally – whilst I was experimenting with this I encountered a few errors that are worth noting here –

The one I was most confused by was

"AADSTS90014: The request body must contain the following parameter: ‘client_secret or client_assertion’."

In my case this happened when I tried to request a token from AD through my client app when it was still coded for interactive user sign-on. when the AD application used was native, using the interactive logon code worked fine, as soon as I tried to use a web api AD application without changing the code to use client_secret I got the error above.-

Final thought – ACS is slowly being embedded in AD but for the time being I find the experience a little bit fiddly and short of documentation (in particular the Manifest file manipulation) and lack of flexibility

The integration above currently only works with JWT tokens and client secret authentication (SWT is not supported I believe as is certificate based authentication) but this will be corrected over time, I’m sure.

 

[cross posted on the Solidsoft blog]

Advertisements

The problem with ACS….

…is that it currently has no published SLAs and there’s no out-of-the-box solution for Disaster Recovery in an active scenario (as in – web services, REST services)

Let me expand on these two points –

I could not find any SLA information about ACS, so I asked Microsoft who responded that, as things stand ACS is a free service and they do not offer SLAs for free. This might change as and when ACS is properly rolled into Microsoft Azure Active Directory with its paid, Premium option, but that’s not the case at the moment.

Pragmatically – I have not seen any ACS issues in the past and there are several Azure services that do carry SLA that take a dependency on ACS, namely the Service Bus and BizTalk Services. Make of that what you will – you have to either accept or reject this risk.

To make matters worse – there’s no easy solution for DR for ACS in an active scenario.

Federated identity follows two approaches – when dealing with users and browsers the passive approach is used and that relies on browser redirects. This means that the web app is responsible for redirecting users to the Identity Provider (IdP) and holds the configuration of where the IdP is. That means, for example, a web role deployed across data centres and fronted by Traffic Manager, can have separate configurations to redirect users to different ACS namespaces, depending on the environment.

When dealing with services (SOAP with WS-Federation or REST with oAuth) the service client holds the configuration about where the IdP is (in the SOAP case this is part of the service contract in oAuth it is simply exchanged out of band) and it is the service client’s responsibility to go and get a token from the IdP before calling the service.  This means that if the ACS namespace changes (for example due to outage and switch to DR), the client will need to know to go to the alternative the service won’t tell it automatically.

With this in mind, what are the options?

I can think of 3 or 4. would love to hear additional views –

1. Accept the risk and the need to reconfigure clients when switching to DR.

2. If you have control over the client – implement an operation to automatically (on failure) and/or regularly request the metadata from your web role, which would allow it to auto-recover

3. If either of the above are not acceptable – roll your own oAuth solution on your web role which would mean that client access the same url (managed by traffic manager) to access the service and the IdP.

A better alternative is to use the bit of ACS that is rolled into Active Directory through the configuration of Applications for both the Web API and the client. I’ll post an entry on this shortly. the upside is that if you then make sure your directory is a Premium one you are covered by SLAs, although I’m still not sure what the DR story for AD is.

The main downside of this approach at this point in time is that, currently at least, there’s not much configuration that can be done – it only supports a client secret and JWT tokens with no control over token TTL etc. I also the the process is quite fiddly, requiring tempering with the app manifest manually etc, but I’m sure all of this will improve over time.

[cross posted on the Solidsoft Blog]

Caching choices

In a meeting with a customer this week the question of which caching capability on Azure to use came up again.

As I’m writing this Microsoft Azure offers three caching options, here’s the extract from the Azure web page –

Azure Cache is a family of distributed, in-memory, scalable solutions that enables you to build highly scalable and responsive applications by providing you super-fast access to your data. We offer the following types of Azure Cache:

  • Azure Redis Cache: Built on the open source Redis cache. This is a dedicated service, currently in Preview.
  • Managed Cache Service: Built on App Fabric Cache. This is a dedicated service, currently in General Availability.
  • In-Role Cache: Built on App Fabric Cache. This is a self-hosted cache, available via the Azure SDK.

As you can see from the description above, first and foremost the decision is between two technologies – Redis and AppFabric caching. Then, as things stand currently, for AppFabric there’s another choice of deployment model  – managed or in-role. (I suspect that one can create an in-role Redis cache with not too much effort, but this is not currently an out-of-the-box feature and so I’ll ignore it).

My experience with AppFabric Caching is a good one – I find it performs well, feature rich and mature for the enterprise. I have not had the chance to work with Redis but the feedback that I am getting from colleagues and customers is also very good, it seems it performs slightly better than AppFabric in many (but not all) scenarios, and it has some interesting features beyond what AppFabric provides.

I won’t go into a detailed comparison between the two (although unfortunately I can’t find a recent one either) but that feedback leads me to think that the first point to consider is your application requirements from its caching platform and whether that leads towards one solution over another.

All things being equal, at this point in time, I find that AppFabric provides a bit more flexibility compared to Redis in the sense that I can use it as a managed service on Azure, I can create a private cache in the cloud using in-role caching and I can run it locally in my data centre with a reasonably straight forwarded deployed.

If this flexibility is important to you than, right now, AppFabric might be the better choice.

And finally – if you have settled on using AppFabric on Azure – should you use the managed cache service or in-role service?

My starting position is always to prefer the as-a-service option. I have little if anything to manage, I don’t need to worry about the impact of updates to my roles or to balance resources between my roles and the cache.

So – when do customers prefer in-role caching? in my experience two arguments come up – 1: when they are not happy with a cache service accessible via the internet. using In-role caching I have more control over who has access to my cluster.  2: when they want to save the cost and believe they have enough capacity to balance role memory and in-role caching

%d bloggers like this: