Why does my Authorize Attribute not work?

Sad title, isn’t it? The alternative would have been “The complicated relationship between claim types, ClaimsPrincipal, the JWT security token handler and the Authorize attribute role checks” – but that wasn’t very catchy.

But the reality is, that many people are struggling with getting role-based authorization (e.g. [Authorize(Roles = “foo”)]) to work – especially with external authentication like IdentityServer or other identity providers.

To fully understand the internals I have to start at the beginning…

IPrincipal
When .NET 1.0 shipped, it had a very rudimentary authorization API based on roles. Microsoft created the IPrincipal interface which specified a bool IsInRole(string roleName). They also created a couple of implementations for doing role-based checks against Windows groups (WindowsPrincipal) and custom data stores (GenericPrincipal).

The idea behind putting that authorization primitive into a formal interface was to create higher level functionality for doing role-based authorization. Examples of that are the PrincipalPermissionAttribute, the good old web.config Authorization section…and the [Authorize] attribute.

Moving to Claims
In .NET 4.5 the .NET team did a radical change and injected a new base class into all existing principal implementations – ClaimsPrincipal. While claims were much more powerful than just roles, they needed to maintain backwards compatibility. In other words, what was supposed to happen if someone moved a pre-4.5 application to 4.5 and called IsInRole? Which claim will represent roles?

To make the behaviour configurable they introduced the RoleClaimType (and also NameClaimType) property on ClaimsIdentity. So practically speaking, when you call IsInRole, ClaimsPrincipal check its identities if a claim of whatever type you set on RoleClaimType with the given value is present. As a default value they decided on re-using a WS*/SOAP -era proprietary type they introduced with WIF (as part of the ClaimTypes class): http://schemas.microsoft.com/ws/2008/06/identity/claims/role.

So to summarize, if you call IsInRole, by default the assumption is that your claims representing roles have the type mentioned above – otherwise the role check will not succeed.

When you are staying within the Microsoft world and their guidance, you will probably always use the ClaimTypes class which has a Role member that maps to the above claim type. This will make role checks automagically work.

Fast forward to modern Applications and OpenID Connect
When you are working with external identity providers, the chance is quite low that they will use the Microsoft legacy claim types. They will rather use the more modern standard OpenID Connect claim types.

In that case you need to be aware of the default behaviour of ClaimsPrincipal – and either set the NameClaimType and RoleClaimType to the right values manually – or transform the external claims types to Microsoft’s claim types.

The latter approach is what Microsoft implemented (of course) in their JWT validation library. The JWT handler tries to map all kinds of external claim types to the corresponding values on the ClaimTypes class – e.g. role to http://schemas.microsoft.com/ws/2008/06/identity/claims/role.

I personally don’t like that, because I think that claim types are an explicit contract in your application, and changing them should be part of application logic and claims transformation – and not a “smart” feature of token validation. That’s why you will always see the following line in my code:

JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();

..which turns the mapping off. Newer versions of the handler call it DefaultInboundClaimTypeMap.

Setting the claim types manually
The constructor of ClaimsIdentity allows setting the claim types explicitly:

var id = new ClaimsIdentity(claims, “authenticationType”, “name”, “role”);
var p = new ClaimsPrincipal(id);

Also the token validation parameters object used by the JWT library has that feature. It bubbles up to e.g. the OpenID Connect authentication middleware like this:

var oidcOptions = new OpenIdConnectOptions
{
    AuthenticationScheme = "oidc",
    SignInScheme = "cookies",
 
    Authority = Clients.Constants.BaseAddress,
    ClientId = "mvc.implicit",
    ResponseType = "id_token",
    SaveTokens = true,
 
    TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "name",
        RoleClaimType = "role",
    }
};

Other JWT related libraries have the same capabilities – just have a look around.

Summary
Role checks are legacy – they only exist in the (Microsoft) claims world because of backwards compatibility with IPrincipal. There’s no need for them anymore – and you shouldn’t do role checks. If you want to check for the existence of specific claims – simply query the claims collection for what you are looking for.

If you need to bring old code that uses role checks forward, either let the JWT handler do some magic for you, or take control over the claim types yourself. You probably know by now what I would do ;)

 

…oh – and just in case you were looking for some practical advice here. The next time your [Authorize] attribute does not behave as expected – bring up the debugger, inspect your ClaimsPrincipal (e.g. Controller.User) and compare the RoleClaimType property with the claim type that holds your roles. If they are different – there’s your answer.

Screenshot 2016-08-21 14.20.28

 

 

Posted in .NET Security, OAuth, OpenID Connect, WebAPI | 2 Comments

Trying IdentityServer

We have a demo instance of IdentityServer3 on https://demo.identityserver.io.

I already used this for various samples (e.g. the OpenID Connect native clients) – and it makes it easy to try IdentityServer with your clients without having to deploy and configure anything yourself.

The Auth0 guys just released a nice OpenID Connect playground website that allows you to interact with arbitrary spec compliant providers. If you want to try it yourself with IdentityServer – click on the configuration link and use these settings:

Screenshot 2016-08-17 10.09.34

In essence you only need to provide the URL of the discovery document, the client ID and the secret. The rest gets configured automatically for you.

Pressing Start will bring you to our standard login page:

Screenshot 2016-08-17 11.22.56

You can either use bob / bob (or alice / alice) to log in – or use your Google account.

Logging in will bring you to the consent screen – and then back to the playground:

Screenshot 2016-08-17 11.24.24

Now you can exercise the code to token exchange as well as the validation. As a last step you can even jump directly to jwt.io for inspecting the identity token:

Screenshot 2016-08-17 11.27.05

The source code for the IdentityServer demo web site can be found here.

We also have a more client types preconfigured, e.g. OpenID Connect hybrid flow, implicit flow as well as clients using PKCE. You can see the full list here.

You can request the typical OpenID Connect scopes – as well as a scope called api. The resulting access token can then be used to call https://demo.identityserver.io/api/identity which in turn will echo back the token claims as a JSON document.

Screenshot 2016-08-17 11.45.50

Have fun!

 

Posted in ASP.NET, IdentityServer, OpenID Connect, OWIN, Uncategorized, WebAPI | 2 Comments

Commercial Support Options for IdentityServer

Many customers have asked us for production support for IdentityServer. While this is something we would love to provide, Brock and I can’t do that on our own because we can’t guarantee the response times.

I am happy to announce that we have now partnered with our good friends at Rock Solid Knowledge to provide commercial support for IdentityServer!

RSK has excellent people with deep IdentityServer knowledge and Brock and I will help out as 2nd level support if needed.

Head over to https://www.identityserver.com/ and get in touch with them!

Posted in ASP.NET, IdentityServer, OAuth, OpenID Connect, WebAPI | 1 Comment

Fixing OAuth 2.0 with OpenID Connect?

I didn’t like Nat’s Fixing OAuth? post.

“For protecting a resource with low value, current RFC6749 and RFC6750 with an appropriate constraint should be good enough…For protecting a resource whose value is higher than a certain level, e.g., the write access to the Financial API, then it would be more appropriate to use a modified protocol.”

I agree that write access to a financial API is a high value operation (and security measure will go far beyond authentication and token requests) – but most users and implementers of OAuth 2.0 based system would surely disagree that their resources only have a low value.

Then on the other hand I agree that OAuth 2.0 (or rather RFC6749 and 6750) on its own indeed has its issues and I would advise against using it (important part “on its own”).

Instead I would recommend using OpenID Connect – all of the OAuth 2.0 problems regarding client to provider communication are already fixed in OIDC – metadata, signed protocol responses, sender authentication, nonces etc.

When we designed identity server, we always saw OpenID Connect as a “super-set” of OAuth 2.0 and always recommended against using OAuth without the OIDC parts. Some people didn’t like that – but applying sound constraints definitely helped security.

I really don’t understand why this is not the official messaging? Maybe it’s political?

Screenshot 2016-07-29 08.42.17.png

(no response)

Wrt to the issues around bearer tokens – well – I really, really don’t understand why proof of possession and HTTP signing takes that long and seems to be such a low priority. We successfully implemented PoP tokens in IdentityServer and customers are using it. Of course there are issues – there will always be issues. But sitting on a half done spec for years will definitely not solve them.

So my verdict is – for interactive applications, don’t use OAuth 2.0 on its own. Just use OpenID Connect and identity tokens in addition to access tokens – you don’t need to be a financial API to have proper security.

 

Posted in IdentityServer, OAuth, OpenID Connect, WebAPI | 13 Comments

.NET Core 1.0 is released, but where is IdentityServer?

In short: we are working on it.

Migrating the code from Katana to ASP.NET Core was actually mostly mechanical. But obviously new approaches and patterns have been introduced which might, or might not align directly with how we used to do things in IdentityServer3.

We also wanted to take the time to do some re-work and re-thinking, as well as doing some breaking changes that we couldn’t easily do before.

For a roadmap – in essence we will release a beta including the new UI interaction next week. Then we will have an RC by August and an RTM before the final ASP.NET/.NET Core tooling ships later this year.

Meanwhile we encourage you to try the current bits and give us feedback. The more the better.

Stay tuned.

Posted in ASP.NET, IdentityServer, OAuth, OpenID Connect, WebAPI | 2 Comments

Update for authentication & API access for native applications and IdentityModel.OidcClient

The most relevant spec for authentication and API access for native apps has been recently updated.

If you are “that kind of person” that enjoys looking at diffs of pre-release RFCs – you would have spotted a new way of dealing with the system browser for desktop operating systems (e.g. Windows or MacOS).

Quoting section 7.3:

“More applicable to desktop operating systems, some environments allow apps to create a local HTTP listener on a random port, and receive URI redirects that way.  This is an acceptable redirect URI choice for native apps on compatible platforms.”

IOW – your application launches a local “web server”, starts the system browser with a local redirect URI and waits for the response to come back (either a code or an error). This is much easier than trying to fiddle with custom URL monikers and such on desktop operating systems.

William Denniss – one of the authors of the above spec and the corresponding reference implementations – also created a couple of samples that show the usage of that technique for Windows desktop apps.

Inspired by that I, created a sample showing how to do OpenID Connect authentication from a console application using IdentityModel.OidcClient.

In a nutshell – it works like this:

Open a local listener

// create a redirect URI using an available port on the loopback address.
string redirectUri = string.Format("http://127.0.0.1:7890/");
Console.WriteLine("redirect URI: " + redirectUri);
 
// create an HttpListener to listen for requests on that redirect URI.
var http = new HttpListener();
http.Prefixes.Add(redirectUri);
Console.WriteLine("Listening..");
http.Start();

 

Construct the start URL, open the system browser and wait for a response

var options = new OidcClientOptions(
    "https://demo.identityserver.io",
    "native.code",
    "secret",
    "openid profile api",
    redirectUri);
options.Style = OidcClientOptions.AuthenticationStyle.AuthorizationCode;
 
var client = new OidcClient(options);
var state = await client.PrepareLoginAsync();
 
Console.WriteLine($"Start URL: {state.StartUrl}");
            
// open system browser to start authentication
Process.Start(state.StartUrl);
 
// wait for the authorization response.
var context = await http.GetContextAsync();

 

Process the response and access the claims and tokens

var result = await client.ValidateResponseAsync(context.Request.Url.AbsoluteUri, state);
 
if (result.Success)
{
    Console.WriteLine("\n\nClaims:");
    foreach (var claim in result.Claims)
    {
        Console.WriteLine("{0}: {1}", claim.Type, claim.Value);
    }
 
    Console.WriteLine();
    Console.WriteLine("Access token:\n{0}", result.AccessToken);
 
    if (!string.IsNullOrWhiteSpace(result.RefreshToken))
    {
        Console.WriteLine("Refresh token:\n{0}", result.RefreshToken);
    }
}
else
{
    Console.WriteLine("\n\nError:\n{0}", result.Error);
}
 
http.Stop();

 

Sample can be found here – have fun ;)

 

 

Posted in IdentityModel, OAuth, OpenID Connect, WebAPI | 10 Comments

Identity Videos, Podcasts and Slides from Conference Season 2016/1

My plan was to cut down on conferences and travelling in general – this didn’t work out ;) I did more conferences in the first 6 months of 2016 than I did in total last year. weird.

Here are some of the digital artefacts:

NDC Oslo 2016: Authentication & secure API access for native & mobile Applications

DevSum 2016: What’s new in ASP.NET Core Security

DevSum 2016: Buzzfrog Podcast with Dag König

DevWeek 2016: Modern Applications need modern Identity

DevWeek 2016: Implementing OpenID Connect and OAuth 2.0 with IdentityServer

All my slides are on speakerdeck.

Posted in .NET Security, ASP.NET, Conferences & Training, IdentityModel, IdentityServer, OAuth, OpenID Connect, Uncategorized, WebAPI | Leave a comment