Sunday, June 21, 2015

The Case for MVC (Part 4)

Summary

In this post, I'm going to cover how to handle basic authentication.  I'll show how to create a filter that you can use as an attribute to affix to your Web API method calls.


Basic Authentication

Basic authentication is one of the easiest authentication to implement.  This method is not the most secure method of authenticating and you'll need to use SSL in conjunction with this method.  In a nutshell, basic authentication uses a user name and password appended together with a colon and then using base 64 encoding to avoid passing plain-text to the API.  The whole string is placed in the header of the sending party.  This method is more secure if the password is randomly generated as a token when the user logs in and then the token is thrown away after the user logs out (not to be confused with the users actual password, which is only used at log-in time).

First, the console WebAPIRetreiver will be modified to add the basic authorization string to the header:

// Inside JSONRetriever() method
string userId = "MyUserName";
string storePassword = "RandomLongPassword";
string apiAuthorization = "Basic " + (userId + ":" + storePassword).Base64Encode();

var request = (HttpWebRequest)WebRequest.Create(apiURLLocation);
request.ContentType = "application/json; charset=utf-8";
request.Accept = "application/json";
request.Method = "POST";
request.Headers.Add(HttpRequestHeader.Authorization, apiAuthorization);
request.UserAgent = "ClassAPIRoomRequest";



The method "Base64Encode()" is a string helper that I added in another cs file:

public static class StringHelpers
{
    public static string Base64Encode(this string plainText)
    {
        var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
        return Convert.ToBase64String(plainTextBytes);
    }

    public static string Base64Decode(this string base64EncodedData)
    {
        var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
        return Encoding.UTF8.GetString(base64EncodedBytes);
    }
}


 If you execute the retriever, nothing unusual will happen, since the api is not expecting any authorization.  For that, we'll need to add code to the API (code comments removed in this sample):

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class UniversityBasicAuthentication : AuthorizationFilterAttribute
{
    bool Active = true;

    public UniversityBasicAuthentication()
    {
    }

    public UniversityBasicAuthentication(bool active)
    {
        Active = active;
    }

    public override void OnAuthorization(HttpActionContext actionContext)
    {
        if (Active)
        {
            var identity = ParseAuthorizationHeader(actionContext);
            if (identity == null)
            {
                Challenge(actionContext);
                return;
            }


            if (!OnAuthorizeUser(identity.Name, identity.Password, actionContext))
            {
                Challenge(actionContext);
                return;
            }

            var principal = new GenericPrincipal(identity, null);

            Thread.CurrentPrincipal = principal;

            base.OnAuthorization(actionContext);
        }
    }

    protected virtual bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
            return false;

        VerifyCredentials verifyCredentials = new VerifyCredentials();

        return verifyCredentials.AuthorizeUser(username, password);
    }

    protected virtual BasicAuthenticationIdentity ParseAuthorizationHeader(HttpActionContext actionContext)
    {
        string authHeader = null;
        var auth = actionContext.Request.Headers.Authorization;
        if (auth != null && auth.Scheme == "Basic")
            authHeader = auth.Parameter;

        if (string.IsNullOrEmpty(authHeader))
            return null;

        authHeader = Encoding.Default.GetString(Convert.FromBase64String(authHeader));

        var tokens = authHeader.Split(':');
        if (tokens.Length < 2)
            return null;

        return new BasicAuthenticationIdentity(tokens[0], tokens[1]);
    }

    void Challenge(HttpActionContext actionContext)
    {
        var host = actionContext.Request.RequestUri.DnsSafeHost;
        actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
        actionContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host));
    }
}


You'll need to add the following using statements:

using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Net;
using System.Net.Http;
using System.Security.Principal;
using Authentication;


The "Authentication" dll is a new project added to check the user name and password.  If you download the sample you'll see one class that I added to demonstrate where to verify the user rights.  Here's the class in its entirety:

public class VerifyCredentials
{
    public bool AuthorizeUser(string userId, string password)
    {
        //TODO: replace this hard-coded example with a database lookup
        if (userId == "MyUserName" && password == "RandomLongPassword")
        {
            return true;
        }

        return false;
    }
}


When the API is called, the filter intercepts the header and verifies that it contains a base 64 encoded credential string.  This string is split by the colon and the two sub-strings are passed to the VerifyCredentials class for verification.  The AuthorizeUser() method shown above is an example only.  You'll need to implement a database table with user id's and passwords that have access to your API.  You'll also have to expand the filter to pass a parameter if you want to make your user rights more granular.  You can pass a rights-type string and then implement a database schema where users are assigned rights to one or more rights types.  Then the rights-type can be assigned to each API.  In this sample I'm only showing how to give overall rights to all APIs in your application according to the user's name and password.

I'm planning for at least one more part to this series and then I'm going to wrap up my case for using the MVC design pattern.


Credits and More Information

This demo is based on the code from this blog post: A WebAPI Basic Authentication Authorization Filter
as well as information from this page: Authentication Filters in ASP.NET Web API 2


Where to Get the Code

You can download the code at my GitHub account by clicking here.  Be sure to change the MS SQL server name to match your local SQL server (search for "{YOUR SQL SERVER CONNECTION STRING}" inside the ClassDatabase.cs file).  I have also added the CreateAPIUniversityData.sql file so you can generate the tables inside your SQL server.

Sunday, June 7, 2015

The Case for MVC (Part 3)

Summary

In this post, I'm going to demonstrate how to use an API to separate your business objects from your website front-end.


Diagram

First, I'd like to present a diagram of how the pieces of this project will fit together.  The following is a basic "system" diagram showing how the pieces are connected to each other:


The UniverisityApp project is the business layer or Model part.  This performs all the database operations and connects to the API.  I will be using the project from the previous blog post for this object, so the database is accessed using Entity Framework 6 and all the code is unchanged.  The WebAPI project, as it's name suggests, is the API.  The only purpose is to connect the business logic to an API that communicates with the website front-end using JSON.  Only the Controller part of this MVC project is used here, the model.  The MVCFrontEnd project is just a simple MVC website using Bootstrap, JQuery, and AngularJS.  Technically, only the view part of MVC is used in this project.


The Backend


The backend consists of the Business layer/model, unit tests, a test console, a helper project (just common objects used to access data and run the unit tests), and the Web API project itself.  As I mentioned before, the UniversityApp project is the same application that was used in my previous blog post.  If you’ve spent time examining that portion of this project, then you can ignore it and focus on the API project itself.  The API project is an MVC Web API project created by Visual Studio 2013.  



Setting up IIS


I created a new website for this demo and I also added a DNS entry in the hosts file.  To mimic what I have done, you can add a line to your hosts file (located at C:\windows\system32\drivers\etc directory) like this:


127.0.0.1   www.university.com


Then add a website to your IIS server.  Set the physical path to point to the WebAPI project directory of the WebAPIBlogDemo solution.  Make sure you add permissions to this directory for IUSR and {localPCName}\IIS_IUSRS.  Modify the application pool for the new website and make sure it is a .Net 4 application and integrated.  

You might need to add rights to your MS SQL server if you are using windows authentication.  First, add the user to your security/logins:





Then go to the “User mappings” tab and add db_datareader/db_datawriter/db_owner rights to the APIUniversity database.


Cross Site Scripting Problems

One of the difficult tasks you’ll encounter if you are designing and building APIs is how to handle cross-site scripting.  New browsers have mechanisms in place to prevent javascript from performing a call to another domain.  This can occur if the web page you are accessing uses an AJAX call to an API on a website with a different domain name.  

This project uses Web API 2, which contains facilities for handling CORS.  There are ways to handle this in code, but I chose to use configuration settings in the web.config file to allow cross-site scripting.  If you examine the web.config file of the WebAPI project, you’ll see a section that looks like this:

<httpProtocol>
       <customHeaders>
              <add name="Access-Control-Allow-Origin" value="*"/>
              <add name="Access-Control-Allow-Headers" value="Content-Type, Accept" />
              <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS" />
              <add name="Access-Control-Max-Age" value="1728000" />
       </customHeaders>
</httpProtocol>

This will handle the CORS issue on the website side.  To handle the problem on the API side and allow the API to accept messages from the website side, you’ll need to add an origin header in your ajax call:

headers: { 'Origin': 'www.university.com' },

If you get to a point where you are going to deploy code like this to a production system utilizing multiple servers, you might need to tweak the origin and access control values to make it work right. 


Troubleshooting with Fiddler


I use Fiddler for most of my API troubleshooting involving the communications between one end and the other (you can use your favorite network monitoring tool, like wireshark).  One of the things I like about fiddler is that it can decode JSON outputs into the structures that they represent.  If your API is malformed or you are just outputting text that looks like JSON, fiddler will make it obvious.


Another nice feature of fiddler is that you can see both the message that was sent and the message that was received, as well as the headers and the body content.


Fiddler can be used to pretend it is at one end or the other of the connection.  For instance, you can test your API by setting up a post header and watching the response back.  Here’s an example that will work for the sample code that is used in this blog post:



Troubleshooting with C#

You can setup a quick retriever in a Console application that can be used to test your API.  This can use the HttpWebRsponse call to do a post and read the data returned. The back-end sample code contains a console application setup for this purpose (located inside the testing directory).  Just make it the default startup project and hit F-5.  A console window will pop up and end.  If you want to see what it is doing, but a break-point inside the console application at the point where it is desearializing the results returned (look in the WebAPIRetreiver.cs file).  Then you can hover over the ClassRoomRservationList object and see the result set.


The Front-side Application


The front-side application is also an MVC application.  This application is literally a minimized website.  All of its data is obtained by an AJAX call to the back-end using an API.  Many AJAX calls to multiple APIs can be used together to form a website.  The website itself can be reduced to code necessary to provide a user experience.  APIs can be shared between two or more different websites, designed to provide different user experiences.  The same APIs can also be used by iPhone and Android applications to provide a different view on the same data.  This demonstration application contains a lot of complex details necessary in order to make it all work and it appears to be overkill.  If you’re building a small website with a few pages and you don’t intend to use your APIs for any other purpose, then this may not be the method you would use.  If, however, you are involved in a very large web application and there are many subsystems involved or many different devices that access the same data, then this might be the preferred method.  

Using AngularJS and Bootstrap


I chose to use AngularJS in this demo so I can focus on the connection portion of this example.  AngularJS wires up the JSON packet data to a table that forms the list.  If you examine the index.cshtml view, you’ll see that there is a reference to ng-app and a refernce to ng-controller.  This is the application and controller that is located in the RoomList.js file.  The AngularJS website is full of example code for controlling variables in HTML so I won’t go into great detail on this subject.  The AngularJS processing is performed on the browser-side, so you can connect a JQuery drop-down list to the angular code to dynamically change the data in the table, without submitting the page or refreshing the browser.  One technique I used in the HTML code using AngularJS is I turned a true/false into a Yes/No.  I also reversed the result to switch the room Reserved into a room Available indicator.


Bootstrap is an add-on that allows you to format your website html and css so it can work on multiple devices.  I used bootstrap because it has a lot of formatting features built in that reduces the amount of time I have to spend tweaking css.  If you’ve never used bootstrap before, their documentation is excellent and the framework is great for building websites that might need to be used from a hand-held device as well as a large screen PC.  Bootstrap menus have the ability to fold into drop down menus when the browser is shrunk.  No coding necessary.


Both Angular and Bootstrap require JQuery, so you’ll see js files for JQuery in the sample code.  I have purposely minimized the number of js files that are necessary to make this application run.  My intention is to reduce the amount of clutter that you need to dig through to understand how the application fits together.



API Security


I have not covered the security part of the API in this blog post.  The demonstration programs provided are only to show the concept of how Web APIs can be used to modularize a system.  Before going live, I would recommend performing two tasks: Add a security filter to the API and pass a token in the header, and second, narrow down the acceptable domains that can access your API.  Normally, this can be hard-coded as the domain that is calling, unless you are providing the API for general use.

Also, make sure you are using an SSL connection if you intend to communicate with applications outside your systems firewall (unless you're providing public information this does not need to be secured).


I will be demonstrating how to use the security filter method in a future post.  I’ll show how a user can log into a website, obtain a new encrypted random token and pass it through the header authorization field.


Where to Get the Code

As always, I provide all the code at my GitHub account.  You can click here to download a copy and experiment yourself.  There is a SQL Server script you can used to create the tables and insert test data inside the root directory of the source code (the file is called: CreateAPIUniversityData.sql).