aspxerrorpath in query string can cause custom error pages to fail with Runtime Error

A bit of a strange and obscure problem here, which is why I am posting about it. I think this may be a problem with ASP.NET rather than the application but I’m willing to be proved wrong!

ASP.NET has a reserved query string variable called aspxerrorpath. This is used by default when a custom error page is invoked, i.e. if you have a 404 or 500 error, and catch it via a custom error page set up in the web.config, then the query string will be something like Error?aspexerrorpath=/Path/To/Location/Error/Occurred. The URL after the equals sign can be used to redirect or log the error page. This happens with MVC as well as Webforms.

However if there is a problem with the aspxerropath URL, for instance it is too long, then the application will fall over with a Runtime Error screen. This is probably because ASP.NET is attempting to parse the URL, it fails, but obviously can’t go back to the custom error page because otherwise it would keep going round in an infinite loop.

Although it is easily possible to remove aspxerrorpath from the error page’s URL, simply by adding an alternative query parameter, the problem is that hacker-types can still manually type it in and possibly gain a little bit more information about your site. It was highlighted as a ‘Low risk’ problem by a security company on a website of mine so I thought I should get it sorted.

I found that following ‘fix’ for another problem seemed to work for this as well, basically it just makes ASP.NET stop parsing the passed URL by instructing it to ignore URLs with aspxerrorpath in the querystring.

http://weblogs.asp.net/scottgu/archive/2010/09/24/update-on-asp-net-vulnerability.aspx

Note I am using .Net 4.0, and the above is an old blog post, so there still seems to be some issues with it. I’m not entirely sure why they can’t remove it altogether!

web.config transforms for CAS integration

I have previously posted about using a different web.config file for each build configuration, to save you having to change your web.config each time you want to change from a development build to a production build etc (Read here).

That was some time ago though and MVC3 has since moved on to use web.config transforms, where you use XPath style commands to change the web.config file for each configuration.

As a useful reference here are the transforms I used for adding CAS integration into my app. You only need to change the attributes of the authentication node if you are not using forms authentication as your default. If you are using forms authentications as your default then you will probably need to use xdt:Transform=”RemoveAll” with the forms nodes, before you add the new one too.

More about web.config transforms is here.

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

  <configSections>
    <section name="casClientConfig"
           type="DotNetCasClient.Configuration.CasClientConfiguration, DotNetCasClient" xdt:Transform="Insert"  />
  </configSections>

  <casClientConfig
  casServerLoginUrl="https://login.casserver.com/cas/login"
  casServerUrlPrefix="https://login.casserver.com/cas/"
  serverName="http://myservername.com"
  notAuthorizedUrl="~/Security/NotAuthorised"
  cookiesRequiredUrl="~/Security/CookiesRequired"
  redirectAfterValidation="true"
  renew="false"
  singleSignOut="true"
  ticketValidatorName="Cas10"
  serviceTicketManager="CacheServiceTicketManager" xdt:Transform="InsertAfter(/configuration/configSections)" />


  <system.web>

    <authentication
       
        mode="Forms"
        xdt:Transform="SetAttributes">

      <forms
       loginUrl="https://login.casserver.com/cas/login"
       timeout="30"
       defaultUrl="/"
       cookieless="UseCookies"
       slidingExpiration="true"
       path="/MyVirtualPath" xdt:Transform="Insert" />
      
    </authentication>

    <httpModules>
      <add name="DotNetCasClient"
           type="DotNetCasClient.CasAuthenticationModule,DotNetCasClient" xdt:Transform="Insert" />
    </httpModules>
    
 
 
  </system.web>

  <system.webServer>
    <modules>
      <remove name="DotNetCasClient" xdt:Transform="Insert"/>

      <add name="DotNetCasClient"
           type="DotNetCasClient.CasAuthenticationModule,DotNetCasClient" xdt:Transform="Insert"/>
    </modules>
    
  </system.webServer>
</configuration>

Downgrading a service reference to a web reference in a .Net 4.0 web application

If you are trying to use a service reference in a .Net 4.0 site, but get an error message similar to the following when trying to access one of its methods…

> The HTTP request is unauthorized with client authentication scheme
> ‘Anonymous’. The authentication header received from the server was
> ‘Basic realm=”webMethods”‘.

… then the reason is that you need to pass a user name and password to the web service you are trying to connect to.

‘I’m already doing that,’ you say.

Well good, however you will also need to change your security mode to ‘Transport’ and your clientCredentialType to ‘Basic’, plus add you ‘realm’ in.

‘Done that too, it still comes back with that error message’, you reply.

This problem is caused by the fact that .Net 4.0 service references do not allow you to pass a user name and password over a non-SSL link. Security mode has to be ‘Transport’ for user credentials, and that looks for an https URL. This is a good thing, it’s more secure. But what if you have to use a web service that makes you pass a user name and password insecurely, and what if there is no way of getting the owners to change it?

Well you’ll have to use the old .Net 2.0 web reference method, which lets you do it. Assuming that you’ve already added the .Net 4.0 service reference and code to call it this is what you should do:

1) Remove the entry under the Service Reference directory (make a note of the URL!).
2) Right click the Service Reference folder, click Add Service Reference.
3) Click Advanced.
4) Click Add Web Reference, and enter your URL. Change the name to the same as the one you’ve just removed and press Add Reference.
5) Look at your web.config file. There should be an applicationSettings section at the bottom with the details of the web reference.
6) Go to the configSections area of your web.config and add the following code, substituting ‘MyNameSpace’ for your app’s web project’s namespace:

<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
      <section name="MyNameSpace.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />

</sectionGroup>

7) Then go to your source code where you call the service – then change:

// .Net 4.0 service reference code
MyService.wsThings_PortTypeClient proxyServ;
proxyServ = new MyService.wsThings_PortTypeClient();
proxyServ.ClientCredentials.UserName.UserName = "User";
proxyServ.ClientCredentials.UserName.Password = "Password";

to

// .Net 2.0 web reference code
MyService.wsThings proxyServ;
proxyServ = new MyService.wsApplicants();
proxyServ.Credentials =  new System.Net.NetworkCredential("User", "Password");

The rest of the code calling the methods, and classes, should be the same, and you shouldn’t need to change it.

If you can persuade them to change to a secure service then do so though – there’s a reason why it is made harder to connect to an insecure one in .Net 4.0!

Using web.config application settings in nUnit

If the piece of code that you are testing refers to an appsetting value in the web.config file then nUnit will fall over – basically because nUnit itself does not use the web.config file.

This is a fairly common thing to come up against, and the easy solution is on the web, but it doesn’t appear to be in the nUnit help so I thought I’d put it here too, and make it specific to the dependency injection/Sharp Architecture web projects that my team use.

There are two things that you can do. The quick thing to do is to find your tests dll file. In a Sharp Architecture 1.6 project this will be in something like [project root]/tests/[namespace].Tests/bin/Debug. The dll file will be called (unsurprisingly) [namespace].Tests.dll.

You will see that nUnit has also created a [namespace].Tests.dll.config file. This is where you should put your application settings. When you open it up you can see that it looks similar to the web.config file – there is already an appsettings section. Simply copy your web.config settings to here.

That is all very well, but what if you want to mock different values of this app setting when you are testing? If you are using a dependency injection development pattern you might also want to consider having a separate class and interface that just handles the retrieval of application settings, e.g.

public class AppSettingsService: IAppSettingsService
{
        public string ManagerRole
        {
            get { 
              if (ConfigurationManager.ConnectionStrings["ManagerRole"] == null)
                 return "";
              else
                 return ConfigurationManager.ConnectionStrings["ManagerRole"].ToString();  
            } 
        }
}

You can then inject this service class into the class that you are testing, use the methods on this service class to retrieve your appsettings, and mock them to your heart’s content.

Note: I am assuming you know what dependency injection, mocking, interfaces etc are. If not I suggest searching the net – they are a very good way of developing!

Using different web.config/NHibernate.config settings for each Visual Studio release configuration

When you have a development, test and production environment it is likely that each one has different connection strings and other application settings. To avoid the tedium (and any errors) of having to manually change the config files each time you change configuration then I suggest Scott Hanselmann’s method of using a pre-build command that chooses one out of multiple config files (one for each configuration) is a less error-prone way of doing it.

His article is here.

There are several other things to note here:

  1. The pre-build command is not quite correct (for my system anyway). Instead of:
    "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)Web.config.$(ConfigurationName)" "$(ProjectDir)Web.config"
    

    You will need:

    call "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)Web.config.$(ConfigurationName)" "$(ProjectDir)Web.config"
    
  2. If you are using NHibernate then you will probably also want to change the NHibernate.config file between releases. In which case simply add another line to the pre-build event:
    call "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)Web.config.$(ConfigurationName)" "$(ProjectDir)Web.config"
    call "$(ProjectDir)copyifnewer.bat" "$(ProjectDir)NHibernate.config.$(ConfigurationName)" "$(ProjectDir)NHibernate.config"
    
  3. If you are using SourceSafe then you will need to make sure that your Web.config and NHibernate.config files are checked out prior to building, otherwise they are read-only and the copy process won’t be able to overwrite them (and you probably wouldn’t want it to anyway).
  4. Of course any new application settings etc probably have to be added into all versions of the config files, rather than just the one.

This method saves a lot of mistakes being made in more complex web.config files.

Follow

Get every new post delivered to your Inbox.

Join 70 other followers