Quantcast
Channel: IdentityModel – leastprivilege.com
Viewing all 204 articles
Browse latest View live

Retrieving bearer tokens from alternative locations in Katana/OWIN

$
0
0

The Katana bearer token authentication middleware tries to retrieve tokens from the HTTP Authorization header with a scheme of Bearer by default.

You can customize this behavior by providing a so called Provider (this is a common pattern in Katana). The following provider retrieves the access token from a query string:

public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider

{

    readonly string _name;

 

    public QueryStringOAuthBearerProvider(string name)

    {

        _name = name;

    }

 

    public override Task RequestToken(OAuthRequestTokenContext context)

    {

        var value = context.Request.Query.Get(_name);

 

        if (!string.IsNullOrEmpty(value))

        {

            context.Token = value;

        }

 

        return Task.FromResult<object>(null);

    }

}

 

…or from an alternative header:

public class HeaderOAuthBearerProvider : OAuthBearerAuthenticationProvider

{

    readonly string _name;

 

    public HeaderOAuthBearerProvider(string name)

    {

        _name = name;

    }

 

    public override Task RequestToken(OAuthRequestTokenContext context)

    {

        var value = context.Request.Headers.Get(_name);

 

        if (!string.IsNullOrEmpty(value))

        {

            context.Token = value;

        }

 

        return Task.FromResult<object>(null);

    }

}

You can the pass such a provider to the middleware, e.g.:

var options = new JwtBearerAuthenticationOptions

{

    AllowedAudiences = new[] { audience },

    IssuerSecurityTokenProviders = new[]

        {

            new SymmetricKeyIssuerSecurityTokenProvider(

                issuer,

                signingKey)

        },

    Provider = new QueryStringOAuthBearerProvider(“access_token”)

};

 

..or by using the helpers from Thinktecture.IdentityModel.Owin:

app.UseJsonWebToken(

    issuer:     Constants.AS.IssuerName,

    audience:   Constants.Audience,

    signingKey: Constants.AS.SigningKey,

    location:   TokenLocation.QueryString(“access_token”));

 


Filed under: IdentityModel, Katana, OWIN, WebAPI

Thinktecture AuthenticationHandler for Web API v2

$
0
0

Here I mentioned that there are some incompatibilities between AuthenticationHandler and Web API v2/OWIN hosting.

As part of making Thinktecture.IdentityModel more modular – I updated the AuthenticationHandler code and did some cleanup. You can find the source code here and the Nuget package here. HTH


Filed under: IdentityModel, Katana, OWIN, WebAPI

Client Certificate Authentication Middleware for Katana

$
0
0

Katana has no middleware to turn SSL client certificates into a ClaimsIdentity. And since I am currently collecting material for my upcoming Web API security course I used the opportunity to experiment with Katana authentication middleware.

There’s a certain pattern you have to follow for integrating into the Katana security model. It all starts with a class that configures the authentication mechanism – the so called options:

public class ClientCertificateAuthenticationOptions : AuthenticationOptions

{

    public X509CertificateValidator Validator { get; set; }

    public bool CreateExtendedClaimSet { get; set; }

 

    public ClientCertificateAuthenticationOptions() : base(“X.509”)

    {

        Validator = X509CertificateValidator.ChainTrust;

        CreateExtendedClaimSet = false;

    }

}

You have to derive from AuthenticationOptions and set your default authentication type – that’s just a string and can be changed by the user of your middleware. You further expose whatever customization make sense for you – in my case the certificate validator and an indicator if you want a minimal or a full claim set.

The real work is done in a so called authentication handler – again there is base class to derive from. You typically need to implement AuthenticateCoreAsync (credential validation) and ApplyResponseChallengeAsync (challenge generation). Client certificates don’t really have an HTTP challenge – so I skipped this method. There are other methods that you can override when you need initialization and cleanup features (InitializeCoreAsync and TeardownCoreAsync).

In the authentication logic, you inspect the incoming credential and – if present – turn it into a ClaimsIdentity. This identity in turn gets wrapped into an authentication ticket which allows to couple the identity with additional properties that are not claims. –

public class ClientCertificateAuthenticationHandler :
  AuthenticationHandler
<ClientCertificateAuthenticationOptions
>

{

    protected override Task<AuthenticationTicket> AuthenticateCoreAsync()

    {

        var cert = Context.Get<X509Certificate2>(“ssl.ClientCertificate”);

 

        if (cert == null)

        {

            return Task.FromResult<AuthenticationTicket>(null);

        }

 

        try

        {

            Options.Validator.Validate(cert);

        }

        catch

        {

            return Task.FromResult<AuthenticationTicket>(null);

        }

 

        var claims = GetClaimsFromCertificate(
          cert, cert.Issuer, Options.CreateExtendedClaimSet);

 

        var identity = new ClaimsIdentity(Options.AuthenticationType);

        identity.AddClaims(claims);

 

        var ticket = new AuthenticationTicket(
          identity,
new AuthenticationProperties
());

        return Task.FromResult<AuthenticationTicket>(ticket);

    }

}

 

The glue between the handler, lifetime management, configuration and the Katana pipeline is the Katana authentication middleware. It’s responsibility is to create the handler, transfer the options and call the corresponding methods on the handler at the right point in time:

public class ClientCertificateAuthenticationMiddleware :
  AuthenticationMiddleware
<ClientCertificateAuthenticationOptions
>

{

    public ClientCertificateAuthenticationMiddleware(
     
OwinMiddleware next,
     
ClientCertificateAuthenticationOptions
options)

        : base(next, options)

    { }

 

    protected override AuthenticationHandler<ClientCertificateAuthenticationOptions> CreateHandler()

    {

        return new ClientCertificateAuthenticationHandler();

    }

}

…and with a bit of extension method syntactic sugar – you end up here:

app.UseClientCertificateAuthentication();

app.UseWebApi(WebApiConfig.Register());

 

The claims describing the client certificate can then be retrieved either using the OwinContext or Web API specific using the RequestContext.


Filed under: IdentityModel, Katana, OWIN, WebAPI

Adding Refresh Tokens to a Web API v2 Authorization Server

$
0
0

In the last post I showed how to add a simple username/password (aka resource owner password credentials flow) authorization server to Web API v2. This has several advantages:

  • The client does not need to hold on to the user credentials after the token has been requested (e.g. for re-submitting them on every request)
  • The user does not need to re-enter his credentials for the lifetime of the token
  • The back end does not need to validate the password on each request (passwords become harder and harder too secure – and validation becomes increasingly expensive)
  • Credential validation is factored out into the authorization server, and does not “pollute” the business services

This is already a big improvement. But there are also some security/architecture considerations:

  • Once the token has been issued, there is no “built-in” way to revoke it. Or in other words you’d need to write your own mechanism for that which often involves database checks on each request. Doable – but often defeats the purpose.
  • Related to that – when a claim that’s inside the token changes in your back end (e.g. role membership) you cannot easily “update” the token. You need to wait until the old token expires for the new claims to propagate. A good example of that is Windows authentication – when an admin adds or removes you from a Windows group, you need to logoff/logon for your Windows token to get updated.

For these reasons you need to find a balance between usability (how often must the user re-authenticate) and security/enforcing business requirements.

Refresh tokens can potentially improve the situation but also increase complexity. A refresh token is a long lived token that allows requesting new access tokens without having to present the user credentials again. This means that the access token itself could be short lived and whenever the refresh token is used to request a new access token, the contents of that access token can be updated. But with that power, you’ll have more responsibilities. Let’s have a look.

Refresh tokens must be bound to a client – you typically don’t want that a refresh token from your desktop client can be used from the web client and so on (this is also important for being able to revoke them). That means you need to introduce client authentication (or at least identification). This also means that your client needs an embedded credential (or must use dynamic client registration – but that is out of scope for this post). Depending on the client type this might not be a real secret and shouldn’t be used to base further security decisions on.

This changes how the ValidateClientAuthentication method looks like. We need to validate client credentials, and need to make the client ID available in the pipeline for later processing (unfortunately we need to use the OWIN context for that because of some shortcoming in the current middleware API).

public override async Task ValidateClientAuthentication
  (
OAuthValidateClientAuthenticationContext
context)

{

    // validate client credentials (demo)

    // should be stored securely (salted, hashed, iterated)

    string id, secret;

    if (context.TryGetBasicCredentials(out id, out secret))

    {

        if (secret == “secret”)

        {

            // need to make the client_id available for later security checks

            context.OwinContext.Set<string>(“as:client_id”, id);

            context.Validated();

        }

    }

}

We also need slight modifications to the GrantResourceOwnerCredentials method. In there we need to add some metadata to the resulting authentication ticket about the client. This will be used later when it comes to creating and persisting the refresh token.

public override async Task GrantResourceOwnerCredentials
  (
OAuthGrantResourceOwnerCredentialsContext
context)

{

    // validate user credentials (demo mode)

    // should be stored securely (salted, hashed, iterated)       

    if (context.UserName != context.Password)

    {

        context.Rejected();

        return;

    }

 

    // create identity

    var id = new ClaimsIdentity(“Embedded”);

    id.AddClaim(new Claim(“sub”, context.UserName));

    id.AddClaim(new Claim(“role”, “user”));

 

    // create metadata to pass on to refresh token provider

    var props = new AuthenticationProperties(new Dictionary<string, string>

        {

            { “as:client_id”, context.ClientId }

        });

 

    var ticket = new AuthenticationTicket(id, props);

    context.Validated(ticket);

}

At this point, the refresh token handler alongside the authentication ticket need to be persisted in some data store – – I’ll skip that for now and come back to it later.

There is one method you need to add to the authorization server provider. This method is called when the actual refresh token request comes in. In there you need to verify that the current client is actually the client that requested the token in the first place (the client binding). Here’s also your chance to modify the outgoing access token when you want to update claims etc..

public override async Task GrantRefreshToken(
 
OAuthGrantRefreshTokenContext
context)

{

    var originalClient = context.Ticket.Properties.Dictionary[“as:client_id”];

    var currentClient = context.OwinContext.Get<string>(“as:client_id”);

 

    // enforce client binding of refresh token

    if (originalClient != currentClient)

    {

        context.Rejected();

        return;

    }

 

    // chance to change authentication ticket for refresh token requests

    var newId = new ClaimsIdentity(context.Ticket.Identity);

    newId.AddClaim(new Claim(“newClaim”, “refreshToken”));

 

    var newTicket = new AuthenticationTicket(newId, context.Ticket.Properties);

    context.Validated(newTicket);

}

The last missing piece is persistence – this is encapsulated in an IAuthenticationTokenProvider derived class. Here you need to create a secure handle for the refresh token and associate the authentication ticket with it to store it in some data store. Refresh token handles should be treated as secrets and should be stored hashed (I leave that as an exercise). Another security decision to make is if you want the refresh handle to be one-time use only, or if you re-use the same handle for that client/application combination. Most implementations I have seen so far seem to re-use the handle, my sample uses the one-time approach:

// sample persistence of refresh tokens

// this is not production ready!

public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider

{

    private static ConcurrentDictionary<string, AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string,AuthenticationTicket>();

 

    public async Task CreateAsync(AuthenticationTokenCreateContext context)

    {

        var guid = Guid.NewGuid().ToString();

           

        // maybe only create a handle the first time, then re-use

        _refreshTokens.TryAdd(guid, context.Ticket);

 

        // consider storing only the hash of the handle

        context.SetToken(guid);

    }

 

    public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)

    {

        AuthenticationTicket ticket;

        if (_refreshTokens.TryRemove(context.Token, out ticket))

        {

            context.SetTicket(ticket);

        }

    }

}

You then register the token provider in startup (note the shorter access token lifetime):

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions

    {

        // for demo purposes

        AllowInsecureHttp = true,

 

        TokenEndpointPath = new PathString(“/token”),

        AccessTokenExpireTimeSpan = TimeSpan.FromHours(1),

 

        Provider = new SimpleAuthorizationServerProvider(),

        RefreshTokenProvider = new SimpleRefreshTokenProvider()

    });

 

The Client
On the client side you now have to distinguish between three phases – requesting the initial access token (+ refresh token), using that token until it expires and requesting a new access token using the refresh token. You also need to pass in the client id and secret to all requests to the authorization server. Using the Thinktecture.IdentityModel.Client OAuth2Client this looks like this:

private static TokenResponse GetToken()

{

    var client = new OAuth2Client(

        new Uri(http://localhost:2727/token),

        “client1”,

        “secret”);

 

    var response = client.RequestResourceOwnerPasswordAsync(
     
“bob”, “bob”
).Result;

    return response;

}

 

private static TokenResponse RefreshToken(string refreshToken)

{

    var client = new OAuth2Client(

        new Uri(http://localhost:2727/token),

        “client1”,

        “secret”);

 

    var response = client.RequestRefreshTokenAsync(refreshToken).Result;

    return response;

}

 

Summary
This post turned out to be longer than I planned  – and that reminds me that there is indeed some complexity here, e.g.:

  • secure storage of user and client credentials as well as token handles
  • doing proper client binding for token handles
  • thinking about retention policies for handles (one-time vs. re-use)
  • persistence layer

And we haven’t even touched topics like refresh token revocation and the added complexity of scopes and supporting multiple OAuth2 flows.

As you’ve seen above this is all doable using Web API v2 built-in tech – that’s nice. Another option of course would be to use AuthorizationServer which has the above already built-in and much much more.

Full sample here.


Filed under: AuthorizationServer, IdentityModel, Katana, OAuth, OWIN, WebAPI

Thinktecture.IdentityModel.Client v1.0

$
0
0

As part of the restructuring work of IdentityModel, I separated the HTTP and OAuth2 client bits into a separate project. The nice side effect of this is that the client library is now portable and can be used in .NET 4.5, WinRT, Windows Phone 8 and Xamarin.

What’s inside?

OAuth2 token requests
The OAuth2Client class assists in making requests to a OAuth2 token endpoint. It supports code, password, refresh token, client credentials and assertion grants, e.g.:

private async Task<TokenResponse> RequestTokenAsync(
 
string userName, string
password)

{

    var client = new OAuth2Client(

        new Uri(_baseAddress + “/token”),

        “clientId”,

        “clientSecret”);

 

    return await client.RequestResourceOwnerPasswordAsync(userName, password);

}

Besides scope, you can also pass arbitrary additional parameters.

Creating authorize request URLs
Another helper creates URLs for authorize requests – in particular for the code and implicit flow:

var client = new OAuth2Client(endpoint);

var startUri = client.CreateImplicitFlowUrl(

    clientId,

    scope,

    callbackUri.AbsoluteUri);

 

Parsing authorize and token responses
We can also help parsing responses coming back from authorize and token endpoints, following example is part of an implicit flow client (parsing the redirect URI of a web view):

private string GetToken(string redirectUri)

{

    var response = new AuthorizeResponse(redirectUri);

    return response.AccessToken;

}

Again these classes support additional response parameters that are not part of the core spec.

Extensions methods
The library also includes extensions methods for HttpClient to set bearer and basic authentication authorization headers and helpers to deal with epoch time (the time format used in OAuth2 expires_in responses).

var client = new HttpClient { BaseAddress = _baseAddress };

client.SetBearerToken(token);

 

var response = await client.GetStringAsync(“api/identity”);

 

Give it a try and give us feedback! The source code can be found here – and the nuget here.


Filed under: IdentityModel, OAuth, WebAPI

Advanced OAuth2: Assertion Flow (how)

$
0
0

My last post described the mechanics and motivation for the OAuth2 assertion flow.

In this post I want to show you how you can use Thinktecture AuthorizationServer to implement an assertion flow scenario. For this specific example I will use Microsoft Account authentication on WinRT – but this could be substituted by any other authentication system (see my last post for more examples).

1 Microsoft Account authentication
The easiest way to do MSA authentication is to use the Live SDK.

For WinRT – you first need to register your application in the store. This will result in a client ID and a client secret. Next you need to associate your VS solution with that store app (right click the project in solution explorer –> Store –> Associate App with the Store).

The following code does the interaction with the MSA infrastructure:

var scopes = new string[] { “wl.signin” };

var authClient = new LiveAuthClient(http://www.thinktecture.com);

 

// try silent logon first

_loginResult = await authClient.InitializeAsync(scopes);

 

if (_loginResult.Status != LiveConnectSessionStatus.Connected)

{

    // need to (re) prompt

    _loginResult = await authClient.LoginAsync(scopes);

 

    if (_loginResult.Status != LiveConnectSessionStatus.Connected)

    {

        await new MessageDialog(“Access denied!”).ShowAsync();

        return;

    }

}

A few things to note here:

  • If the user uses his Microsoft Account to sign into Windows, there is no need to re-authenticate (single sign-on).
  • The first time this code runs, the user will be prompted for consent (see screenshot). Afterwards the consent decision will be remembered and the dialog will not be shown again.
  • The above code does not include the client ID – that is implicitly sourced from the application package identity (that’s why we needed to associate the VS solution with the store app).
  • The above code also does not include a client secret, this is not used at all on the client (it couldn’t be stored there securely anyways) – but later when it comes to validate the token in AuthorizationServer.

 

image

The login result actually contains two tokens: an access token for Microsoft’s backend that you can use to access the users’ data (profile, friends etc.) and an identity token.

image

The access token format is a private implementation detail, the identity token (or authentication token as they call it) is actually a JWT. We can peek inside the token using this tool:

image

As you can see – the token contains information about the issuer, expiration, the subject as well as the identity of the client. The token is signed by the client secret and can be used as input for the assertion flow.

2 Registering the client for assertion flow in AuthorizationServer
Before the client application can use the assertion flow with AuthorizationServer, you need to register it. Starting with version 1.1 we have a new option in the flows drop-down:

image

Also make sure the client is allowed to request at least one scope in the application.

3 Using Assertion Flow to request an access token
Requesting an access token using an assertion is easy. Our OAuth2Client library has direct support for that:

var client = new OAuth2Client(

    new Uri(https://as.local/users/oauth/token),

    “assertionclient”,

    “secret”);

 

_asTokenResponse = await client.RequestAssertionAsync(

    “urn:msaidentitytoken”,

    _loginResult.Session.AuthenticationToken,

    “read”);

 

This will create an (authenticated) POST to the token endpoint looking like this:

grant_type=urn:msaidentitytoken&
assertion=abcxyz&
scope=read

The urn:msaidentitytoken is something I came up with – it is used in the next step to give AuthorizationServer a hint how to validate the token. As mentioned in my previous post, there are also official grant types for SAML2 and JWT.

4 Validating the token
The last step is to tell AuthorizationServer how to validate the incoming token. For this purpose there is a new interface in AS called IAssertionGrantValidation:

public interface IAssertionGrantValidation

{

    ClaimsPrincipal ValidateAssertion(ValidatedRequest validatedRequest);

}

You can simply implement that interface and plug it into AS by either wiring up your code in autofacConfig.cs or in autofac.config (both in the WebHost project).

To validate Microsoft Account authentication tokens you can use the Live SDK, e.g.:

public class AssertionGrantValidator : IAssertionGrantValidation

{

    public const string MsaIdentityToken = “urn:msaidentitytoken”;

 

    public ClaimsPrincipal ValidateAssertion(
     
ValidatedRequest
validatedRequest)

    {

        if (validatedRequest.AssertionType == MsaIdentityToken)

        {

            var appId = “ms-app://s-1-15-2…1721910”;

            var appSecret = “jqR…xOxv”;

            var redirectUri = http://www.thinktecture.com;

 

            var authClient = new LiveAuthClient(

                    appId,

                    appSecret,

                    redirectUri);

 

            var msaId = authClient.GetUserId(validatedRequest.Assertion);

            var id = new ClaimsIdentity(“MSA”);

            id.AddClaim(new Claim(ClaimTypes.NameIdentifier, msaId));

 

            return FederatedAuthentication
              .FederationConfiguration
              .IdentityConfiguration
              .ClaimsAuthenticationManager
              .Authenticate(

                “AssertionValidation”,

                new ClaimsPrincipal(id));

        }

 

        return null;

    }

 

Here is where the MSA client secret comes in, it is used to validate the authentication token. Afterwards the extension creates a ClaimsIdentity, runs it through claims transformation and passes it back to AS. AS in turn will create the usual access token, sign it and return it to the client.

From that point the client can use the access token to access the resource servers just as usual.

image

Assertion flow support is new in AS v1.1 – give it a try and give us feedback if you like it or not.


Filed under: ASP.NET, AuthorizationServer, IdentityModel, OAuth, WebAPI

OpenID Connect and the IdentityServer Roadmap

$
0
0

Since OpenID Connect has been officially released now, I thought I’ll tell you a little bit more about our plans around our identity open source projects.

IdentityServer
IdSrv is a very popular identity provider with excellent support for WS-Federation and WS-Trust. It has decent support for OAuth2 and OpenID Connect (basic client profile) since quite some time – but these protocols were more like an afterthought than part of the initial design. IdSrv uses by default the pretty dated ASP.NET membership, but can be easily extended to use different data stores.

AuthorizationServer
We built AS because we wanted to implement OAuth2 “the right way” and we thought it is easier to start from scratch than retrofitting it into IdSrv. We deliberately didn’t add any authentication / user management pieces to AS because we wanted it to be freely combinable with existing infrastructure. For people without existing infrastructure, this was often a problem because setting up the IdP and AS at the same time was a steep learning curve.

While both projects solved very specific problems, there was room for improvement:

  • Combine identity management and a full featured OAuth2 implementation in a single component – still be able to use them independently if needed
  • Make it more lightweight so it can be hosted more flexibly
  • Incorporate OpenID Connect true cross platform client / relying party support (which was always a problem with WS-Federation)
  • Make authentication and acquisition of access tokens possible in a single round trip – which is a scenario that becomes more and more common.

So we actually decided to combine all those improvements and feature ideas into a new project currently codenamed “IdentityServer v3” :

  • Single codebase and server component to deploy
  • OpenID Connect and OAuth2 as the core protocols – but extensible to add support for e.g. WS-Federation
  • Built as an OWIN/Katana component with no dependencies on a specific host (e.g. IIS)
  • Completely customizable – think “STS toolkit”
  • Ability to incorporate arbitrary identity management systems – support for Brock’s MembershipReboot and ASP.NET Identity by default
  • Separation of core STS and user / configuration management for more flexibility
  • ..and more

We are not done yet – but will have more details soon – in the meantime – here’s a preview screenshot of a consent screen for a native client requesting identity claims (user id and email) as well as access tokens for an HTTP API backend.

image


Filed under: AuthorizationServer, IdentityModel, IdentityServer, Katana, OAuth, OpenID Connect, OWIN, WebAPI

Validating Scopes in ASP.NET 4 and 5

$
0
0

OAuth 2.0 scopes are a way to model (API) resources. This allows you to give logical “names” to APIs that clients can use to request tokens for.

You might have very granular scopes like e.g. api1 & api2, or very coarse grained like application.backend. Some people use functional names e.g. contacts.api and customers.api (which might or might not span multiple physical APIs) – some group by criteria like public or internal only. Some even sub-divide a single API – e.g. calendar.read and calendar.readwrite. It is totally up to you (this is how Google uses scopes).

At the end of the day, the access token (be it self-contained or referenced) will be associated with the scopes the client was authorized for (and optionally – the user consented to).

IdentityServer does that by including claims of type scope in the access token – so really any technique that allows checking the claims of the current user will do.

As a side note – there is also a spec that deals with return codes for failed scope validation. In short – this should return a 403 instead of a 401.

We ourselves had some iterations in our thinking how we deal with scopes – here’s a summary and some options.

ASP.NET 4.x

The most common way we do scope checking is via our token validation middleware (source/nuget), which combines token and scope validation into a single step:

app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
    {
        Authority = "https://localhost:44333/core",
        RequiredScopes = new[] { "calendar.read""calendar.readwrite" },
    });

This would validate the token and require that either the calendar.read or calendar.readwrite scope claims are present.

This middleware also emits the right response status code, Www-Authenticate header and respects CORS pre-flight requests.

For finer granularity we also once wrote a Web API authorization attribute – [ScopeAuthorize] that you can put on top of controllers and actions (source).

As mentioned before – you can always check inside your code for scope claims yourself using the claims collection.

ASP.NET 5

We will have the same “all in one” IdentityServer token validation middleware for ASP.NET 5 – but this time split up into separate middleware that can be also used stand-alone (I wrote about the introspection aspect of it in my last post).

The scope validation part (source/nuget) of it looks like this:

app.AllowScopes("calendar.read""calendar.readwrite");

This has the same OR semantics as described above.

You can also use the new ASP.NET 5 authorization API to do scope checks – e.g. as a global policy:

public void ConfigureServices(IServiceCollection services)
{
    var scopePolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireClaim("scope""calendar.read""calendar.readwrite")
        .Build();

    services.AddMvc(options =>
    {
        options.Filters.Add(new AuthorizeFilter(scopePolicy));
    });
}

..or as a named policy to decorate individual controllers and actions:

services.AddAuthorization(options =>
{
    options.AddPolicy("read",
        policy => policy.RequireClaim("scope""calendar.read"));
    options.AddPolicy("readwrite",
        policy => policy.RequireClaim("scope""calendar.readwrite"));
});

and use it e.g. like that:

public class CalendarControllerController
{
    [Authorize("read")]
    public IActionFilter Get() { ... }

    [Authorize("readwrite")]
    public IActionFilter Put() { ... }
}

One last remark: We get this question a lot – scopes are not used for authorizing users. They are used for modeling resources (and optionally to compose the consent screen as well as to specify which client might have access to these resources).

HTH


Filed under: ASP.NET, IdentityModel, IdentityServer, Katana, OAuth, Uncategorized, WebAPI

IdentityModel: OpenID Connect & OAuth 2.0 Client Library for Mobile/Native Applications

$
0
0

Recently we had a couple of customers that needed to connect their native desktop and mobile applications to an OpenID Connect and OAuth 2.0 back-end.

We always had samples that showed how to do this, but making them re-usable and cross-platform was a bit harder than I originally thought. At the same time the IETF released some good guidance around OAuth 2.0 for native applications (draft-spec) that I wanted to incorporate.

The end result of that is IdentityModel.OidcClient, which is a PCL that runs on desktop .NET, WinRT/UWP and Xamarin iOS and Android. It encapsulates all the protocol and crypto work needed for OpenID Connect Hybrid Flow with PKCE and can reduce all those steps to a few lines of code:

var client = new OidcClient(options);
var result = await client.LoginAsync();

The result object will contain the claims of the user as well as an access token and refresh token (if requested).

The second problem I wanted to solve is keeping the access tokens fresh without putting too much logic into the client application. This is done by an HTTP message handler that you can plug into HttpClient. The handler will add the access token to outgoing requests and try to refresh the token whenever it sees a 401 response. You would then use this one HttpClient throughout your code:

_client = new HttpClient(result.Handler);
_client.BaseAddress = new Uri("https://demo.identityserver.io/api/");

You can find more code snippets in the readme and the samples repo contains sample WinForms, UWP and iOS clients.

OSS FTW
To create such a library as a PCL was a combined effort – I’d like to thank Andrew Arnott for PCLCrypto and dvsekhvalnov for building Jose-Pcl on top. Without them JWT validation wouldn’t be possible.

I pushed a 1.0 to nuget – but there is still a lot of work. I opened a couple of issues already which are all up for grabs.

We also need more samples – Android, WPF and console hosts come to mind. Please support OidcClient and the above libraries by giving feedback and maybe contributing to them.

HTH

 


Filed under: IdentityModel, OAuth, OpenID Connect

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

$
0
0

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.


Filed under: .NET Security, ASP.NET, Conferences & Training, IdentityModel, IdentityServer, OAuth, OpenID Connect, Uncategorized, WebAPI

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

$
0
0

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 ;)

 

 


Filed under: IdentityModel, OAuth, OpenID Connect, WebAPI

Identity & Access Control for ASP.NET Core Deep Dive

$
0
0

Once a year Brock and I do our three day version of the Identity & Access Control workshop in London.

This year it will be all about .NET Core and ASP.NET Core – and a full day on the new IdentityModel2 & IdentityServer4.

You can find the details and sign-up here – and there is an early bird ’til the 23rd September.

Really looking forward to this, since the extra day gives us so much more time for labs and going even deeper on the mechanics are architecture of modern identity and applications.

See you there!


Filed under: .NET Security, ASP.NET, IdentityModel, IdentityServer, OAuth, OpenID Connect, WebAPI

IdentityModel v2 released

$
0
0

IdentityModel is our protocol client library for various OpenID Connect and OAuth 2 endpoints like discovery, userinfo, token, introspection and token revocation. In addition it has some general purpose helpers like generating random numbers, base64 URL encoding, time-constant string comparison and X509 store access.

V1 is a PCL – but V2 now targets netstandard 1.3 (and classic .NET 4.5). Since we have quite a big user base for V1, we didn’t want to break anyone doing that change. This is the reason why v1 and v2 now live in separate repos and can evolve independently if needed.

See the readme for examples what IdentityModel can do – and – as always give us feedback via the issue tracker.


Filed under: .NET Security, IdentityModel, OAuth, OpenID Connect, WebAPI

IdentityServer4 RC2 released

$
0
0

Yesterday we pushed IdentityServer4 RC2 to nuget. There are no big new features this time, but a lot of cleaning up, bug fixing and adding more tests.

We might add one or two more bigger things before RTM – but mainly we are in stabilization-mode right now.

All the docs have been updated, and the release notes give you more details on the changes.

Please go ahead and try it out – and give us feedback on the issue tracker. The more, the better.


Filed under: .NET Security, ASP.NET, IdentityModel, IdentityServer, OAuth, OpenID Connect, WebAPI

IdentityModel.OidcClient v2 & the OpenID RP Certification

$
0
0

A couple of weeks ago I started re-writing (an re-designing) my OpenID Connect & OAuth 2 client library for native applications. The library follows the guidance from the OpenID Connect and OAuth 2.0 for native Applications specification.

Main features are:

  • Support for OpenID Connect authorization code and hybrid flow
  • Support for PKCE
  • NetStandard 1.4 library, which makes it compatible with x-plat .NET Core, desktop .NET, Xamarin iOS & Android (and UWP soon)
  • Configurable policy to lock down security requirements (e.g. requiring at_hash or c_hash, policies around discovery etc.)
  • either stand-alone mode (request generation and response processing) or support for pluggable (system) browser implementations
  • support for pluggable logging via .NET ILogger

In addition, starting with v2 – OidcClient is also now certified by the OpenID Foundation for the basic and config profile.

oid-l-certification-mark-l-cmyk-150dpi-90mm

It also passes all conformance tests for the code id_token grant type (hybrid flow) – but since I don’t support the other hybrid flow combinations (e.g. code token or code id_token token), I couldn’t certify for the full hybrid profile.

For maximum transparency, I checked in my conformance test runner along with the source code. Feel free to try/verify yourself.

The latest version of OidcClient is the dalwhinnie release (courtesy of my whisky semver scheme). Source code is here.

I am waiting a couple more days for feedback – and then I will release the final 2.0.0 version. If you have some spare time, please give it a try (there’s a console client included and some more sample here <use the v2 branch for the time being>). Thanks!


Filed under: .NET Security, IdentityModel, OAuth, OpenID Connect, WebAPI

OpenID Connect Client Library for JavaScript/SPA-style Applications

NDC London 2017

Using iOS11 SFAuthenticationSession with IdentityModel.OidcClient

$
0
0

Starting with iOS 11, there’s a special system service for browser-based authentication called SFAuthenticationSession. This is the recommended approach for OpenID Connect and OAuth 2 native iOS clients (see RFC8252).

If you are using our OidcClient library – this is how you would wrap that in an IBrowser:

using Foundation;
using System.Threading.Tasks;
using IdentityModel.OidcClient.Browser;
using SafariServices;
 
namespace iOS11Client
{
    public class SystemBrowser : IBrowser
    {
        SFAuthenticationSession _sf;
 
        public Task InvokeAsync(BrowserOptions options)
        {
            var wait = new TaskCompletionSource();
 
            _sf = new SFAuthenticationSession(
                new NSUrl(options.StartUrl),
                options.EndUrl,
                (callbackUrl, error) =>
                {
                    if (error != null)
                    {
                        var errorResult = new BrowserResult
                        {
                            ResultType = BrowserResultType.UserCancel,
                            Error = error.ToString()
                        };
 
                        wait.SetResult(errorResult);
                    }
                    else
                    {
                        var result = new BrowserResult
                        {
                            ResultType = BrowserResultType.Success,
                            Response = callbackUrl.AbsoluteString
                        };
 
                        wait.SetResult(result);
                    }
                });
 
            _sf.Start();
            return wait.Task;
        }
    }
}

The State of HttpClient and .NET Multi-Targeting

$
0
0

IdentityModel is a library that uses HttpClient internally – it should also run on all recent versions of the .NET Framework and .NET Core.

HttpClient is sometimes “built-in”, e.g. in the .NET Framework, and sometimes not, e.g. in .NET Core 1.x. So fundamentally there is a “GAC version” and a “Nuget version” of the same type.

We had lots of issues with this because it seemed regardless in which combination you are using the flavours of HttpClient, this will lead to a problem one way or another (github issues). The additional confusion was added by the fact that the .NET tooling had certain bugs in the past that needed workarounds that lead to other problems when those bugs were fixes in later tooling.

Long story short – every time I had to change the csproj file, it broke someone. The latest issue was related to Powershell and .NET 4.7.x (see here).

I once and for all wanted an official statement, how to deal with HttpClient – so I reached out to Immo (@terrajobst) over various channels. Turns out I was not alone with this problem.

Screenshot 2018-05-21 07.43.06

Despite him being on holidays during that time, he gave a really elaborate answer that contains both excellent background information and guidance.

I thought I should copy it here, so it becomes more search engine friendly and hopefully helps out other people that are in the same situation (original thread here).

“Alright, let me try to answer your question. It will probably have more detail than you need/asked for but I might be helpful to start with intention/goals and then the status quo. HttpClient started out as a NuGet package (out-of-band) and was added to the .NET Framework in 4.5 as well (in-box).

With .NET Core/.NET Standard we originally tried to model the .NET platform as a set of packages where being in-box vs. out-of-band no longer mattered. However, this was messier and more complicated than we anticipated.

As a result, we largely abandoned the idea of modeling the .NET platform as a NuGet graph with Core/Standard 2.0.

With .NET Core 2.0 and .NET Standard 2.0 you shouldn’t need to reference the SystemNetHttpClient NuGet package at all. It might get pulled from 1.x dependencies though.

Same goes for .NET Framework: if you target 4.5 and up, you should generally use the in-box version instead of the NuGet package. Again, you might end up pulling it in for .NET Standard 1.x and PCL dependencies, but code written directly against .NET Framework shouldn’t use it.

So why does the package still exist/why do we still update it? Simply because we want to make existing code work that took a dependency on it. However, as you discovered that isn’t smooth sailing on .NET Framework.

The intended model for the legacy package is: if you consume the package from .NET Framework 4.5+, .NET Core 2+, .NET Standard 2+ the package only forwards to the platform provided implementation as opposed to bring it’s own version.

That’s not what actually happens in all cases though: the HTTP Client package will (partially) replace in-box components on .NET Framework which happen to work for some customers and fails for others. Thus, we cannot easily fix the issue now.

On top of that we have the usual binding issues with the .NET Framework so this only really works well if you add binding redirects. Yay!

So, as a library author my recommendation is to avoid taking a dependency on this package and prefer the in-box versions in .NET Framework 4.5, .NET Core 2.0 and .NET Standard 2.0.

Thanks Immo!

Making the IdentityModel Client Libraries HttpClientFactory friendly

$
0
0

IdentityModel has a number of protocol client libraries, e.g. for requesting, refreshing, revoking and introspecting OAuth 2 tokens as well as a client and cache for the OpenID Connect discovery endpoint.

While they work fine, the style around libraries that use HTTP has changed a bit recently, e.g.:

  • the lifetime of the HttpClient is currently managed internally (including IDisposable). In the light of modern APIs like HttpClientFactory, this is an anti-pattern.
  • the main extensibility point is HttpMessageHandler – again the HttpClientFactory promotes a more composable way via DelegatingHandler.

While I could just add more constructor overloads that take an HttpClient, I decided to explore another route (all credits for this idea goes to @randompunter).

I reworked all the clients to be simply extensions methods for HttpClient. This allows you to new up your own client or get one from a factory. This gives you complete control over the lifetime and configuration of the client including handlers, default headers, base address, proxy settings etc. – e.g.:

public async Task<string> NoFactory()
{
    var client = new HttpClient();
 
    var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
    {
        Address = "https://demo.identityserver.io/connect/token",
        ClientId = "client",
        ClientSecret = "secret"
    });
 
    return response.AccessToken ?? response.Error;
}

If you want to throw in the client factory – you can register the client like this:

services.AddHttpClient();

..and use it like this:

public async Task<string> Simple()
{
    var client = HttpClientFactory.CreateClient();
 
    var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
    {
        Address = "https://demo.identityserver.io/connect/token",
        ClientId = "client",
        ClientSecret = "secret"
    });
 
    return response.AccessToken ?? response.Error;
}

HttpClientFactory also supports named clients, which allows configuring certain things upfront, e.g. the base address:

services.AddHttpClient("token_client", 
    client => client.BaseAddress = new Uri("https://demo.identityserver.io/connect/token"));

Which means you don’t need to supply the address per request:

public async Task<string> WithAddress()
{
    var client = HttpClientFactory.CreateClient("token_client");
 
    var response = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
    {
        ClientId = "client",
        ClientSecret = "secret"
    });
 
    return response.AccessToken ?? response.Error;
}

You can also go one step further by creating a typed client, which exactly models the type of OAuth 2 requests you need to make in your application. You can mix that with the ASP.NET Core configuration model as well:

public class TokenClient
{
    public TokenClient(HttpClient client, IOptions<TokenClientOptions> options)
    {
        Client = client;
        Options = options.Value;
    }
 
    public HttpClient Client { get; }
    public TokenClientOptions Options { get; }
 
    public async Task<string> GetToken()
    {
        var response = await Client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
        {
            Address = Options.Address,
            ClientId = Options.ClientId,
            ClientSecret = Options.ClientSecret
        });
 
        return response.AccessToken ?? response.Error;
    }
}

..and register it like this:

services.Configure<TokenClientOptions>(options =>
{
    options.Address = "https://demo.identityserver.io/connect/token";
    options.ClientId = "client";
    options.ClientSecret = "secret";
});
 
services.AddHttpClient<TokenClient>();

…and use it e.g. like this:

public async Task<string> Typed([FromServicesTokenClient tokenClient)
{
    return await tokenClient.GetToken();
}

And one of my favourite features is the nice integration of the Polly library (and handlers in general) to give you extra features like retry logic:

services.AddHttpClient<TokenClient>()
    .AddTransientHttpErrorPolicy(builder => builder.WaitAndRetryAsync(new[]
    {
        TimeSpan.FromSeconds(1),
        TimeSpan.FromSeconds(2),
        TimeSpan.FromSeconds(3)
    }));

This is work in progress right now, but it feels like this is a better abstraction level than the current client implementations. I am planning to release that soon – if you have any feedback, please leave a comment here or open an issue on github. Thanks!

Viewing all 204 articles
Browse latest View live