ASP.NET Core hosting (revisited) – Part I

Last year I did a series of posts following ASP.NET Core execution in depth. At that time the framework was still named ASP.NET 5, I was using betas 5/6 and DNX (.NET Execution Environment) was still around. A lot has changed since then, namely the usage of .NET CLI instead of DNX. Today I’ll revisit last year’s post about ASP.NET hosting.

Prior to RC2, an ASP.NET Core application was a class library. DNX – the execution environment at that time – was responsible for providing support for project.json, loading assemblies and invoking the ASP.NET hosting libraries, which in turn would find a Startup class to configure and start the application. Just for completeness, we used to have something like this on the commands section of project.json:

"web": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.WebListener --server.urls http://localhost:5000"

With the release of RC2, DNX and the related tools were replaced by the .NET CLI and, as such, ASP.NET Core applications became regular console applications. Instead of using the hosting libraries as the entry point and have them discover our application, we now call into ASP.NET libraries from our Main method (the common entry point) to configure the web application and fire up ASP.NET. Here’s an example of such a Main method:

public static void Main(string[] args)
        {
            var host = new WebHostBuilder()
                .UseKestrel()
                .UseStartup<Startup>()
                .Build();
            host.Run();
        }

The code is straightforward: we configure the server (Kestrel, in this case) and the Startup class (this now has to be done explicitly) to build the web host. Then we run it, blocking the main thread until the application shuts down. For the remainder of this post (and the following) I’ll go through the ASP.NET code to see what’s happening under the covers when we configure and run the web host.

Before moving further it’s worth doing a quick recap on some terminology:

  • RequestDelegate – represents the handling of a request. It’s a function that gets a context and returns a Task that completes when the request has been processed. This simple delegate actually represents the whole application.
    public delegate Task RequestDelegate(HttpContext context);
  • Middleware – a component that participates on request processing by inspecting, routing, or modifying request and/or response messages. A simplistic view of a middleware is a Func<RequestDelegate, RequestDelegate>, i.e. a means of composing around a given request delegate. This composition approach replaces the event-driven model found on previous versions of ASP.NET.
  • Startup class – the class where you configure the services and middlewares of your application. The configuration methods are discovered by convention, as described on ASP.NET documentation. You can also check this post for a more detailed explanation.

The interface of WebHostBuilder is rather simple, as illustrated below. Configuring the builder is mostly about configuring services for the DI infrastructure.

    public interface IWebHostBuilder
    {
        IWebHost Build();
        IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices);
        IWebHostBuilder UseSetting(string key, string value);
        // ...
    }
    public class WebHostBuilder : IWebHostBuilder 
    {
        private readonly List<Action<IServiceCollection>> _configureServicesDelegates;

        public IWebHostBuilder ConfigureServices(Action<IServiceCollection> configureServices)
        {
          _configureServicesDelegates.Add(configureServices);
          return this;
        }
        // ...
    }

Most of the builder configurations done on the Main method are exposed via extension methods on the corresponding packages. For instance, the UseKestrel method is found on the Kestrel server package and looks like this:

public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder)
{
    return hostBuilder.ConfigureServices(services =>
    {
        services.AddTransient<IConfigureOptions<KestrelServerOptions>, KestrelServerOptionsSetup>();
        services.AddSingleton<IServer, KestrelServer>();
    });
}

Notice the registration of IServer. This is (as expected) a required service that represents the server and will be used later on to link incoming requests to the application. If we were to use another server implementation, it would likely register its own IServer class via a similar extension method.

The WebHostBuilder.Build method is where everything is assembled. It has two main responsibilities:

  1. Configure and register the services needed for hosting.
  2. Create and initialize the WebHost.
public IWebHost Build()
{
    var hostingServices = BuildHostingServices();
    var hostingContainer = hostingServices.BuildServiceProvider();
    var host = new WebHost(hostingServices, hostingContainer, _options, _config);
    host.Initialize();
    return host;
}

The BuildHostingServices method is where hosting-related configuration takes place. First, the IHostingEnvironment is configured. This service can be used from this moment on to get information about the physical environment where the application is hosted, such as the root path for static content.

_options = new WebHostOptions(_config);

var appEnvironment = PlatformServices.Default.Application;
var contentRootPath = ResolveContentRootPath(_options.ContentRootPath, appEnvironment.ApplicationBasePath);
var applicationName = _options.ApplicationName ?? appEnvironment.ApplicationName;

_hostingEnvironment.Initialize(applicationName, contentRootPath, _options);

var services = new ServiceCollection(); // (1)
services.AddSingleton(_hostingEnvironment);

Note the creation of the service collection (1) that is used to create the base DI service provider for the WebHost (on the Build method shown before).

The next relevant action is the registration of some important built-in services that will be used for application configuration and request processing. We’ll go through the usage of these services later on.

services.AddLogging();
services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
services.AddTransient<IHttpContextFactory, HttpContextFactory>();
services.AddOptions();
  • IApplicationBuilderFactory – allows create of the application builder that is used by the Startup class to configure middlewares.
  • IHttpContextFactory – create the HttpContext for an incoming request.
  • AddOptions – adds support for the options configuration pattern.

The last step is to execute the service configuration delegates that were externally registered in the WebHostBuilder. This is the case of the delegates registered by UseKestrel and UseStartup methods, as shown before.

private readonly List<Action<IServiceCollection>> _configureServicesDelegates;
// ...
foreach (var configureServices in _configureServicesDelegates)
{
    configureServices(services);
}

At this point all the base configurations and services required by the host are in place. The Build method can now create a WebHost instance and initialize it. This where all the application-specific configurations are triggered and it will be the subject of my next post. Stay tuned!

OAuth 2.0 library for .NET native apps

A few months ago I wrote about OAuth 2.0 for native apps, mentioning App Auth, an OAuth 2.0 client library for native Android and iOS applications. Recently I discovered that a similar library has been release for .NET! It is a PCL (Xamarin included) and it features the same security concerns as App Auth, following the IETF recommendations for native OAuth 2.0 clients. In addition, it also supports OpenId Connect features, such as validating identity  tokens. Very nice!

OAuth 2.0 mind map

Since the publication of The OAuth 2.0 Authorization Framework (RFC 6749) in 2012, both the IETF OAuth work group and the OpenID Foundation have released many other RFCs that extend/complement the base framework and the OAuth 2.0 ecosystem. I found this variety a bit confusing, so I figured I’d do a mind map and short summary of the specs for future reference. Here it goes.

oauth-mindmap

RFC 6749 – The OAuth 2.0 Authorization Framework

This is the core OAuth 2.0 standard. It defines the different roles (resource owner, client, authorization server, etc.) and the main authorization endpoints, flows and artifacts. Extensibility rules are also defined in this document. The “framework” on the RFC title is important: there are multiple authorization scenarios and a lot of aspects are left unspecified, which somehow justifies all the satellite specs. This was also the reason for heavy criticism on the early days of OAuth 2.0.

Tokens

RFC 6750 – Bearer Token Usage

The main spec doesn’t define the format of access tokens nor how they should be used to access protected resources. The most commonly deployed tokens, however, are bearer tokens. As the name implies, the possession of such tokens is sufficient to access the associated resources. RFC 6750 defines how bearer tokens should be sent to resource servers.

RFC 7009 – Token Revocation

Authorization servers usually allow resource owners to revoke previously granted authorizations. This RFC proposes an additional endpoint for authorization servers that clients can use to invalidate tokens they no longer need.

RFC 7662 – Token Introspection

The main spec doesn’t cover the actual usage of access tokens nor the procedure that resource servers should apply to verify them. More than verifying if a token is valid, resource servers are likely to need the associated metadata (e.g. the granted scopes) for authorization decisions. In a common deployment scenario, both authorization and resource servers are under the same domain, hence being able to somehow share the token validation logic. For more loose scenarios, RFC 7662 defines a token introspection endpoint that resource servers may use to query the authorization server to obtain the status and metadata of a token that is presented by an OAuth 2.0 client.

RFC 7519 – JSON Web Token (JWT)

JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object.” JWTs can be used with JSON Web Signature (JWS) and JSON Web Encryption (JWE), enabling the claims to be integrity protected and/or encrypted. The spec includes a set of predefined claims – such as the issuer, subject and audience identifiers – as well as processing rules. JWTs can be used as self-contained access/refresh tokens.

More on obtaining authorization grants

RFC 7636 – Proof Key for Code Exchange by OAuth Public Clients (PKCE)

Clients that can’t keep their credentials private are called public clients. This is the case of most native applications. As such, the authorization code grant cannot be securely used by this type of clients. This spec defines a proof of possession extension that makes the code grant usable by these clients. Read this post for more details on PKCE and the underlying vulnerability.

Device Flow (draft)

Defines an authorization flow for clients executing on devices with limited input and/or browsing capabilities (e.g. TVs, STBs). It is based on out-of-band codes that the user provides to the authorization server using another device with better user-agent capabilities (e.g. a tablet).

Multiple Response Type Encoding Practices

Defines rules to encode authorization response parameters when multiple response types are used. Also defines response mode, a new authorization request parameter that allows the client to specify how the response should be delivered (query-string, fragment, etc.).

Form Post Response Mode

Based on the previous spec, this document defines a new response mode on which the authorization response is returned to the client via a auto-submit HTML form using an HTTP POST. This is different from the redirects (HTTP GET) defined on the core OAuth spec, with the advantage of reducing the likelihood of codes and tokens being logged as part of URLs.

Management

RFC 7591 – Dynamic Client Registration Protocol

Clients are usually registered by their developers in the intended authorization servers. This spec defines a means of dynamically registering clients Registration requests include items such as redirect URIs, intended grant types and web page URLs, and the response contains the assigned client ID and secret. There’s also a complementary experimental spec for subsequent changes to the client metadata.

Authorization Server Discovery Metadata (draft)

This draft defines the format of a JSON document that a client can use to obtain the different endpoints and capabilities of an authorization server. This metadata includes items such as the URL of the token endpoint and the supported response types. Besides this draft there’s also the OpenID Connect version, which is final and actually appeared first. The draft is compatible with the later.

Other types of authorization grants

RFC 7521 – Assertion Framework for Client Authentication and Authorization Grants

Defines mechanisms for OAuth 2.0 to work with other identity systems using assertions. The spec defines processing rules and message flows for using assertion-based client authentication and authorization grants when interacting with the token endpoint. This means that authorization grants are obtained by other means, instead of using the common OAuth flows. There’s a profile using SAML 2.0 assertions and another using JWT assertions.

Informational & best practices

RFC 6819 – Threat Model and Security Considerations

Defines a set of threats to the authorization flows and the corresponding countermeasures. Since OAuth 2.0 doesn’t include any “message security” on the base flows, being aware of those security aspects is very important to ensure the protocols’ security.

OAuth 2.0 for Native Apps (draft)

Native clients – such as mobile applications – can’t keep their credentials private. This spec defines a set of best practices for implementing such clients, namely the usage of the device’s native browser for authorization flows. I’ve discussed this subject in detail on a previous post.

Authentication

OpenID Connect Core 1.0

OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol“. Actually it’s not that simple; it’s a whole new subject, but this post wouldn’t be complete without mentioning it. The spec defines extensions to OAuth 2.0 that enable clients to verify the identity of the user that authenticated on the authorization server.

Cake build example

Recently I’ve been experimenting with Cake for .NET builds. It is a build automation tool with a C# DSL, which per se is pretty nice! Besides that, I found the following nice aspects:

  • Expressive and comprehensive API which supports most of the common tasks on this type of builds.
  • Lots of add-ins for additional tasks.
  • Cross-platform.
  • Seems easy to extend.

I’ve put together an example project using Cake, which includes compilation via MSBuild, StyleCop analysis, test execution, creation of a NuGet package and publication of a web application to the file system,

Google’s Site Reliability Engineering

DevOps & Co

Here’s How Google Makes Sure It (Almost) Never Goes Down

OAuth 2.0 for native apps

When a native application needs access to a user’s account on a given online service, there are two main alternatives: 1) rely on accounts previously configured on the device; 2) interact directly with the online service to get the needed authorization. The former approach builds directly on features exposed by the OS and usually requires the app to have specific permissions. This is the case of Android’s AccountManager. The latter usually relies on some authorization protocol supported by the target service, which nowadays is likely to be OAuth 2.0. In this case the application will require some sort of user-agent to perform the authorization flow.

Google’s Identity team recently open sourced AppAuth for Android and iOS, a client library that enables native applications to perform OAuth 2.0 authorization flows in a secure and usable manner. AppAuth follows the recent IETF draft of best practices for authorization flows on native applications.

The OAuth 2.0 RFC already includes a section around native applications, reminding that these clients can’t keep their credentials confidential and providing two main approaches to perform the authorization flow: embedded user-agents and external user-agents (e.g. system default browser).

Embedded user-agents are usually a native component that the application directly communicates with. This is the case of WebViews in Android. Embedded user-agents are a very common option because they don’t require the user to switch context and there wasn’t a better approach to overcome this aspect (not anymore, as we’ll see later on). However, this approach has many usability and security drawbacks. Regarding usability, embedded user agents don’t share the authentication state with other apps or the system browser, meaning the user might have to re-authenticate. On the other hand, users are authenticating on an unidentified window without the usual browser features, which makes it harder for them to know if they are singing in to the legitimate site and educates them in the wrong way. Worst than that, the host application has access to the whole user-agent context, such as cookies and key strokes. Finally, since embedded user-agents are native components they might not be so easily updated as an external user-agent, which is likely to be just another application on the OS.

When using external user-agents, in order to perform an OAuth authorization request, an application needs to somehow activate the external browser. Most environments provide URI-based inter-app communication (e.g. Intent on Android) which fit OAuth 2.0, since authorization requests are HTTP URIs. In this case, the authorization flow is executed in the browser, which is registered on the OS as knowing how to handle HTTP URIs. The authentication state is shared, avoiding re-authentications, and the user faces a familiar experience and may rely on browser features for authentication (stored credentials, extensions, etc). In order to get the authorization response, the most common approach is to use custom schemes on OAuth redirect URIs. All the major platforms have support for binding custom URI schemes to applications. When the browser (on any other application) attempts to follow such an URI, the corresponding application is activated. This is how the last redirect on the authorization flow is delivered to the initiator.

The IETF draft of best practices for authorization flows on native applications adds some restrictions and recommendations for this scenario:

  • Authorization flows should be delegated to external user-agents via URI-based communication. Embedded user-agents are not recommended.
  • Whenever possible in-app browser tabs should be used. In-app browser tabs are provided by a browser in the system but displayed within the application with limited navigation capabilities. However, they cannot be directly accessed by the application and they share the browser’s authentication state and security features. On iOS this feature is available via SFSafariViewController and iOS 9+. On Android, the feature is available via Chrome Custom Tabs since Chrome 45 (Sep 2015) from Jellybean on. Both versions support some customization, such as changing the navigation bar color, adding custom share buttons and going back to the application in one tap..Note that this feature can be supported by other browsers installed on the devices. Also note that this feature is not restricted to authorization flows. In-app tabs are already used by some applications, such as Facebook and Twitter, to display generic external web content.
  • Applications should use custom URI schemes that are globally unique for their redirect URIs. The recommend strategy is using the reverse domain name pattern applied to a domain under the application publisher control.
  • Applications must use Proof Key for Code Exchange by OAuth Public Clients (PKCE) when using custom URI schemes. Since multiple applications might register the same custom scheme, the OS could activate a malicious application to receive the authorization response. PKCE “is a Proof of Possession extension to OAuth 2.0 that protects the code grant from being used if it is intercepted“. Read this post for more details on PKCE and the underlying vulnerability (applies to public clients, which is the case of most native applications).

The recently open sourced AppAuth library for Android and iOS was implemented with all these considerations in mind, so I think it’s worth mentioning. In addition, it supports custom extensions on OAuth requests and includes fallback to the default browser if a browser supporting custom tabs is not found. Seems to do all the plumbing to support a uniform and secure authorization experience.