Saturday, October 28, 2006

Error 401.1 when when using integrated authentication and a custom service account

There's a great MSDN article, with step by step instructions on how to set up a service account for an ASP.NET 2.0 application should you not want to user the Network Service account.

Once a user account has been created, assign ASP.NET permissions to the new account by running the command below from the framework prompt.

aspnet_regiis -ga MachineName\AccountName

Where MachineName is the name of your server or the domain name if you are using a domain account, and AccountName is the name of your custom account. When you run aspnet_regiis.exe with the -ga switch, the command grants the following rights to the account:

  • Access to the IIS Metabase Permission to write to the %Windir%\Microsoft.NET\Framework\version\Temporary ASP.NET Files folder
  • The account is also a member of the local Users group; therefore, it has read access to the \Inetpub directory tree (these directories have an ACL that grants read access to the Users group).
Should you be using the XmlSerializer Class, the account must also have permission to write to the temporary directory (as defined by the TEMP environment variable) in order to deserialize an object.

The article also details one of the disadvantages of using a custom account -

When you change the identity of your application pool to use a domain account instead of a machine account, you lose the ability to perform Kerberos authentication until a domain administrator runs the Setspn utility to create a service principal name (SPN) for the domain account. If you have multiple applications on the same server that use separate domain identities and they need to use Kerberos authentication, then you need to use separate Domain Name System (DNS) names for each application.

If your account does not have a service principal name and for some time, your web site will require authentication and user's will be prompted for a user name and password but even valid credential will not be authenticated. Should you be unable to create a service principle name, another MSDN article, How to configure IIS to support both the Kerberos protocol and the NTLM protocol for network authentication, details how to enable/disable Kerberos authentication.

IIS passes the Negotiate security header when Integrated Windows authentication is used to authenticate client requests. The Negotiate security header lets clients select between Kerberos authentication and NTLM authentication.

1. the following command, usually located in C:\Inetpub\Adminscripts to retrieve the current values for the NTAuthenticationProviders metabase property:

cscript adsutil.vbs get w3svc/WebSite/root/NTAuthenticationProviders

In this command, WebSite is a placeholder for the Web site ID number. The Web site ID number of the default Web site is 1.

This command fails if the NTAuthenticationProviders metabase property is not defined. If the Negotiate process is enabled, this command returns the following information:

NTAuthenticationProviders : (STRING) "Negotiate,NTLM"

2. If the command in step 1 does not return the string "Negotiate,NTLM," use the following command to disable the Negotiate process:

cscript adsutil.vbs set w3svc/WebSite/root/NTAuthenticationProviders "NTLM"

Repeat step 1 to verify that the Negotiate process has been disabled.

Next week, I'm going to look into how the Microsoft Authentication and Access Control Diagnostics 1.0 Tool could have helped solve this problem.

Monday, October 23, 2006

Data Binding Child Object Properties

I don't know why but I always have trouble remembering the syntax to databind child object properties. When using a GridView, a TemplateField must be used to get the values from the child object as a BoundField do not work correctly in this scenario.

In order to bind to properties of a Customer object which is a property of another class, use the syntax below:

<%# ((Customer)Eval("Customer")).ID %>
<%# ((Customer)Eval("Customer")).Name %>

Note that a null customer property value will cause problems with this approach and don't forget to add the a reference to the Customer class using the Import directive.

<%@ Import namespace="MyNamespace.Customer" %>

Another fiddly issue can be embedding a nested data control such as Repeater within a GridView column and databinding to a child object.

<asp:Repeater ID="rpt" runat="server" DataSource='<%# ((Customer)Container.DataItem).Address%>'>
<ItemTemplate><%# Container.DataItem %></ItemTemplate>

Tuesday, October 17, 2006

Replacing nested web.config sections using Web Deployment Projects

It's relatively straightforward to replace specific sections of a Visual Studio 2005 Web Site web.config using a Web Deployment Project. Scott Guthrie has a great blog post on the Web Deployment Project feature set, but I stumbled across a minor issue today when I tried to replace the compilation section.

To replace web.config sections, open the Web Deployment Property Pages and select Deployment in the left hand menu. Click the checkbox to Enable Web.config file section replacement. Whilst the examples hyperlink shows a tooltip on how to replace the appSettings and connectionStrings sections using sectionName=filename, when I attempted to replace the compilation element in the web.config, I received the following build error.

Error 2 web.config(1): error WDP00002: missing section compilation.

To successfully replace the compilation element or other nested elements, it's necessary to use an XPath expression. For example, system.web/compilation as below.

Web Deployment Project Property Pages

Monday, October 16, 2006

IIS Extended Logging Properties

Countless times, the .NET exception, The request failed with HTTP status 401: Access Denied dumbfounds developers. To determine under what user is trying to access a resource extend the default logging available in Internet Information Services (IIS).

  1. Right click on the Web Site you want to manage.
  2. Click Properties in the Enable Logging panel of the Web Site tab.

    Web Site Properties

  3. Click the Extended Properties tab and check the User Name (cs-username) checkbox under Extended Properties.

    Extended Properties

Once the User Name is checked, the the windows user who is accessing the resource will be logged as below.

02:40:00 domain\username W3SVC1 AUHDQL99 POST /TestAuthentication/Default.aspx 500

Colour Your Console Apps

A new feature in .NET2.0 is the ability to add colour to console applications. There's now no need to use Interop to import Kernel32.dll as was previously the case. Simply use the ForegroundColor and BackgroundColor properties of the Console object to give your console apps more readability as below. Lovely !

Console.ForegroundColor = System.ConsoleColor.Cyan;
Console.BackgroundColor = System.ConsoleColor
Console.ForegroundColor = System.ConsoleColor
Console.BackgroundColor = System.ConsoleColor

Break When an Exception is Thrown

A colleague of mine recently had an issue with a .NET exception that was caught in a try catch block, not reported and subsequently caused issues. Make sure you have the Exceptions... option in the Debug menu. If not, add it using the Customize... option in the Tools menu. Then, to break whenever an exception is thrown follow these simple steps -

  1. On the Debug menu, click Exceptions...
  2. In the Exceptions dialog box, select Thrown for Common Language Runtime Exceptions.
It's possible to limit the exception types by expanding the tree and checking specific options. Pretty neat I thought.

Saturday, October 07, 2006

LINQ Project Types do not appear if VB.NET is not installed

I installed LINQ (Language Integrated Query) earlier this week and had a bit of trouble getting going. I live in a world of C# and don't have VB.NET installed on my aging laptop at home. This caused the LINQ Preview (May 2006) installer to skip a few tasks during install and the project types that should appear in the Visual Studio New Project menu didn't appear. Well it didn't take me long to hunt this one on down MSDN forums but here's what to do if you have this problem. Remove the LINQ Preview if you've already installed it and the project types are missing or simply install using this command line from the same directory as "LINQ Preview (May 2006).msi" :

msiexec.exe /i "LINQ Preview (May 2006).msi" VCSPROJECTTEMPLATESDIR.C7A0C9D96EB648548BD084A2A4C688EB="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ProjectTemplates\CSharp\LINQ Preview\" VCSPKGDIR.C7A0C9D96EB648548BD084A2A4C688EB="C:\Program Files\Microsoft Visual Studio 8\VC#\VCSPackages\" VCSIDEDIR.C7A0C9D96EB648548BD084A2A4C688EB="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\" DEBUGVISUALIZERDIR.C7A0C9D96EB648548BD084A2A4C688EB="C:\Program Files\Microsoft Visual Studio 8\Common7\Packages\Debugger\Visualizers\" CSWEBPROJECTTEMPLATESDIR.4AE13B6F621C49B9995EB64016EC2E60="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ProjectTemplates\Web\CSharp\1033" CSITEMTEMPLATEDIR.92D1EB66EA714CFE9C88A25F2388CD0F="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\ItemTemplates\CSharp\1033" DEVENV="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\Devenv.exe" DEVENVPATH="C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\"

Please replace relevant Visual Studio paths (underlined) with actual Visual Studio installation path. Couldn't be simpler ;)