Challenge of Solving an ASP.NET Web API Self-Hosting Problem: No HTTP resource was found that matches the request URI

Couple of weeks ago, one of my former coworkers ran across a very weird problem when he was prototyping on some of his ideas with ASP.NET Web API: No HTTP resource was found that matches the request URI. Let's see what this issue was all about and what is the solution.
2014-04-16 08:28
Tugberk Ugurlu


Couple of weeks ago, one of my former coworkers ran across a very weird problem when he was prototyping on some of his ideas with ASP.NET Web API. He was hosting his ASP.NET Web API application on a console application using the Microsoft.Owin.Hosting components and Microsoft.Owin.Host.HttpListener host. His solution structure was also very simple. He put all of his controllers, message handlers, filters, etc. in one class library and all the hosting logic inside the console application. The below structure was pretty similar to what he did:

Screenshot 2014-04-16 10.36.01

Console application also has very little amount of code:

class Program
{
    static void Main(string[] args)
    {
        using (WebApp.Start("http://localhost:5555/", Start))
        {
            Console.WriteLine("Started listening on localhost:5555");
            Console.ReadLine();
            Console.WriteLine("Shutting down...");
        }
    }

    static void Start(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();
        config.Routes.MapHttpRoute("DefaultHttpRoute", "api/{controller}");
        app.UseWebApi(config);
    }
}

As you can see, it's all done by the book. However, he was constantly getting 404 when he fired up the application and sent a request to /api/cars:

Screenshot 2014-04-16 10.41.50

"No HTTP resource was found that matches the request URI". It's pretty strange. After I looked into the issue for a while, I was able to figure what the problem is:

Screenshot 2014-04-16 10.45.50

Let's make this a little bit interesting and have a look at the modules loaded into the AppDomain :)

Screenshot 2014-04-16 10.49.30

Notice that the WebApiStrangeConsoleHostSample.dll was never loaded into the AppDomain because we never used it even if it's referenced. As ASP.NET Web API uses reflection to determine the controller and the action, it never finds the CarsController. To prove our point here, I'll load the assembly manually:

static void Main(string[] args)
{
    Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, "WebApiStrangeConsoleHostSample.dll"));
    using (WebApp.Start("http://localhost:5555/", Start))
    {
        Console.WriteLine("Started listening on localhost:5555");
        Console.ReadLine();
        Console.WriteLine("Shutting down...");
    }
}

The result is a success:

Screenshot 2014-04-16 10.56.56

However, this is not an ideal solution and I bet that you never run into this issue before. Why? Because, you wise developer keep your hosting agnostic bootstrap code inside the same assembly with you core ASP.NET Web API layer and you call this inside the host application. As soon as you call a method from the core layer assembly, that assembly will be loaded into your AppDomain.

public static class WebApiConfig
{
    public static void Configure(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute("DefaultHttpRoute", "api/{controller}");
    }
}
class Program
{
    static void Main(string[] args)
    {
        using (WebApp.Start("http://localhost:5555/", Start))
        {
            Console.WriteLine("Started listening on localhost:5555");
            Console.ReadLine();
            Console.WriteLine("Shutting down...");
        }
    }

    static void Start(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();
        WebApiConfig.Configure(config);
        app.UseWebApi(config);
    }
}

There is one other potential solution to a problem which is similar to this one. That is to replace the IAssembliesResolver service as Filip did in this post.

Order of Fields Matters on MongoDB Indexes

Order of Fields Matters on MongoDB Indexes. Let's see how with an example.
2014-04-12 18:52
Tugberk Ugurlu


As my MongoDB journey continues, I discover new stuff along the way and one of them is about indexes in MongoDB. Let me try to explain it with a sample.

First, create the below four documents inside our users collection:

db.users.save({ 
	_id: 1, 
	name: "tugberk1", 
	login: [
		{ProviderName: "twitter", ProviderKey: "232"}, 
		{ProviderName: "facebook", ProviderKey: "423"}
	]
});
	
db.users.save({ 
	_id: 2, 
	name: "tugberk23", 
	login: [
		{ProviderName: "twitter", ProviderKey: "3443"}
	]
});

db.users.save({ 
	_id: 3, 
	name: "tugberk4343", 
	login: [
		{ProviderName: "dropbox", ProviderKey: "445345"}
	]
});

db.users.save({ 
	_id: 4, 
	name: "tugberk98", 
	login: [
		{ProviderName: "dropbox", ProviderKey: "3443"}, 
		{ProviderName: "facebook", ProviderKey: "768"}
	]
});

Let’s query the users collection by login.ProviderKey and login.ProviderName:

db.users.find({
	"login.ProviderKey": "232", 
	"login.ProviderName": "twitter"
}).pretty();

image

It found the document we wanted. Let’s see how it performed:

db.users.find({
	"login.ProviderKey": "232", 
	"login.ProviderName": "twitter"
}).explain();

image

Result is actually pretty bad. It scanned all four documents to find the one that we wanted to get. Let’s put an index to ProviderName and ProviderKey fields:

db.users.ensureIndex({
	"login.ProviderName": 1, 
	"login.ProviderKey": 1
});

Now, let’s see how it performs the query:

image

It’s better as it scanned only two documents. However, we had only one matching document for our query. As the chances that the providerKey will be more unique than the ProviderName, I want it to first look for the ProviderKey. To do that, I need to change the index:

db.users.dropIndex({
	"login.ProviderName": 1, 
	"login.ProviderKey": 1 
});
db.users.ensureIndex({ 
	"login.ProviderKey": 1, 
	"login.ProviderName": 1 
});

Let’s now see how it’s trying to find the matching documents:

db.users.find({
	"login.ProviderKey": "232", 
	"login.ProviderName": "twitter"
}).explain();

image

Boom! Only one document was scanned. This shows us how it’s important to put the fields in right order for our queries.

A C# Developer's First Thoughts on MongoDB

After working with RavenDB over the year, I just started looking into MongoDB. I worked with MongoDB a year ago or so in a small project but my knowledge was mostly rusty and I don't want that to happen again :) So, here I'm, documenting what my second thoughts are :)
2014-04-12 14:22
Tugberk Ugurlu


After working with RavenDB over the year, I just started looking into MongoDB. I worked with MongoDB a year ago or so in a small project but my knowledge was mostly rusty and I don't want that to happen again :) So, here I'm, documenting what my second thoughts are :) The TL;DR is that: I'm loving it but the lack of transaction sometimes drifts on a vast dark sea. It's OK through. The advantages generally overcomes this disadvantage.

Loved the Mongo Shell

First thing I liked about MongoDB is its shell (Mongo Shell). 

3d6f5fdd4be53096b6992d5b84b0d7be

It makes it insanely easy for you to get used to MongoDB. After running the mongod.exe, I fired up a command prompt and navigated to mongo.exe directory and entered the mongo shell. Mongo Shell runs pure JavaScript code. That's right! Anything you know about JavaScript is completely valid inside the mongo shell. Let's see a few things that you can do with mongo shell.

You can list the databases on your server: show dbs

2

You can see which database you are connected to: db

3

You can switch to a different database: use <database name here>

4

You can see the collections inside the database you are on: show collections

5

You can save a document inside a collection: db.users.save({ _id: "tugberk", userName: "Tugberk" })

6

You can list the documents inside a collection: db.users.find().pretty()

7

You can run a for loop:

for(var i = 0; i < 10; i++) { 
	db.users.save({ 
		_id: "tugberk" + i.toString(), 
		userName: "Tugberk" + i.toString() 
	}) 
}

8

You can run the code inside a js file

9

saveCount.js contains the following code and it just gets the count of documents inside the users collection and logs it inside another collection:

(function() {
     var myDb = db.getSiblingDB('myDatabase'),
         usersCount = myDb.users.find().count();
         
     myDb.countLogs.save({
          count: usersCount,
          createdOn: new Date()
     });
}());

All of those and more can be done using the mongo shell. It's a full blown MongoDB client and probably the best one. I don't know if it's just me but big missing feature of RavenDB is this type of shell.

Loved the Updates

Update operations in MongoDB is just fabulous. You can construct many kinds of updates, the engine allows you to do this fairly easily. The one I found most useful is the increment updates. Increment updates allows you to increment a field and this operation will be performed concurrency in-mind:

db.books.update(
   { item: "Divine Comedy" },
   {
      $inc: { stock: 5 }
   }
)

The above query will update the stock filed by 5 safely.

Not much Love for the .NET Client

MongoDB has an official .NET client but MongoDB guys decided to call this "C# driver". This is so strange because it works with any other .NET languages as well. I have to say that MongoDB .NET client is not so great in my opinion. After coming from the RavenDB .NET client, using the MongoDB .NET client just feels uncomfortable (However, I’m most certainly sure that I’d love its Node.Js client as it would feel very natural).

First of all, it doesn't support asynchronous requests to MongoDB server. All TCP requests are being done synchronously. Also, there is no embedded server support. RavenDB has this and it makes testing a joy. Let's look at the below code which gets an instance of a database:

MongoClient client = new MongoClient("mongodb://localhost");
MongoServer server = client.GetServer();
MongoDatabase db = server.GetDatabase("mongodemo");

There is too much noise going on here. For example, what is GetServer method there? Instead, I would want to see something like below:

MongoClient client = new MongoClient("mongodb://localhost");
using(var session = client.OpenSession("myDatabase"))
{
     // work with the session here...
}

Looks familiar :) I bet it does! Other than the above issues, creating map/reduce jobs just feels weird as well because MongoDB supports JavaScript to perform map/reduce operations.

var map =
    "function() {" +
    "    for (var key in this) {" +
    "        emit(key, { count : 1 });" +
    "    }" +
    "}";

var reduce =
    "function(key, emits) {" +
    "    total = 0;" +
    "    for (var i in emits) {" +
    "        total += emits[i].count;" +
    "    }" +
    "    return { count : total };" +
    "}";

var mr = collection.MapReduce(map, reduce);
foreach (var document in mr.GetResults()) {
    Console.WriteLine(document.ToJson());
}

The above code is directly taken from the MongoDB documentation.

Explore Yourself

MongoDB has a nice documentation and you can explore it yourself. Besides that, Pluralsight has a pretty nice course on MongoDB: Introduction to MongoDB by Nuri Halperin. Also, don't miss the Ben's post on the comparison of Map-Reduce in MongoDB and RavenDB.

Simple OAuth Server: Implementing a Simple OAuth Server with Katana OAuth Authorization Server Components (Part 1)

In my previous post, I emphasized a few important facts on my journey of building an OAuth authorization server. As great people say: "Talk is cheap. Show me the code." It is exactly what I'm trying to do in this blog post. Also, this post is the first one in the "Simple OAuth Server" series.
2014-04-01 14:30
Tugberk Ugurlu


In my previous post, I emphasized a few important facts on my journey of building an OAuth authorization server. As great people say: "Talk is cheap. Show me the code." It is exactly what I'm trying to do in this blog post. Also, this post is the first one in the "Simple OAuth Server" series.

What are We Trying to Solve Here?

What we want to achieve at the end of the next two blog posts is actually very doable. We want to have a console application where we handle calls to our protected web service endpoints and access them in a delegated manner which means that the client will actually access the resources on behalf of a user (in other words, resource owner). However, we won't be accessing the web service with resource owner's credentials (username and password). Instead, we will use the credentials to obtain an access token through the resource owner credentials grant and use that token to access the resources from that point on. After this blog post, we will expend our needs and build on top of our existing solution with the upcoming posts. That's why this post will be a little bit detailed about how you could set up the project and we will only cover building the OAuth server part.

Building the Application Infrastructure

I'll start by creating the ASP.NET Web API application. As mentioned, our application will evolve over time with the upcoming posts. So, this post will only cover the minimum requirements. So, bare this in mind just in case. I used the provided project templates in Visual Studio 2013 to create the project. For this blog post content, we only need ASP.NET Web API components to create our project.

Screenshot 2014-03-31 11.19.58 

Screenshot 2014-03-31 11.22.19

At the time of writing this post, visual Studio 2013 had the old ASP.NET Web API bits and it's worth updating the package before we continue:

Screenshot 2014-03-31 11.26.09

The OAuth authorization server and the ASP.NET Web API endpoints will be hosted inside the same host in our application here. In your production application, you would probably don't want to do this but for our demo purposes, this will be simpler.

Now we are ready to build on top of the project template. First thing we need is a membership storage system. Nothing would be better than new ASP.NET Identity components. I will use the official Entity Framework port of the ASP.NET Identity for our application here. However, you are free to choose your own data storage engine. Scott Allen has a great blog post about the extensibility of ASP.NET Identity and he listed available open source projects which provide additional storage options for ASP.NET Identity such as AspNet.Identity.RavenDB.

Screenshot 2014-03-31 11.36.12

There are two more packages that you need to install. One of them is Microsoft.AspNet.Identity.Owin. This package provides several useful extensions you will use while working with ASP.NET Identity on top of OWIN. The other one is Microsoft.Owin.Host.SystemWeb package which enables OWIN-based applications to run on IIS using the ASP.NET request pipeline.

The packages we just installed (Microsoft.AspNet.Identity.Owin) also brought down some other packages as its dependencies. One of those dependency packages is Microsoft.Owin.Security.OAuth and this is the core package that includes the components to support any standard OAuth 2.0 authentication workflow. Just wanted to highlight this fact as this is an important part of the project.

I will create the Entity Framework DbContext which will hold membership and OAuth client data. ASP.NET Identity Entity Framework package already has the DbContext implementation for the membership storage and our context class will be derived from that.

public class OAuthDbContext : IdentityDbContext
{
    public OAuthDbContext()
        : base("OAuthDbContext")
    {
    }

    public DbSet<Client> Clients { get; set; }
}

OAuthDbContext class is derived from IdentityDbContext class as you see. Also notice that we have another DbSet property for clients. That will represent the information of the clients. The Client class is a shown below:

public class Client
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string ClientSecretHash { get; set; }
    public OAuthGrant AllowedGrant { get; set; }

    public DateTimeOffset CreatedOn { get; set; }
}

This is the minimum that we need from the client to register in our authorization server. For certain grants, the client doesn't need to have a secret but for "Resource Owner Password Credentials Grant", it's mandatory. The client is also allowed for only one grant, that's all. This is not inside the OAuth 2.0 specification but it's the recommended approach. OAuthGrant is an enum and has the following values:

public enum OAuthGrant
{
    Code = 1,
    Implicit = 2,
    ResourceOwner = 3,
    Client = 4
}

These are all we need for now and we are ready to create the database. I will use Entity Framework Migrations feature to stand up the database and seed some data for demo purposes. As a one time process, I need to enable migrations first by running the "Enable-Migrations" command from the Package Manager Console.

Screenshot 2014-03-31 14.39.34

I will run the another command to add a migration code to reflect my context to a database schema: Add-Migration:

Screenshot 2014-03-31 14.41.44

Enable-Migration command created an internal class called Configuration and it contains a Seed method. I can use that seed method to inject some data during the database creation process:

protected override void Seed(SimpleOAuthSample.Models.OAuthDbContext context)
{
    context.Clients.AddOrUpdate(
        client => client.Name,
        new Client
        {
            Id = "42ff5dad3c274c97a3a7c3d44b67bb42",
            Name = "Demo Resource Owner Password Credentials Grant Client",
            ClientSecretHash = new PasswordHasher().HashPassword("client123456"),
            AllowedGrant = OAuthGrant.ResourceOwner,
            CreatedOn = DateTimeOffset.UtcNow
        });

    context.Users.AddOrUpdate(
        user => user.UserName,
        new IdentityUser("Tugberk")
        {
            Id = Guid.NewGuid().ToString("N"),
            PasswordHash = new PasswordHasher().HashPassword("user123456"),
            SecurityStamp = Guid.NewGuid().ToString(),
            Email = "tugberk@example.com",
            EmailConfirmed = true
        });
}

Now, I will use the Update-Database command to create my database:

Screenshot 2014-03-31 17.04.38

This command just created the database with the seed data on my SQL Express:

image

We will interact with our database mostly through the UserManager class which ASP.NET Identity core library provides. However, we will still use the OAuthDbContext directly. To use those classes efficiently, we need to write some setup code. I'll do this inside the OWIN Startup class:

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.CreatePerOwinContext<OAuthDbContext>(() => new OAuthDbContext());
        app.CreatePerOwinContext<UserManager<IdentityUser>>(CreateManager);
    }

    private static UserManager<IdentityUser> CreateManager(
        IdentityFactoryOptions<UserManager<IdentityUser>> options,
        IOwinContext context)
    {
        var userStore =
            new UserStore<IdentityUser>(context.Get<OAuthDbContext>());

        var manager =
            new UserManager<IdentityUser>(userStore);

        return manager;
    }
}

This is the minimum code that we can write to use the UserManager class inside our OWIN components efficiently. Although I'm not fan of this approach, I chose to do it this way since doing it in my way would complicate the post.

OAuth Authorization Server Application with Katana OAuthAuthorizationServerMiddleware

Here we come to the real meat of the post. I will now set up the OAuth 2.0 token endpoint to support Resource Owner Password Credentials Grant by using the OAuthAuthorizationServerMiddleware which comes with the Microsoft.Owin.Security.OAuth library. There is a shorthand extension method on IAppBuilder to use this middleware: UseOAuthAuthorizationServer. I will use this extension method to configure my OAuth 2.0 endpoints through the Configuration method of my Startup class:

public void Configuration(IAppBuilder app)
{
    //... 
	
    app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
    {
        TokenEndpointPath = new PathString("/oauth/token"),
        Provider = new MyOAuthAuthorizationServerProvider(),
        AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
#if DEBUG
        AllowInsecureHttp = true,
#endif
    });
}

I'm passing an instance of OAuthAuthorizationServerOptions here and setting a few of its properties. Everything is pretty much self explanatory except of Provider property. I'm setting an implementation of IOAuthAuthorizationServerProvider to Provider property to handle the request at the specific places. Fortunately, I didn't have to implement this interface from top to bottom as there is a default implementation of it (OAuthAuthorizationServerProvider) and I just needed to override the methods that I needed.

Spare some time to read the documentation of the OAuthAuthorizationServerProvider's methods. Those are pretty detailed and should give you a great head start.

public class MyOAuthAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
    public override async Task ValidateClientAuthentication(
        OAuthValidateClientAuthenticationContext context)
    {
        string clientId;
        string clientSecret;

        if (context.TryGetBasicCredentials(out clientId, out clientSecret))
        {
            UserManager<IdentityUser> userManager = 
                context.OwinContext.GetUserManager<UserManager<IdentityUser>>();
            OAuthDbContext dbContext = 
                context.OwinContext.Get<OAuthDbContext>();

            try
            {
                Client client = await dbContext
                    .Clients
                    .FirstOrDefaultAsync(clientEntity => clientEntity.Id == clientId);

                if (client != null &&
                    userManager.PasswordHasher.VerifyHashedPassword(
                        client.ClientSecretHash, clientSecret) == PasswordVerificationResult.Success)
                {
                    // Client has been verified.
                    context.OwinContext.Set<Client>("oauth:client", client);
                    context.Validated(clientId);
                }
                else
                {
                    // Client could not be validated.
                    context.SetError("invalid_client", "Client credentials are invalid.");
                    context.Rejected();
                }
            }
            catch
            {
                // Could not get the client through the IClientManager implementation.
                context.SetError("server_error");
                context.Rejected();
            }
        }
        else
        {
            // The client credentials could not be retrieved.
            context.SetError(
                "invalid_client", 
                "Client credentials could not be retrieved through the Authorization header.");

            context.Rejected();
        }
    }

    public override async Task GrantResourceOwnerCredentials(
        OAuthGrantResourceOwnerCredentialsContext context)
    {
        Client client = context.OwinContext.Get<Client>("oauth:client");
        if (client.AllowedGrant == OAuthGrant.ResourceOwner)
        {
            // Client flow matches the requested flow. Continue...
            UserManager<IdentityUser> userManager = 
                context.OwinContext.GetUserManager<UserManager<IdentityUser>>();

            IdentityUser user;
            try
            {
                user = await userManager.FindAsync(context.UserName, context.Password);
            }
            catch
            {
                // Could not retrieve the user.
                context.SetError("server_error");
                context.Rejected();

                // Return here so that we don't process further. Not ideal but needed to be done here.
                return;
            }

            if (user != null)
            {
                try
                {
                    // User is found. Signal this by calling context.Validated
                    ClaimsIdentity identity = await userManager.CreateIdentityAsync(
                        user, 
                        DefaultAuthenticationTypes.ExternalBearer);

                    context.Validated(identity);
                }
                catch
                {
                    // The ClaimsIdentity could not be created by the UserManager.
                    context.SetError("server_error");
                    context.Rejected();
                }
            }
            else
            {
                // The resource owner credentials are invalid or resource owner does not exist.
                context.SetError(
                    "access_denied", 
                    "The resource owner credentials are invalid or resource owner does not exist.");

                context.Rejected();
            }
        }
        else
        {
            // Client is not allowed for the 'Resource Owner Password Credentials Grant'.
            context.SetError(
                "invalid_grant", 
                "Client is not allowed for the 'Resource Owner Password Credentials Grant'");

            context.Rejected();
        }
    }
}

Petty much all the methods you will implement, you will be given a context class and you can signal the validity of the request at any point by calling the Validated and Rejected method with their provided signatures. I implemented two methods above (ValidateClientAuthentication and GrantResourceOwnerCredentials) and I performed Validated and Rejected at several points as I have seen it fit.

An HTTP POST request made to "/oauth/token" endpoint with response_type parameter set to "password" will first arrive at the ValidateClientAuthentication method. This is the place where you should retrieve the client credentials and validate it. According to OAuth 2.0 specification, the client credentials can also be sent as request parameters. However, I don't think this is such a good idea comparing to sending the credentials through basic authentication. That's why I only tried to get it from the "Authorization" header. If the client credentials are valid, the request will continue. If not, it will not process further and the error response will be returned as described inside the OAuth 2.0 specification.

If the client credentials are valid and the "response_type" parameter is set to password, the request will arrive at the GrantResourceOwnerCredentials method. Inside this method there are three things we will essentials do:

  • Validate the client's allowed grant. I's check if it's set to ResourceOwner.
  • If the client's grant type is valid, validate the resource owner credentials.
  • If resource owner credentials are valid, generate a claims identity for the resource owner and pass it to the Validated method.

If all goes as expected, the middleware will issue the access token.

Calling the OAuth Token Endpoint and Getting the Access Token

Let's try out the pieces that we have built. As you see previously, I have seeded a sample client and a sample user when during the database creation process. I will use those information to generate a valid OAuth 2.0 "Resource Owner Password Credentials Grant" request.

Request:

POST http://localhost:53523/oauth/token HTTP/1.1
User-Agent: Fiddler
Content-Type: application/x-www-form-urlencoded
Authorization: Basic NDJmZjVkYWQzYzI3NGM5N2EzYTdjM2Q0NGI2N2JiNDI6Y2xpZW50MTIzNDU2
Host: localhost:53523
Content-Length: 56

grant_type=password&username=Tugberk&password=user123456

Response:

HTTP/1.1 200 OK
Cache-Control: no-cache
Pragma: no-cache
Content-Length: 550
Content-Type: application/json;charset=UTF-8
Expires: -1
Server: Microsoft-IIS/8.0
X-SourceFiles: =?UTF-8?B?RDpcRHJvcGJveFxBcHBzXFNhbXBsZXNcQXNwTmV0SWRlbnRpdHlTYW1wbGVzXFNpbXBsZU9BdXRoU2FtcGxlXFNpbXBsZU9BdXRoU2FtcGxlXG9hdXRoXHRva2Vu?=
X-Powered-By: ASP.NET
Date: Tue, 01 Apr 2014 13:56:32 GMT

{"access_token":"ydbP24rMOATt7TK3dBCjluD2F5LcLkoX8ud39X135x0a1LEvOgsPf0ekm4Lyu2a06Rv_Z105GRZT_NoclgTTf7Slt5_WNfe68zOUq22j6MqW4Fh__Abzjm6I8otDzxvCJpt5d73R-Um6GwTui3LDbcOk5bH2BZuQLTJsNLknbLPu_FdpgkYfBodUoyPiFhv5-gNBEsfp4gCZYfdKtlhaK0wtloZiIzH1_sNPhBt9FavSfThM5BeoWkz8PFxkv_cOsOhOIzK66nSx7B2XL7K9aLqPSJLxus2ud8GBZyteSeFi26L9oX9do7MyCL1nXa8D9DRWfcIXiQi1v19AwyhoupP3L-k89xOK6_NTSzYOVhSMG9Juz8VYHWGkJeYTmekmnVkCvQe7KMQ6PceeUFJnA88TkiHNhai0hV8j012OUxPpUN5zRPJOU81XywSkQ7oKE0UsX3hQamgFrXV9eA-TSwZd4Qr-P9w6a82OM66Te9E","token_type":"bearer","expires_in":1799}

We successfully retrieved the response and it contains the JSON response body which includes the access token in the format described inside the OAuth 2.0 specification.

Summary and What is Next

In this post, we have set up our authorization server and we have a working OAuth 2.0 token endpoint which only supports "Resource Owner Password Credentials Grant" for now. The code is available on GitHub if you are interested in. In the next post, we will create our web service and protect it using our authorization server. We will also see how we can call this web service successfully from a typical .NET application.

Resources

My Baby Steps to OAuth 2.0 Hell (or Should I Call It Heaven)

Securing our HTTP API endpoints are one of the biggest challenges we face when writing so-called modern applications and this is where the OAuth 2.0 enters. In this post, I will highlight the things that I have found vital for the last couple of months when I have been working on an OAuth 2.0 Server implementation in .NET Framework.
2014-03-16 13:05
Tugberk Ugurlu


Securing our HTTP API endpoints are one of the biggest challenges we face when writing so-called modern applications. There are multiple concerns that we need to cover when security is the issue but for those modern applications, the concerns are much bigger because you are no more under your trusted subsystem in your organization domain. Dominick Baier, Mr. Identity, has covered this topic several times:

This is where the OAuth 2.0 enters. OAuth 2.0 is a specification and defines an authorization framework which enables you to give limited access to the third party applications on behalf of the resource owner through one of the defined flows. I’m not going to duplicate the RFC 6749 here but I will highlight the things that I have found vital for the last couple of months when I have been working on an OAuth 2.0 Server implementation in .NET Framework. So, this post is mostly a brain dump.

First of all, there are a few terms that you have to know before you dip your toes in the OAuth water:

  • Resource server: The server that holds the resource.
  • Resource owner: The user which owns the specific resources.
  • Authorization server: A server that authenticates the resource owner and issues access tokens to the client.
  • Client: The application that requests access on a resource on behalf of the resource owner.

There are more terms that you will see when you start reading the specification but the above list should be enough for this blog post. From this point on, I will go through a few bullet points which come in handy as a checklist when designing an OAuth 2.0 authorization server and an HTTP service backed by that authorization server.

Give Scope-based Permissions

The best thing that OAuth specifies is the distinction between the client and the application (resource server) and this gives you a chance to think about your structure again after you read the specification. The application is where you handle your business and expose the certain data. The data exposed here may be tied to a resource owner (for example, user’s hotel bookings) but it doesn’t have to be. That data can be something that your application deals with directly with the user context (for example, the list of hotels).

You should probably see where I’m going with this. Each of your exposed HTTP endpoints need different level of access grant, permission, whatever you want to call it. The OAuth 2.0 helps you handles this as well in a standard way: scopes. A scope defines a level of access that the client acquired. In each OAuth flow, the client specifies which scopes it needs to obtain. Assume that your application is handles data for a travel and tourism company (just like Expedia) and the scopes would be similar to below list:

  • Reading user hotel reservations
  • Changes to user hotel reservations
  • Making hotel reservations on behalf of a user

This list can go on. Handling access to a resource based on scopes in your HTTP service layer gives you a natural way of dealing with the resources. Thinktecture.IdentityModel library has a nice little authorization attribute for your ASP.NET Web API applications: ScopeAuthorizeAttribute. This attribute allows you to protect the each HTTP service endpoint based on required scopes.

Every Endpoint Should Require Authentication

It is certainly a valid situation if you have some endpoints which don’t require resource owner context. For example, a client application may want to get a list of hotels in a region (going with my Expedia sample here again). In that case, resource owner permission is not necessary. So, those endpoints can be exposed publicly without needing any type of authentication and authorization? Absolutely not! In such an environment, don’t ever design your HTTP service in this way. I have found out that requiring an identity in each endpoint of your HTTP service is vital. For cases where you see that resource owner context is not necessary, the client application can obtain the access token through the Client Credentials Grant and hit your HTTP service endpoints with the access token obtained through the client credentials grant.

DO Validate the Redirect URI

This is a must! You should always validate the redirect_uri parameter and try to match it with the client’s pre-registered redirect URIs for Authorization Code Grant and Implicit Grant requests. Unless you do this, your authorization server will be very dangerous! Potentially, you could be ending up redirecting the access token to anywhere.

Only One Grant Type + Client Credentials Grant for a Client

Besides the client credentials grant, only allow one grant type for a client. When you think about it, you should see that a client only needs one type of grant. A server based client application (a web application, for instance) will need Authorization Code Grant. An iPhone application will need Implicit Grant. So, on the way to issuing an access token, validate the grant type as well.

References