Sunday, August 29, 2010

MSBuild

Over at World of VS there's a scaled out online poll taking place about what extensions would be useful additions to Visual Studio. There are a couple I really like and I've voted accordingly. My own suggestion is something I personally would find extremely useful and that is being able to manipulate MSBuild files in Visual Studio with full intellisense, including community MSBuild tasks. I've been a little underwhelmed by the love and I guess the question I have is what level of automation do Microsoft developers use in their projects and what tool is used if it isn't MSBuild?

To me automation is a no-brainer - being able to kick off builds in Team Build that not only compile the source but also produce installers for my target deployment environments, e.g. test, staging, and production. That means that whenever a developer checks in some source code we end up with a consistent set of installers built using a known set of referenced assemblies. At the end of a sprint when you really want to demonstrate the work you've completed do you really want to waste effort figuring out why the build that was generated on one developer's machine doesn't install when it installed perfectly from a different machine's build last week?

I also use MSBuild to update version numbers in a dozen configuration files, a job that previously was done by hand and resulted in many wasted hours and broken builds. I use MSBuild to precompile a website and copy the output to my local test site, including making the necessary modifications to config files for connection strings. I realise that Visual Studio is now far better at creating config files that match the target environment but just having that ability to press a button and know that if something is broken it has everything to do with some bad code I wrote and not the installer.

The lack of support in Visual Studio for MSBuild, apart from the standard XML editor, is a hole that needs filling. I know enough about MSBuild to be able to get it to do what I need but while it is a core tool I rely on I don't use it often enough to be able to write out build targets without having to reach for Stack Overflow or Google. Once my build file is done I rarely have to revisit it which means my aging neurons aren't providing a feed the next time I need to automate a build task. Maybe next time I'll take the time to have a look at Attrice's Microsoft Build Sidekick.

Sunday, August 15, 2010

Custom Authentication in WCF

I'm building an HTML5 iPhone application that accesses a WCF RESTful web service hosted by IIS. The stumbling block for me has been authentication. I decided to go with Basic Authentication over HTTPS as a simple and secure enough approach for authenticating my users. But as with most Microsoft tech it doesn't pay to wander too far from the track. If you want to authenticate Windows users then I suspect everything would more or less just work. I'm working with an existing credential store in a SQL Server database so I needed something a little different. I'm not going to go into detail about how I eventually got it sorted - this is really just to acknowledge Dominick Baier over at www.leastprivilege.com for shining a light on the process.

A few things to note for future reference. WCF doesn't use HttpContext.Current.User to identify the current user (although this can be enabled). Instead use ServiceSecurityContext.Current.PrimaryIdentity.Name. If following along with Dominick's example and setting up the HttpContextPrincipalPolicy it's quite valid to keep using the Thread.CurrentPrincipal to identify the user. And if the identity of the user is not reflected in Thread.CurrentPrincipal then something else is configured incorrectly. In my case the policy wasn't being loaded because I had it defined under the default behavior and not the MunqServiceBehavior I set up in an earlier post, see config section below:

1 <behaviors>
2   <serviceBehaviors>
3      <behavior name="MunqServiceBehavior">
4         <serviceMetadata httpGetEnabled="true" />
5         <serviceDebug includeExceptionDetailInFaults="false" />
6         <MunqInstanceProvider />
7         <serviceAuthorization principalPermissionMode="Custom"> <!-- set to Custom to enable auth policies below -->
8           <authorizationPolicies>
9           <!--
10             sync ServiceSecurityContext.PrimaryIdentity with Context.User.Identity and Thread.CurrentPrincipal with Context.User
11         -->
12         <add policyType="CustomAuthenticationModule.HttpContextIdentityPolicy, CustomAuthenticationModule" />
13         <add policyType="CustomAuthenticationModule.HttpContextPrincipalPolicy, CustomAuthenticationModule" />
14        </authorizationPolicies>
15       </serviceAuthorization>
16     </behavior>
17     <behavior name="">
18        <serviceMetadata httpGetEnabled="true" />
19        <serviceDebug includeExceptionDetailInFaults="false" />
20     </behavior>
21    </serviceBehaviors>
22 </behaviors>

Then I couldn't figure out why the authentication module itself wasn't loading. Turns out it's a known issue with Cassini, the Visual Studio web server. For IIS7 we're supposed to be using the <system.webServer> section but Cassini uses the old IIS6 syntax. The work around is to define the module in both locations:

1 <system.web>
2   <compilation debug="true" targetFramework="4.0" />
3   <httpModules>
4     <!-- added here and in system.webServer to load module using Cassini -->
5     <add name="CustomAuthenticationModule"
6         type="CustomAuthenticationModule.CustomAuthentication, CustomAuthenticationModule"/>
7   </httpModules>
8 </system.web>
9
10 <system.webServer>
11   <validation validateIntegratedModeConfiguration="false"/>
12   <modules runAllManagedModulesForAllRequests="true">
13     <remove name="CustomAuthenticationModule"/>
14     <add name="UrlRoutingModule"
15         type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
16     <add name="CustomAuthenticationModule"
17         type="CustomAuthenticationModule.CustomAuthentication, CustomAuthenticationModule"/>
18   </modules>
19 </system.webServer>
20

So getting that sorted helped but the next issue was particularly annoying. I set breakpoints in my code and I could see the custom authentication taking place but after successfully authenticating the user and exiting my AuthenticateRequest handler it would immediately hit the EndRequest handler with a 401 - Unauthorized error. Apparently it pays to turn off security in the standard endpoint in order to use a custom handler. Presumably after executing my handler it was trundling off to a standard handler which wasn't then able to authenticate the user trying to access the service and returning access denied.

1 <standardEndpoints>
2   <webHttpEndpoint>
3      <!--
4       Configure the WCF REST service base address via the global.asax.cs file and the default endpoint
5       via the attributes on the <standardEndpoint> element below
6     -->
7     <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true">
8       <security mode="None"/> <!-- turn off security to use custom module -->
9     </standardEndpoint>
10  </webHttpEndpoint>
11 </standardEndpoints>
12

As a postscript and after working for more than a few years developing an Internet Banking site I'm extremely wary of roll-your-own authentication schemes. It's very difficult to get authentication right and the amount of effort required is typically a reflection of the overall risk of getting it wrong. For a bank that can include not just the risk of exposing a customer's accounts or even losing actual money. Banks have for a number of years implemented rules to minimise those losses by restricting the amount of money that can be transferred online and ensuring inter-bank transfers have a built-in delay period. The risk to a bank is also about the public perception of safety and bad press around online banking can result in substantial loss of custom. I walked away from a job with a bank where I felt strongly that inadequate steps were taken to ensure the security of the online application I was developing. I still think I made the right decision and in case anyone is wondering, it most definitely wasn't the PSIS.

Friday, August 6, 2010

Munq IocContainer Version 2.0

I've just upgraded my project to version 2 of Munq, now with lifetime managers. No drama and a great validation for the use of Unit Tests. Remove the reference to the original container, download and unzip the new version. Load up the source for the new version, rebuild, and run tests. Then add a reference to the new version, or in this case two references, Munq.Interfaces and Munq.IocContainer, adjust namespace imports (using Munq), use the new IIocContainer interface to declare the container (see below), and run tests. That's it.

public static IIocContainer Di { get; private set; }