Recently, I was involved in a project where we had a mobile application that needed to make calls to a server, and the client wanted to authenticate against their users’ Windows username and password. Given the application and the client’s requirements, both the mobile developer and I agreed that the best (and simplest) solution was a web service using token-based active directory authentication. This blog will review the benefits of a token-based active directory authentication API and the implementation steps.
Benefits of Token-based Active Directory Authentication
Token-based authentication has the benefit of being fairly easy to manage on the mobile side since it only needs to keep a token to send over each HTTP request. And on the server side, with the addition of OWIN (Open Web Interface for .NET), it’s nearly seamless, as demonstrated below.
First off, you’ll need to create an empty ASP.NET project with a reference to Web API:
You’ll also need to add the OWIN authentication package:
Install-Package Microsoft.Owin.Host.SystemWeb -Version 3.0.1 Install-Package Microsoft.Owin.Security.OAuth -Version 3.0.1 Install-Package Microsoft.AspNet.WebApi.Owin -Version 5.2.3
The above references should give you everything you need to offload a lot of the token handling to OWIN. Next, you’ll need to build a simple authentication provider class to handle the actual process of authenticating and generating the token. This involves adding a reference to the System.DirectoryServices.AccountManagement assembly, then adding a Providers folder, and finally, adding the following class:
using System.Threading.Tasks; using Microsoft.Owin.Security.OAuth; using System.DirectoryServices.AccountManagement; using System.Security.Claims; namespace TokenAuthAPI.Providers { public class ADAuthorizationServerProvider : OAuthAuthorizationServerProvider { public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); } public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) { context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "MYDOMAIN")) { // validate the credentials bool isValid = pc.ValidateCredentials(context.UserName, context.Password); if (!isValid) { context.SetError("invalid_grant", "The user name or password is incorrect."); return; } } var identity = new ClaimsIdentity(context.Options.AuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Role, "user")); context.Validated(identity); } } }
That’s the guts of the authentication. However, if you wanted to use some other method, this is where you’d put the code for it. Obviously, if you are using Active Directory, you’ll want to replace the domain name. For the purposes of this example, we only checked whether or not a user exists, but the DirectoryServices classes are pretty well documented elsewhere, just in case you needed/wanted to get any fancier.
You can also alter the kinds of things you can track about your authenticated user by adding claims to your identity (such as a username or security identifier). Just be sure to use them judiciously, because each claim you add increases the size of your token. Also, make sure not to put anything too sensitive in there. Given enough time and resources, any token could be cracked and decrypted.
Next up, we need to configure OWIN to use our provider. To do that, delete the Global.asax (since we’re taking over the API setup) and create a Startup.cs class in the root directory of your project:
using System; using Microsoft.Owin; using Owin; using System.Web.Http; using Microsoft.Owin.Security.OAuth; using TokenAuthAPI.Providers; [assembly: OwinStartup(typeof(TokenAuthAPI.Startup))] namespace TokenAuthAPI { public class Startup { public void Configuration(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); ConfigureOAuth(app); WebApiConfig.Register(config); app.UseWebApi(config); } public void ConfigureOAuth(IAppBuilder app) { OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), Provider = new ADAuthorizationServerProvider() }; // Token Generation app.UseOAuthAuthorizationServer(OAuthServerOptions); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); } } }
Finally, add a simple Web API Controller for testing our authentication:
using System.Web.Http; namespace TokenAuthAPI.Controllers { public class APIController : ApiController { [Authorize(Roles = "user")] [Route("IsTokenAuthorized")] public IHttpActionResult Get() { return Ok("True"); } } }
Did you notice the “Authorize” attribute on the method? You’ll want to add that to any other API methods you add later, since that’s what tells the system it needs to authenticate the token. And, you can see that we’re verifying that the token is granted a claim to the “user” group.
To test all of this, I like to use the Chrome Extension Postman. The way things are set up, the only kind of POST the token issuing part of our web service will accept is a form submission, so we need to set Postman up to use x-www-form-urlencoded:
If everything is set up correctly, you should get an access_token like above, which you can paste into another call to test whether it worked:
Now you can go on to add whatever other methods the API needs to handle, knowing that only authorized users are allowed in.