Pages

Tuesday, 10 February 2015

Debugging a Visual Studio Web Application that uses Windows Authentication

In many companies, web applications are developed that use Windows Authentication for validating users of those applications. These are not just internal facing applications either, as many companies either have customer or extranet systems that use Windows Authentication.

Debugging a web application in Visual Studio that uses Windows Authentication can be problematic without making changes to how it is set-up for debugging, and how your browser is configured.

The Set-Up


In order to debug a web application that uses Windows Authentication, you will firstly need to configure your project to use IIS Express, and this is done by setting properties in the Web section of the project's properties page:


Here you need to select Use IIS Express and click the Configure Virtual Directory button, as shown above.

The next step is to select the UI project for your web application (if there are multiple projects in the solution) in the solution explorer window, and press F4 to bring up the properties window:


In the properties window, ensure that Windows Authentication is set to Enabled.

That's it for the Visual Studio changes required, and these are fairly straightforward. The next step is to configure Internet Explorer, even if IE is not your choice of browser to debug with.

The reason we need to configure IE is to stop the automatic passing of credentials to your web application when being debugged. This is particularly important if you need to log on as different users during the debugging process.

In Internet Explorer:

1. Open the Internet Options Dialog
2. Select the Security tab
3. Select the Local Intranet zone
4. Click on the Sites button

This will display another dialog, and you will need to untick the Automatically detect intranet network box. Once this is unticked, click OK and OK again.


The Gotcha


There is a potential gotcha when debugging an application that uses Windows Authentication, and it's all to do with the User Account Control feature in Windows.

Both IIS and IIS Express use an applicationhost.config file that contains server-wide configuration information. With IIS Express, every user owns their own copy of applicationhost.config, which means the user can add sites, remove sites, configure virtual directories, and so on without special privileges.

IIS Express looks for an applicationhost.config file in the user’s Documents folder (for example, %userprofile%\Documents\IISExpress\config on Windows 7). 

It is important to note that IIS Express runs in the context of the logged in user, and this causes a problem with Windows UAC, as UAC may required you to permit the applicationhost.config file to be opened, even if you are logged on as a user who is a member of the administrators group on your development machine.

If you encounter errors when debugging your application, such as CSS files or JS files not loading and returning an access denied error, you may need to follow these steps:

1. Rename or delete the applicationhost.config file
2. Open up your solution in Visual Studio

This should fire an IIS Express dialog window from within Visual Studio, which will create a new copy of applicationhost.config. Once this is created, you should be able to debug as normal, and have all files loaded correctly in your web application.

To work around the gotcha, you could always turn off UAC, or run Visual Studio as an Administrator, however neither of these are recommended for security!









Friday, 1 March 2013

MVC - SSL, Testing and Production Nuget Package Released

Following on from my earlier post regarding awareness of SSL flag removal that can cause security holes ending up in released code from a development environment, I've released RemoteRequireHttps as a package on Nuget.org

Please download and use as required!


Thursday, 3 January 2013

HTML to PDF Conversion in MVC 4

My preferred tool for dynamically creating PDF documents in a web application is iTextSharp (http://sourceforge.net/projects/itextsharp/) however, I recently had a PDF generation problem to solve where iTextSharp couldn't help.

One thing that seems to be an issue is the generation of PDF documents from HTML, and ensuring CSS used to style the HTML is included in the generation. If the CSS is not included, then the resulting PDF can be greatly different from the source HTML. This can be a problem if for example you need to convert a HTML page returned from a third party's webservice. You have no control over the source HTML, but need the PDF to be styled as per the returned HTML. This situation is commonly encountered with invoice generation, delivery label generation, that sort of thing.

There is an excellent program available that will convert HTML to PDF and preserve all styling, however it is  a command line program - wkhtmltopdf (http://code.google.com/p/wkhtmltopdf/). The solving of my HTML to PDF program was resolved by using this program, but calling it from an MVC 4 Web Application.

This is achieved by using a new instance of the System.Diagnostics.Process class, to create a process calling the wkhtmltopdf application. A URL to the HTML page I want to convert is passed to the wkhtmlpdf application through the arguments set when calling the application. Wrapping this functionality into a method looks like the following:


public static byte[] ConvertHtmlToPdf(string url)
        {

            const string fileName = " - ";
            const string wkhtmlDir = @"C:\Program Files (x86)\wkhtmltopdf\";
            const string wkhtml = @"C:\Program Files (x86)\wkhtmltopdf\wkhtmltopdf.exe";
            var p = new Process
                {
                    StartInfo =
                        {
                            CreateNoWindow = true,
                            RedirectStandardOutput = true,
                            RedirectStandardError = true,
                            RedirectStandardInput = true,
                            UseShellExecute = false,
                            FileName = wkhtml,
                            WorkingDirectory = wkhtmlDir
                        }
                };

            var switches = "";
            switches += "--print-media-type ";
            switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm ";
            switches += "--page-size Letter ";
            p.StartInfo.Arguments = switches + " " + url + " " + fileName;
            p.Start();

            //read output
            var buffer = new byte[32768];
            byte[] file;
            using (var ms = new MemoryStream())
            {
                while (true)
                {
                    var read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);

                    if (read <= 0)
                    {
                        break;
                    }
                    ms.Write(buffer, 0, read);
                }
                file = ms.ToArray();
            }

            // wait or exit
            p.WaitForExit(60000);

            // read the exit code, close process
            var returnCode = p.ExitCode;
            p.Close();
            return returnCode == 0 ? file : null;
        }

You may need to change the location of the program file folder!

I can then call this method using a controller action, passing in a URL:


[HttpPost]
        public ActionResult Index(string htmlUrl)
        {
            
            var pdf = ConvertHtmlToPdf(htmlUrl);
            var ms = new MemoryStream(pdf);
            return new FileStreamResult(ms, "application/pdf");
        }

My full Home Controller looks like:


using System.Diagnostics;
using System.IO;
using System.Web.Mvc;

namespace HtmlToPDF.Controllers
{
    public class HomeController : Controller
    {
        //
        // GET: /Home/

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(string htmlUrl)
        {
            
            var pdf = ConvertHtmlToPdf(htmlUrl);
            var ms = new MemoryStream(pdf);
            return new FileStreamResult(ms, "application/pdf");
        }

        public static byte[] ConvertHtmlToPdf(string url)
        {

            const string fileName = " - ";
            const string wkhtmlDir = @"C:\Program Files (x86)\wkhtmltopdf\";
            const string wkhtml = @"C:\Program Files (x86)\wkhtmltopdf\wkhtmltopdf.exe";
            var p = new Process
                {
                    StartInfo =
                        {
                            CreateNoWindow = true,
                            RedirectStandardOutput = true,
                            RedirectStandardError = true,
                            RedirectStandardInput = true,
                            UseShellExecute = false,
                            FileName = wkhtml,
                            WorkingDirectory = wkhtmlDir
                        }
                };

            var switches = "";
            switches += "--print-media-type ";
            switches += "--margin-top 10mm --margin-bottom 10mm --margin-right 10mm --margin-left 10mm ";
            switches += "--page-size Letter ";
            p.StartInfo.Arguments = switches + " " + url + " " + fileName;
            p.Start();

            //read output
            var buffer = new byte[32768];
            byte[] file;
            using (var ms = new MemoryStream())
            {
                while (true)
                {
                    var read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);

                    if (read <= 0)
                    {
                        break;
                    }
                    ms.Write(buffer, 0, read);
                }
                file = ms.ToArray();
            }

            // wait or exit
            p.WaitForExit(60000);

            // read the exit code, close process
            var returnCode = p.ExitCode;
            p.Close();
            return returnCode == 0 ? file : null;
        }

    }
}


And my Home / Index view looks like:

@{
    ViewBag.Title = "Index";
}

<h2>HTML to PDF Conversion Example</h2>
@using (Html.BeginForm("Index", "Home"))
{
    <div>
        URL to Convert: <input type="text" name="htmlUrl" width="500px" />
    </div>
    <div>
        <input type="submit" value="Convert" /> 
    </div>
}

A sample MVC 4 Web Application can be downloaded from here: http://www.web-architecture.com/Files/HtmlToPdf.zip

Please Note: You will need to install wkhtmltopdf from here: http://code.google.com/p/wkhtmltopdf/ for the sample to work. Don't forget to check the program folder location before running!

Wednesday, 10 October 2012

WebAPI and Subscriber Authentication by Custom HTTP Headers

Recently I've been experimenting with WebAPI, part of the ASP.NET 4 framework. Whilst providing a great way to provide HTTP services, most HTTP services that are provided by companies are on a subscription basis. With this in mind, how can I best secure my HTTP Services for consumption by a paying subscriber?

The easy answer is to pass in an authentication token or credentials with each call to your HTTP service. How you do this is important, particularly for GET methods.

The best solution I've come up with so far is to add a custom authentication header to calls to my HTTP service, and provide a mechanism in my WebAPI MVC application to check the authentication provided in the header of each call.

First, we need to build our WebAPI MVC application! To do this:

Start Visual Studio and select New Project from the Start page. Or, from the File menu, select New and then Project.

In the Templates pane, select Installed Templates and expand the Visual C# node. Under Visual C#, select Web. In the list of project templates, select ASP.NET MVC 4 Web Application. Name the project "NewsSubscriptionService" and click OK.

In the New ASP.NET MVC 4 Project dialog, select Web API and click OK. For the purposes of this example, don't tick the Create a unit test project box.

Created for you as part of this project will be a default API controller, located in the Controllers folder and called ValuesController.cs. You will need to open this file to create our test GET method.
In the ValuesController.cs file, please replace the class section with:
public class ValuesController : ApiController
    {
        // GET api/values
        [ValidateSubscriber]
        public string Get()
        {
            return "Authenticated";
        }
    }
What does this do? Well, it creates a GET method called Get, which returns a string value. You will see from the code that an attribute has been assigned to the method called ValidateSubscriber. This is what you will create next, and does the job of validating the authentication token passed in the HTTP request to our method. The benefit of this approach is you can secure each HTTP method in your application by applying the attribute as required. 


In your solution, create a folder called Authentication and within this folder create a class file called ValidateSubscriber.cs
In the ValidateSubscriber.cs file, replace the ValidateSubscriber class with:
public class ValidateSubscriber : System.Web.Http.AuthorizeAttribute
    {
        public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
        {
            
            if (actionContext.Request.Headers.GetValues("authenticationToken") != null)
            {
                // get value from header
                string authenticationToken = Convert.ToString(actionContext.Request.Headers.GetValues("authenticationToken").FirstOrDefault());
                // This is a hard-coded token, but in reality you would do a check against a subscriber database or something of that ilk.
                if (authenticationToken != "326ED626-0E95-4C75-A456-B42E605FF929")
                {
                    HttpContext.Current.Response.AddHeader("authenticationToken", authenticationToken);
                    HttpContext.Current.Response.AddHeader("AuthenticationStatus", "NotAuthorized");
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden);
                    return;
                }

                HttpContext.Current.Response.AddHeader("authenticationToken", authenticationToken);
                HttpContext.Current.Response.AddHeader("AuthenticationStatus", "Authorized");
                return;
            }
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.ExpectationFailed);
            actionContext.Response.ReasonPhrase = "Please provide valid inputs";
            base.OnAuthorization(actionContext);
        }
    }
You will see from the code that requests to any HTTP service secured by this attribute is intercepted and a custom HTTP header value is looked for called authenticationToken. For this example, a hard-coded Guid value is expected, but in reality you would plumb this in to a database or data store call to check the supplied Guid is valid. Each subscriber should have a different Guid too!


This is all you need to secure your HTTP method!
A quick test is to call this secured method in a HTML page:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript" src="/Scripts/jquery-1.7.1.min.js"></script>
    <script type="text/javascript" src="/Scripts/knockout-2.1.0.js"></script>
    <script type="text/javascript" src="/Scripts/jquery.unobtrusive-ajax.min.js"></script>
    <script type="text/javascript">
        $(function () {
            $(".button").click(function () {
                $.ajax({
                    
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader("authenticationToken", "326ED626-0E95-4C75-A456-B42E605FF929");
                    },
                    url: "/api/Values/Get",
                    type: "GET",
                    statusCode: {
                        200: function (result) {
                            $("#Data").html(result);
                        },
                        401: function (result) {
                            $("#Data").html("Access was denied");
                        }
                    }
                });
            });
        });
    </script>
</head>
<body>
    <div id="Data"></div>
    
    <input type="submit" class="button" value="test" />
    
</body>
</html>

What this does is create a request to our HTTP method and display the string value that is returned by the method. You can test the authentication by changing the Guid value added to the request in the beforeSend function.
An example solution is available for download here

Tuesday, 7 August 2012

MVC - SSL, Testing and Production

I recently had a conversation with a colleague about SSL and how a login page for an MVC application could be forced over SSL, to ensure credentials supplied in the login form are sent over an encrypted channel.

The answer is quite easy: there is a flag that can be set for your controller method called RequireHttps

However..

During my time as a developer, one problem I have seen and witnessed many times is the one of development code being published to a production environment. The consequences of which can range from minor embarrassment (Response.Write() anyone?) to dangerous security holes.

When debugging an application, having the RequireSSL flag set for a controller method can cause all sorts of issues and the temptation is to comment out this flag for debugging. The danger here of course is that this flag is not then un-commented for deploying to a production environment.

There are several ways to ensure this doesn't happen:

1.You could use IIS and a self-signed certificate when testing locally, but this depends on the level of admin access you have to your development PC.
2. Use conditional compilation. For example:


#if !DEBUG
[RequireHttps] 
#endif


You could argue that this leads to messy code, however my main concern is that it doesn't mitigate against a debug version of a DLL making it's way to a product environment. Trust me, this is more common than you might think.

3. Use a derived flag from RequireHttpsAttribute. This last option is by far my favourite, and the safest option.


using System;
using System.Web.Mvc;


    public class RemoteRequireHttps : RequireHttpsAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext == null)
            {
                throw new ArgumentNullException("filterContext");
            }
            if (filterContext.HttpContext != null && filterContext.HttpContext.Request.IsLocal)
            {
                return;
            }
            base.OnAuthorization(filterContext);
        }
    }

When you need to force a controller method over SSL, use the RemoteRequireHttps flag you have created above. When testing locally, the IsLocal flag will prevent SSL being required. When deployed to a production environment, the method will be forced over SSL.

With security, nothing can be left to chance and the mitigation of an accidental release of development code into a production environment needs to be considered at all times. 


Tuesday, 31 July 2012

Entity Framework 4.3 Seeding Data Using int as Identity Column Type

When seeding data using EF 4.3 code first, there is a gotcha when seeding data in identity columns. Let me explain.


In a recent project, I had two tables as part of my model. The first one was called Questions, and the code looked like:

    [Table("Questions", Schema = "Forms")]
    public class Question
    {

        public int QuestionID { get; set; }

        [Required(ErrorMessage = "The question is required")]
        [MaxLength(400)]
        public string QuestionText { get; set; }

        public string Marker { get; set; }

    }

The next table was a relationship table to link Question records to a table with Form records. I had used a linking table as I needed a display order column:

    [Table("FormsQuestions", Schema = "Forms")]
    public class FormsQuestions
    {

            [Key, ForeignKey("Form"), Column(Order = 0)]
            public int FormID { get; set; }
            public virtual Form Form { get; set; }

            [Key, ForeignKey("Question"), Column(Order = 1)]
            public int QuestionID { get; set; }
            public virtual Question Question { get; set; }

            public int DisplaySequence { get; set; }
    }

As you can see, I am using int as my type for the identity column in the Questions table, a fairly common thing. When seeding the data for these two tables, I can set the value of QuestionID in the Questions table..or can I? I ran across this gotcha when I made a mistake with seeding the Question table:

var questions = new List<Question>
            {
                new Question { QuestionID = 1, QuestionText = "Question text one", Marker = "<<one>>"},
                new Question { QuestionID = 3, QuestionText = "Question text two", Marker = "<<two>>"}
            };
            questions.ForEach(s => context.Questions.Add(s));
            context.SaveChanges();

As you can see, the second record should have a QuestionID with the value 2. However, as I was setting the QuestionID column values (or so I thought), I didn't think this would be a problem. There are a lot more questions being seeded in the actual code, however I've trimmed the data for the example in this post.


If I seed the joining table for questions with QuestionIDs 1 and 2 from above, I have something like:

var formsquestions = new List<FormsQuestions>
            {
                new FormsQuestions { QuestionID = 1, FormID = 1, DisplaySequence = 10},
                new FormsQuestions { QuestionID = 3, FormID = 1, DisplaySequence = 20}
            };
            formsquestions.ForEach(s => context.FormsQuestions.Add(s));
            context.SaveChanges();

However, this is going to fail! When inserting the data, values 1 & 2 have been used for the question records, not 1 & 3.


It transpires that whatever value I set for the QuestionID column when seeding the data is ignored and this set value is not inserted with the record. Instead, the next available value is assigned and there doesn't seem to be a command in EF that's equivalent to setting IDENTITY_INSERT <table_name> ON.

Special mention must go to my friend Luke Baughan for putting me in the right direction when I ran across this issue! Please read his blog at: http://ilovedevelopment.blogspot.co.uk/


Friday, 29 June 2012

ASP.NET DropDownList Postback: The jQuery AJAX Replacement for MVC

It was handy in ASP.NET WebForms to have the AutoPostback property and use the SelectedIndexChanged event, to allow other parts of your WebForm to be updated depending on user selection!

With MVC and Razor you can achieve the same functionality, but it has to be done using some other way that fits in with a View. Recently I had a requirement to render a list of checkboxes on a user form; the catch was that the list of checkboxes to be rendered was dependant on a drop down list option the user selected on the same form...

With this senario, we have three main components to any solution:

1. We need to fire a method when the drop down list selection changes.
2. This method needs to take the value of the selected item in the drop down list and return output based on that value.
3. The returned output needs to be rendered in the view.

With the requirement I had, I needed to query a database to return the data needed to render the checkboxes. The solution I used utilised jQuery AJAX and JSON.

I had an MVC Web Application with the latest version of jQuery installed, however I also needed the json2 library from http://www.json.org/ (this can also be downloaded via NuGet).

With these libraries referenced, I needed to wire up a a method to fire on the change event of the dropdownlist using jQuery:


    $(document).ready(function () {

        $('#OrganisationId').change(getReceivers);

    });


My getReceivers method makes an ajax call using JSON data to a controller action in my MVC application:

function getReceivers() {
        $.ajax({
            url: '/Person/ListRecievers',
            data: "{'organisationId':'" + $('#OrganisationId').val() + "', 'personId':'@Model.Person.Id'}",
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            success: function (result) {
                $('#receiversResponse').empty();
                $.each(result, function (person) {
                    var isChecked;
                    if (this.selected) {
                        isChecked = 'checked=\'checked\'';
                    }
                    else {
                        isChecked = '';
                    }
                    $('#receiversResponse').append(
                            '   <label class=\'checkbox\'>'
                            + '     <input type=\'checkbox\' name=\'Receivers\' ' + isChecked + ' value=\'' + this.id + '\'>' + this.name + ' at ' + this.organisationName + ''
                            + ' </label>'
                        );
                });
            },
            error: function () {

            }
        });
    }


URL: the path to my controller action to get the data back for generating the checkbox HTML

Data: this is data I need to pass to my controller action. I have two inputs, organisationId and personId. It is important to remember that these are passed in the ajax call as strings - if the organisationId is a Guid (for example), you will need to convert this to a Guid once it is passed into your controller action

Success: This takes the returned data (in JSON) and iterates through to generate HTML for the checkboxes. The HTML is written to a div I have in my view with an ID of "receiversResponse".


My controller action that is called to return the data I need in JSON is:



        public ActionResult ListRecievers(string organisationId, string personId)
        {
            var selectedOrganisation = db.Organisations.Where(p => p.Id == new Guid(organisationId)).Single();
                var people = db.People.ToList();
                var peopleList = from p in people
                                 select (new {
                                     id = p.Id,
                                     name = p.Name,
                                     organisationName = p.Organisation.Name,
                                     selected = db.People.Include("Receivers").Where(n => n.Id == new Guid(personId) && n.Receivers.Any(r => r.Id == p.Id)).Count() == 1
                                 }
                                     );
                return Json(peopleList.ToList(), JsonRequestBehavior.AllowGet);  
        }



I hope the solution to this problem helps someone else to dynamically display HTML based on user selection of a dropdownlist option value. You don't have to just display checkboxes with this either!