Transitioning from a Token back to a Windows Identity

Sometimes you are in the situation where you have Windows-based users, but the rest of the application architecture is token-based (e.g. using OpenID Connect or WS-Federation). As long as these users stay in your “token-based world” everything is fine. But if you have impersonate those users to talk to Windows authentication-only service (often that’s SQL Server or a file share), you are in trouble.

Historically this was only possible if you were using Kerberos all the way through – and also only over two hops (e.g. browser to web server – web server impersonating browser user to SQL Server). In you token-based architecture there is no Kerberos.

That’s the reason why Microsoft added extensions to Kerberos (actually already back in Windows Server 2003 days) that make it possible to transition from a non-Windows authentication method to a native Windows token (called S4U – services for user).

In essence there is a way to construct a WindowsIdentity just by passing in a Windows account name and get back a Windows token. When you have a WindowsIdentity, you can call Impersonate and impersonate the user. So really the only thing you need to do, is to be able to map the token user back to a Windows user (e.g. via a UPN claims or similar). Job done !?

Hold on – if that would be possible, wouldn’t that completely subvert the Windows security system? Well it is possible, but there are a number hoops you have to jump through.

This comes up every once in a while, and it is always hard to remember all the details. Since I just did that two weeks ago – here’s a brain dump.

  1. First you have to install the “Claims to Windows Token Service” – that’s a Windows service that runs as SYSTEM and thus has enough privileges to create a Windows token that can be impersonated. This service is hidden behind a Windows Server feature called “Windows Identity Foundation”.
  2. You need to configure the Windows service. Since this is such a highly privileged operation (think about it – this service can create Windows tokens for arbitrary users), you need to specify who is allowed to connect to it. This is done in a .config file in the same directory as the service binaries. Add the Windows account of your application that needs to use the service.
  3. Your application account needs an SPN (use the setspn tool to create one).
  4. You need to configure constrained delegation for the application account. This is done in the “Active Directory Users & Computers” tool. On the property pages – use the Delegation tab to configure this account to be “trusted for delegation to specified services only”. Furthermore set the “Use any authentication protocol” option and configure the list of services to which the Windows user identities can be delegated to.

The last step is a tricky part – you also need to create SPNs for the services you want to connect to. The format of theses SPNs depends on the type of service. This document is very helpful to learn about the format for SQL Server.

If all else fail – I always use Wireshark to trace the Kerberos traffic. This will include the requested SPN and makes it easier to figure out the right format.

If everything is configured correctly – you can use the S4UClient class to get the Windows token for the account you want to impersonate:

var id = S4UClient.UpnLogon(“user@domain”);

The easiest way to get S4UClient is by using Nuget.

Afterwards you can impersonate the Windows identity to make the service request:

using (id.Impersonate())
{
// call SQL Server etc..
}

If you get errors saying something like “NT AUTHORITY\ANONYMOUS” authentication has failed authentication, the delegation configuration is incorrect (most possibly the wrong SPN is configured).

Why is this so complicated?
As I said before, this feature allows constructing a valid Windows identity without having to know the password of the user. IOW – this allows impersonating your CEO and make changes to salary database. That’s why.

So you want to make sure that your application, the application account and the server you run on is properly secured.

HTH

(While writing this I always had to think about these two tweets from Enno: this and this.)

Addition Some readers have pointed out, that the “Claims to Windows Token Service” (or short C2WTS) is not really necessary. You just need to give your application account the “Act as part of the Operating System” privilege, and everything is working fine.

That’s true – but you don’t want to give your application that privilege (that’s in essence SYSTEM) – and that’s the actual reason why the C2WTS service was created in the first place.

Posted in .NET Security, ASP.NET | Leave a comment

Simplified ASP.NET and MVC 6 Security Templates

As mentioned before – the ASP.NET templates never really tried to make to you help  understand the security features.  Instead they crammed ever single feature into a single “sample app” making it really hard to figure out who does what (ASP.NET identity vs middleware vs external authentication vs cookie etc).

This created a lot of confusion – and whenever we taught Katana or ASP.NET 5 security, people had this “wow” effect when theyfinally  see the bits and pieces untangled.

That’s why I published my alternative templates that focus on a single security feature at a time on github (work in progress – feel free to send me PRs)

Cookie-based Authentication

External Authentication (e.g. Google)

External Authentication showing the callback technique to run custom logic between external sign-in and local sign-in

HTH

Posted in .NET Security, ASP.NET | Leave a comment

IdentityModel 1.0.0 released

Part of the ongoing effort to modernize our libraries, I released IdentityModel today.

IdentityModel contains useful helpers, extension methods and constants when working with claims-based identity in general and OAuth 2.0 and OpenID Connect in particular.

See the overview here and nuget here.

Feedback and PRs welcome.

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

The State of Security in ASP.NET 5 and MVC 6: OAuth 2.0, OpenID Connect and IdentityServer

ASP.NET 5 contains a middleware for consuming tokens – but not anymore for producing them. I personally have never been a big fan of the Katana authorization server middleware (see my thoughts here) – and according to this, it seems that the ASP.NET teams sees IdentityServer as the replacement for it going forward.

So let’s have a look at the bits & pieces and how IdentityServer can help in implementing authentication for MVC web apps and APIs.

IdentityServer
IdentityServer is an extensible OAuth 2.0 authorization server and OpenID Connect provider framework. It is different from the old authorization server middleware as it operates on a higher level of abstraction. IdentityServer takes care of all the protocol and data management details while you only need to model your application architecture using clients, users and resources (see the big picture and terminology pages).

IdentityServer is currently available as OWIN middleware only (as opposed to native ASP.NET 5 middleware) – that means it can be used in Katana-based hosts and ASP.NET 5 hosts targeting the “full .NET framework” aka DNX451. It does currently not run on the Core CLR – but we are working on it.

You wire up IdentityServer in ASP.NET 5 using the typical application builder extension method pattern:

public void Configure(IApplicationBuilder app)
{
    var idsrvOptions = new IdentityServerOptions
    {
        Factory = new IdentityServerServiceFactory()
                        .UseInMemoryUsers(Users.Get())
                        .UseInMemoryClients(Clients.Get())
                        .UseInMemoryScopes(Scopes.Get()),
    };

    app.UseIdentityServer(idsrvOptions);
}

For this sample we use in-memory data sources, but you can connect to any data source you like.

The Users class simply defines two test users (Alice and Bob of course) – I won’t bore you with the details. Scopes on the other hand define the resources in your application, e.g. identity resources like email addresses or roles, or resource scopes that represent your APIs:

public static IEnumerable<Scope> Get()
{
    return new[]
    {
        // standard OpenID Connect scopes
        StandardScopes.OpenId,
        StandardScopes.ProfileAlwaysInclude,
        StandardScopes.EmailAlwaysInclude,

        // API – access token will
        // contain roles of user
        new Scope
        {
            Name = “api1”,
            DisplayName = “API 1”,
            Type = ScopeType.Resource,

            Claims = new List<ScopeClaim>
            {
                new ScopeClaim(“role”)
            }
        }
    };
}

Clients on the other hand represent the applications that will request authentication tokens (also called identity tokens) and access tokens.

public static List<Client> Get()
{
    return new List<Client>
    {
        new Client
        {
            ClientName = “Test Client”,
            ClientId = “test”,
            ClientSecrets = new List<Secret>
            {
                new Secret(“secret”.Sha256())
            },

            // server to server communication
            Flow = Flows.ClientCredentials,

            // only allowed to access api1
            AllowedScopes = new List<string>
            {
                “api1”
            }
        },

        new Client
        {
            ClientName = “MVC6 Demo Client”,
            ClientId = “mvc6”,

            // human involved
            Flow = Flows.Implicit,

            RedirectUris = new List<string>
            {
                “
http://localhost:2221/”,
            },

            // access to identity data and api1
            AllowedScopes = new List<string>
            {
                “openid”,
                “email”,
                “profile”,
                “api1”
            }
        }
    };
}

With these definitions in place we can now add an MVC application that uses IdentityServer for authentication, as well as an API that supports token-based access control.

MVC Web Application
ASP.NET 5 includes middleware for OpenID Connect authentication. With this middleware you can use any OpenID Connect compliant provider (see here) to outsource the authentication logic.

Simply add the cookie middleware (for local signin) and the OpenID Connect middleware pointing to our IdentityServer to the pipeline. You need to supply the base URL to IdentityServer (so the middleware can fetch the discovery document), the client ID, scopes, and redirect URI (compare to our client definition we did earlier). The following snippet requests the user’s ID, email and profile claims in addition to an access token that can be used for the “api1” resource.

app.UseCookieAuthentication(options =>
{
    options.AuthenticationScheme = “Cookies”;
    options.AutomaticAuthentication = true;
});

app.UseOpenIdConnectAuthentication(options =>
{
    options.Authority = “
https://localhost:44300″;
    options.ClientId = “mvc6”;
    options.ResponseType = “id_token token”;
    options.Scope = “openid email profile api1”;
    options.RedirectUri = “
http://localhost:2221/”;

    options.SignInScheme = “Cookies”;
    options.AutomaticAuthentication = true;
}

MVC Web API
Building web APIs with MVC that are secured by IdentityServer is equally simple – the ASP.NET 5 OAuth 2.0 middleware supports JWTs out of the box and even understands discovery documents now.

app.UseOAuthBearerAuthentication(options =>
{
    options.Authority = “
https://localhost:44300″;
    options.Audience = “https://localhost:44300/resources”;
    options.AutomaticAuthentication = true;
});

Again Authority points to the base-address of IdentityServer so the middleware can download the metadata and learn about the signing keys.

Since the built-in middleware does not understand the concept of scopes, I had to fix that with this:

app.UseMiddleware<RequiredScopesMiddleware>(
   new List<string> { “api1” });

Expect this be improved in future versions.

API Client
Tokens can be also requested programmatically – e.g. for server-to-server communication scenarios. Our IdentityModel library has a TokenClient helper class which makes that very easy:

async Task<TokenResponse> GetTokenAsync()
{
    var client = new TokenClient(
        “
https://localhost:44300/connect/token”,
        “test”,
        “secret”);

    return await client.RequestClientCredentialsAsync(“api1”);
}

…and using the token:

var client = new HttpClient();
client.SetBearerToken(response.AccessToken);

var result = await client.GetAsync(“http://localhost:2025/claims&#8221;);

The full source code can be found here.

Summary
IdentityServer can be a replacement for the Katana authorization server middleware – but as I said it is a different mindset, since IdentityServer is not protocol oriented – but rather focusing on your application architecture. I should mention that there is actually a middleware for ASP.NET 5 that mimics the Katana approach – you can find it here.

In the end it is all about personal preference, and most importantly how comfortable you are with the low level details of the protocols.

There are actually much more samples on how to use IdentityServer in the samples repo. Give it a try.

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

The State of Security in ASP.NET 5 and MVC 6: Claims & Authentication

Disclaimer: Microsoft announced the roadmap for ASP.NET 5 yesterday – the current release date of the final version is Q1 2016. Some details of the features and APIs I mention will change between now and then. This post is about beta 5.

Claims
I started talking about claims-based identity back in 2005. That was the time when Microsoft introduced a new assembly to the .NET Framework called System.IdentityModel. This assembly contained the first attempt of introducing claims to .NET, but it was only used by WCF and was a bit over-engineered (go figure). The claims model was subsequently re-worked by the WIF guys a couple of years later (kudos!) and then re-integrated into .NET with version 4.5.

Starting with .NET 4.5, every built-in identity/principal implementation was based on claims, essentially replacing the 12+ years old antiquated IIdentity/IPrincipal interfaces. Katana – but more importantly ASP.NET 5 is the first framework that now uses ClaimsPrincipal and ClaimsIdentity as first class citizens – identities are now always based on claims – and finally – no more down-casting!

HttpContext.User and Controller.User are now ClaimsPrincipals – and writing the following code feels as natural as it should be:

var email = User.FindFirst(“email”);

This might not seem like a big deal – but given that it took almost ten years to get there, shows just how slow things are moving sometimes. I also had to take part in a number of discussions with people at Microsoft over the years to convince them that this is actually the right thing to do…

Authentication API
Another thing that ASP.NET was missing is a uniform authentication API – this was fixed in Katana via the IAuthenticationManager and was pretty much identically brought over to ASP.NET 5.

AuthenticationManager hangs off the HttpContext and is a uniform APIs over the various authentication middleware that do the actual grunt work. The major APIs are:

  • SignIn/SignOut
    Instructs a middleware to do a signin/signout gesture
  • Challenge
    Instructs a middleware to trigger some external authentication handshake (this is further abstracted by the new ChallengeResult in MVC 6)
  • Authenticate
    Triggers validation of an incoming credential and conversion to claims
  • GetAuthenticationSchemes
    Enumerates the registered authentication middleware, e.g. for populating a login UI dynamically

Authentication Middleware
The actual authentication mechanisms and protocols are implemented as middleware. If you are coming from Katana then this is a no brainer. If your background is ASP.NET.OLD think of middleware as HTTP modules – just more flexible and lightweight.

For web UIs the following middleware is included:

  • Cookie-based authentication (as a replacement for good old forms authentication or the session authentication module from WIF times)
  • Google, Twitter, Facebook and Microsoft Account
  • OpenID Connect

WS-Federation is missing right now. It is also worth mentioning that there is now a generic middleware for OAuth2-style authentication (sigh). This will make it easier to write middleware for the various OAuth2 dialects without having to duplicate all the boilerplate code and will make the life of these guys much easier.

Wiring up the cookie middleware looks like this:

app.UseCookieAuthentication(options =>
{
    options.LoginPath = new PathString(“/account/login”);
    options.AutomaticAuthentication = true;
    options.AuthenticationScheme = “Cookies”;               
});

The coding style is a little different – instead of passing in an options instance, you now use an Action<Option>. AuthenticationType has been renamed to AuthenticationScheme (and the weird re-purposing of IIdentity.AuthenticationType is gone for good). All authentication middleware is now passive – setting them to active means setting AutomaticAuthentication to true.

For signing in a user, you create the necessary claims and wrap them in a ClaimsPrincipal. Then you call SignIn to instruct the cookie middleware to set the cookie.

var claims = new List<Claim>
{
    new Claim(“sub”, model.UserName),
    new Claim(“name”, “bob”),
    new Claim(“email”, “bob@smith.com”)
};

var id = new ClaimsIdentity(claims, “local”, “name”, “role”);
Context.Authentication.SignIn(“Cookies”, new ClaimsPrincipal(id));

Google authentication as an example looks like this:

app.UseGoogleAuthentication(options =>
{
    options.ClientId = “xxx”;
    options.ClientSecret = “yyy”;

    options.AuthenticationScheme = “Google”;
    options.SignInScheme = “Cookies”;
});

The external authentication middleware implements the authentication protocol only – and when done – hands over to the middleware that does the local sign-in. That’s typically the cookie middleware. For this purpose you set the SignInScheme to the name of the middleware that should take over (this has been renamed from SignInAsAuthenticationType – again clearly an improvement).

Also the pattern of having more than one cookie middleware to be able to inspect claims from external authentication systems before turning them into a trusted cookie still exists. That’s probably a separate post.

For web APIs there is only one relevant middleware – consuming bearer tokens. This middleware has support for JWTs out of the box and is extensible to use different token types and different strategies to convert the tokens to claims. One notable new feature is support for OpenID Connect metadata. That means if your OAuth2 authorization server also happens to be an OpenID Connect provider with support for a discovery document (e.g. IdentityServer or Azure Active Directory) the middleware can auto-configure the issuer name and signing keys.

One thing that is “missing” when coming from Katana, is the OAuth2 authorization server middleware. There are currently no plans to bring that forward. IdentityServer can be a replacement for that. I will dedicate a separate blog post to that topic.

Summary
If you are coming from Katana, this all does not look terribly new to you. AuthenticationManager and authentication middleware works almost identical. Learning that, was no waste of time.

If you are coming from plain ASP.NET (and maybe even WIF or DotNetOpenAuth) this all works radically different under the covers and is really only “conceptually compatible”. In that case you have quite a lot of new tech to learn to make the jump to ASP.NET 5.

Unfortunately (as always) the ASP.NET templates are not very helpful in learning the new features. You either get an empty one, or the full-blown-all-bells-and-whistles-complexity-hidden-by-extensions-method-over-more-abstractions version of that. Therefore I created the (almost) simplest possible cookie-based starter template here. More to follow.

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

The State of Security in ASP.NET 5 and MVC 6

We’ve been closely following ASP.NET 5 and MVC 6 since the days it was presented behind closed doors, through the “vNext” and “Project K” phase up to recent beta builds.

I personally monitored all developments in the security space in particular and was even involved in one or the other decision making process – particularly around authorization which makes me also a little bit proud.

In preparation for the planned ASP.NET and MVC 6 security course for PluralSight, I always maintained a (more or less structured) list of changes and new features.

Tomorrow will be the release of Visual Studio 2015, which does NOT include the final release of ASP.NET 5. Instead we are between Beta 5 and 6 right now and the rough feature set has more or less been decided on. That’s why I think that now is a good time to do a couple of overview posts on what’s new.

Many details are still very much in flux and the best way to keep up with that is to subscribe to the various security related repos on github. Many things are not set in stone yet, so this is also an opportunity to take part in the discussion which I would encourage you to do.

The planned feature posts are:

Since training is very much about the details, we are holding off right now with recording any content until the code has been locked down for “v1”. So stay tuned.

The first public appearance of our updated “identity & access control” training for ASP.NET will be at NDC in London in January 2016.

Update: The final release of ASP.NET 5 is currently scheduled for Q1 2016 (https://github.com/aspnet/Home/wiki/Roadmap)

Posted in .NET Security, ASP.NET, Conferences & Training, IdentityServer, WebAPI | Leave a comment

Federated Logout with the Katana WS-Federation Middleware

For some reason the Katana WS-Fed middleware does not seem to implement signout cleanup.

This means that your application will ignore federated signout callbacks from the STS which will result in resources like logon cookies not being cleaned up properly.

Here’s a quick fix for your pipeline:

app.Use(async (ctx, next) =>
{
   
var
qs = ctx.Request.Query;
   
var wa = qs.Get("wa"
);

   
if (wa != null
)
    {
       
if (wa == "wsignoutcleanup1.0"
)
        {
           
// clean up resources, e.g. the logon cookie

            ctx.Authentication.SignOut(
"Cookies"
);
        }
    }

   
await next();
});

HTH

Posted in .NET Security, ASP.NET, Katana, OWIN | Leave a comment