TFS builds and HTTP Code 500 error

At one of our clients, TFS build server was choking for no good reason with the following error “Please contact your administrator. There was an error contacting the server. Technical information (for administrator): System.ServiceModel.ServiceActivationException.” Not very useful error message, isn’t it? TFS logs were a bit more informative and had the following error:

WebHost failed to process a request.
Sender Information: System.ServiceModel.ServiceHostingEnvironment+HostingManager/4342953
Exception: System.ServiceModel.ServiceActivationException: The service '/tfs/queue/DefaultCollection/Services/v4.0/MessageQueueService2.svc' cannot be activated due to an exception during compilation.  The exception message is: This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection. If your service is being hosted in IIS you can fix the problem by setting 'system.serviceModel/serviceHostingEnvironment/multipleSiteBindingsEnabled' to true or specifying 'system.serviceModel/serviceHostingEnvironment/baseAddressPrefixFilters'.
Parameter name: item. ---> System.ArgumentException: This collection already contains an address with scheme http.  There can be at most one address per scheme in this collection. If your service is being hosted in IIS you can fix the problem by setting 'system.serviceModel/serviceHostingEnvironment/multipleSiteBindingsEnabled' to true or specifying 'system.serviceModel/serviceHostingEnvironment/baseAddressPrefixFilters'.
Parameter name: item
   at System.ServiceModel.UriSchemeKeyedCollection.InsertItem(Int32 index, Uri item)
   at System.Collections.Generic.SynchronizedCollection`1.Add(T item)
   at System.ServiceModel.UriSchemeKeyedCollection..ctor(Uri[] addresses)
   at System.ServiceModel.ServiceHost..ctor(Type serviceType, Uri[] baseAddresses)
   at System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(Type serviceType, Uri[] baseAddresses)
   at System.ServiceModel.Activation.ServiceHostFactory.CreateServiceHost(String constructorString, Uri[] baseAddresses)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.CreateService(String normalizedVirtualPath, EventTraceActivity eventTraceActivity)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.ActivateService(ServiceActivationInfo serviceActivationInfo, EventTraceActivity eventTraceActivity)
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath, EventTraceActivity eventTraceActivity)
   --- End of inner exception stack trace ---
   at System.ServiceModel.ServiceHostingEnvironment.HostingManager.EnsureServiceAvailable(String normalizedVirtualPath, EventTraceActivity eventTraceActivity)
   at System.ServiceModel.ServiceHostingEnvironment.EnsureServiceAvailableFast(String relativeVirtualPath, EventTraceActivity eventTraceActivity)
Process Name: w3wp

Now, that’s a much better error message. It actually tells us that the problem is caused by multiple bindings in IIS on TFS website and it tells us how this error can be fixed. I love such errors. Anyway, to fix the problem we need to add the following line to web.config file on TFS server:

<serviceHostingEnvironment aspNetCompatibilityEnabled=”true" multipleSiteBindingsEnabled="true" />

Then restart TFS Build Service, and it’s all good again…

Things to Know Before Upgrading to SharePoint 2010

Recently, I have been getting a lot of questions about what are the things we should consider before upgrading to SharePoint 2010. Here is my list:

  • Ensure your environment is fully functioning before you perform an upgrade. No need to carry over any old issues into your new SharePoint 2010 environment
  • Make sure you meet hardware requirements: 64-bit hardware, 4 cores CPU or better, 8Gb of RAM or better, enough disk storage, et cetera.
  • Make sure you meet software requirements Windows Server 2008 SP2 or better, SQL Server 2005 SP3 or better, SharePoint prerequisites installed, member of Active Directory domain, and so on. Everything must be 64 bit.
  • Plan browser support (IE6 is not supported) and Office client upgrade
  • Get all your SharePoint servers to Service Pack 2 or later
  • Run Pre-Upgrade check to identify potential issues that will prevent us from successfully upgrading to SharePoint 2010. Review the report. Fix the errors. Re-run pre-upgrade check utility. Repeat, if needed.
  • Identify all customizations such as 3rd party webparts or look-n-feel changes. Make sure those will work properly in SharePoint 2010
  • Backup all SharePoint databases. Seriously. Backup all SharePoint databases.
  • Choose upgrade approach: in-place approach or database attach upgrade. Or hybrid approach.
  • Test the upgrade process. Before you perform an upgrade in production environment, test the upgrade process and address any issues you found during testing
  • UPGRADE all your SharePoint servers to SharePoint 2010 (finally)
  • Evaluate the upgrade. Review logs, check update status troubleshoot issues and errors.
  • Use Visual Upgrade to convert site collections to the SharePoint 2010 product look
  • Completing the upgrade: configure service applications, update database permissions, configure authentication, validate the upgrade, etc.
  • Enjoy the SharePoint 2010 awesomeness.

To learn more about how to build a sound SharePoint environment, check out our Upcoming Courses

Preventing Frame Exploits in a Passive Claims Model

At a presentation a few weeks ago someone asked me about capturing session details during authentication at an STS by way of frames and JavaScript.  To paraphrase the question: “What prevents a malicious developer from sticking an RP within an iframe, cause a redirect to an STS, get some user to log in, and then capture the details through JavaScript from the parent page?”  There are a couple of ways this problem can be solved.  It’s a defense-in-depth problem where on their own, each piece won’t close every attack vector, but when used together you end up with a pretty solid solution.

  • First, a lot of new browsers will actually prevent cross-frame JavaScript calls when SSL is involved.  Depending on the browser, the JavaScript will throw the equivalent of an Access Denied exception.  This is not the case with all browser versions though.  Older browsers may not do this.
  • Second, some browsers will not allow you to host an SSL page in a frame if the parent page is not using SSL.  The easy fix for the malicious developer is to simply use SSL for the parent site, but that could be problematic as the CA’s theoretically verify the sites requesting certificates.
  • Third, you could write some JavaScript for the STS to bust out of the frame.  It would look something like this:

if (top != self)
{
    try
    {
        top.location.replace(self.location.href);
    }
    catch (e)
    {
    }
}

The problem with this is that it wouldn’t work if the browser has JavaScript disabled.

  • Fourth, there is a new HTTP header that Microsoft introduced in IE 8 that tells the browser that if the requested page is hosted in a frame to simply stop processing the request.  Safari and Chrome support it natively, and Firefox supports it with the NoScript add on.  The header is called X-Frame-Options and it can have two values: “DENY” which prevents all requests, and “SAMEORIGIN” which allows a page to be rendered if the parent page is the same page.  E.g. the parent is somesite.com/page and the framed page is somesite.com/page.

There are a couple of ways to add this header to your page.  First you can add it via ASP.NET:

Context.Response.AddHeader("x-frame-options", "DENY");

Or you could add it to all pages via IIS.  To do this open the IIS Manager and select the site in question.  Then select the Feature “HTTP Response Headers”:

image

Select Add… and then set the name to x-frame-options and the value to DENY:

image

By keeping in mind these options you can do a lot to prevent any exploits that use frames.

How SharePoint finds its content?

Well, I was looking through SharePoint web.config file one time and asked myself how SharePoint knows where to find its contents. I know, it's a weird question to ask, but what can I say… I am that kind of person. Anyways, obviously looking through web.config did not yield any results, so I looked googled it. By the way, I do not know why, but I keep calling searching online as "googling" even though I switched to Bing a while ago. Old habits die hard, I guess, but I digress… After a little of research, I have found this blog post that has explained how SharePoint 2010 or 2007 finds its content. Basically, this is how it works:

  • User types in the URL of the SharePoint website
  • IIS gets a HTTP request, then handles it based on port number or a host header specified in the request
  • Matching SharePoint website hands all requests to ASP.NET (thanks to wild card ISAPI mappings), which does all kinds of magic with the request
  • Then, SPRequest HTTP module (defined in the web.config) gets into the play. SPRequest module does its magic too, and eventually request the location of the SharePoint configuration database from the registry. Connection string for the SharePoint configuration database is set using DSN key at HKLM\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\12.0\Secure\ConfigDB (for SharePoint 2007) or HKLM\SOFTWARE\Microsoft\Shared Tools\Web Server Extensions\14.0\Secure\ConfigDB (for SharePoint 2010). So, this is the registry value, you need to change, if you ever need to move configuration database.
  • SharePoint configuration database knows where everything about the SharePoint farm, so it is (relatively speaking) "no brainer" from that point on… and the user sees an awesome SharePoint page on the screen.

It's that easy J

Converting Claims to Windows Tokens and User Impersonation

In a domain environment it is really useful to switch user contexts in a web application.  This could be if you are needing to log in with credentials that have elevated permissions (or vice-versa) or just needing to log in as another user.

It’s pretty easy to do this with Windows Identity Foundation and Claims Authentication.  When the WIF framework is installed, a service is installed (that is off by default) that can translate Claims to Windows Tokens.  This is called (not surprisingly) the Claims to Windows Token Service or (c2WTS).

Following the deploy-with-least-amount-of-attack-surface methodology, this service does not work out of the box.  You need to turn it on and enable which user’s are allowed to impersonate via token translation.  Now, this doesn’t mean which users can switch, it means which users running the process are allowed to switch.  E.g. the process running the IIS application pools local service/network service/local system/etc (preferably a named service user other than system users).

To allow users to do this go to C:\Program Files\Windows Identity Foundation\v3.5\c2wtshost.exe.config and add in the service users to <allowedCallers>:

<windowsTokenService>
  <!--
      By default no callers are allowed to use the Windows Identity Foundation Claims To NT Token Service.
      Add the identities you wish to allow below.
    -->
  <allowedCallers>
    <clear/>
    <!-- <add value="NT AUTHORITY\Network Service" /> -->
    <!-- <add value="NT AUTHORITY\Local Service" /> –>
    <!-- <add value="nt authority\system" /> –>
    <!-- <add value="NT AUTHORITY\Authenticated Users" /> -->
  </allowedCallers>
</windowsTokenService>

You should notice that by default, all users are not allowed.  Once you’ve done that you can start up the service.  It is called Claims to Windows Token Service in the Services MMC snap-in.

That takes care of the administrative side of things.  Lets write some code.  But first, some usings:

using System;
using System.Linq;
using System.Security.Principal;
using System.Threading;
using Microsoft.IdentityModel.Claims;
using Microsoft.IdentityModel.WindowsTokenService;

The next step is to actually generate the token.  From an architectural perspective, we want to use the UPN claims type as that’s what the service wants to see.  To get the claim, we do some simple LINQ:

IClaimsIdentity identity = (ClaimsIdentity)Thread.CurrentPrincipal.Identity;
string upn = identity.Claims.Where(c => c.ClaimType == ClaimTypes.Upn).First().Value;

if (String.IsNullOrEmpty(upn))
{
    throw new Exception("No UPN claim found");
}

Following that we do the impersonation:

WindowsIdentity windowsIdentity = S4UClient.UpnLogon(upn);

using (WindowsImpersonationContext ctxt = windowsIdentity.Impersonate())
{
    DoSomethingAsNewUser();

    ctxt.Undo(); // redundant with using { } statement
}

To release the token we call the Undo() method, but if you are within a using { } statement the Undo() method is called when the object is disposed.

One thing to keep in mind though.  If you do not have permission to impersonate a user a System.ServiceModel.Security.SecurityAccessDeniedException will be thrown.

That’s all there is to it.

Implementation Details

In my opinion, these types of calls really shouldn’t be made all that often.  Realistically you need to take a look at how impersonation fits into the application and then go from there.  Impersonation is pretty weighty topic for discussion, and frankly, I’m not an expert.

Installing ADFS 2 and Federating an Application

From Microsoft Marketing, ADFS 2.0 is:

Active Directory Federation Services 2.0 helps IT enable users to collaborate across organizational boundaries and easily access applications on-premises and in the cloud, while maintaining application security. Through a claims-based infrastructure, IT can enable a single sign-on experience for end-users to applications without requiring a separate account or password, whether applications are located in partner organizations or hosted in the cloud.

So, it’s a Token Service plus some.  In a previous post I had said:

In other words it is a method for centralizing user Identity information, very much like how the Windows Live and OpenID systems work.  The system is reasonably simple.  I have a Membership data store that contains user information.  I want (n) number of websites to use that membership store, EXCEPT I don’t want each application to have direct access to membership data such as passwords.  The way around it is through claims.

The membership store in this case being Active Directory.

I thought it would be a good idea to run through how to install ADFS and set up an application to use it.  Since we already discussed how to federate an application using FedUtil.exe, I will let you go through the steps in the previous post.  I will provide information on where to find the Metadata later on in this post.

But First: The Prerequisites

  1. Join the Server to the Domain. (I’ve started the installation of ADFS three times on non-domain joined systems.  Doh!)
  2. Install the latest .NET Framework.  I’m kinda partial to using SmallestDotNet.com created by Scott Hanselman.  It’s easy.
  3. Install IIS.  If you are running Server 2008 R2 you can follow these steps in another post, or just go through the wizards.  FYI: The post installs EVERY feature.  Just remember that when you move to production.  Surface Area and what not…
  4. Install PowerShell.
  5. Install the Windows Identity Foundation: http://www.microsoft.com/downloads/details.aspx?FamilyID=eb9c345f-e830-40b8-a5fe-ae7a864c4d76&displaylang=en
  6. Install SQL Server.  This is NOT required.  You only need to install it if you want to use a SQL Database to get custom Claims data.  You could also use a SQL Server on another server…
  7. Download ADFS 2.0 RTW: http://www.microsoft.com/downloads/details.aspx?familyid=118c3588-9070-426a-b655-6cec0a92c10b&displaylang=en

The Installation

image

Read the terms and accept them.  If you notice, you only have to read half of what you see because the rest is in French.  Maybe the lawyers are listening…these things are getting more readable.

image

Select Federation Server.  A Server Proxy allows you to use ADFS on a web server not joined to the domain.

image

We already installed all of these things.  When you click next it will check for latest hotfixes and ask if you want to open the configuration MMC snap-in.  Start it.

image

We want to start the configuration Wizard and then create a new Federation Service:

image

Next we want to create a Stand-alone federation server:

image

We need to select a certificate for ADFS to use.  By default it uses the SSL certificate of the default site in IIS.  So lets add one.  In the IIS Manager select the server and then select Server Certificates:

image

We have a couple options when it comes to adding a certificate.  For the sake of this post I’ll just create a self-signed certificate, but if you have a domain Certificate Authority you could go that route, or if this is a public facing service create a request and get a certificate from a 3rd party CA.

image

Once we’ve created the certificate we assign it to the web site.  Go to the website and select Bindings…

image

Add a site binding for https:

image

Now that we’ve done that we can go back to the Configuration Wizard:

image

Click next and it will install the service.  It will stop IIS so be aware of that.

image

You may receive this error if you are installing on Server 2008:

image

The fix for this is here: http://www.syfuhs.net/2010/07/23/ADFS20WindowsServiceNotStartingOnServer2008.aspx

You will need to re-run the configuration wizard if you do this.  It may complain about the virtual applications already existing.  You two options: 1) delete the applications in IIS as well as the folder C:\inetpub\adfs; 2) Ignore the warning.

Back to the installation, it will create two new Virtual Applications in IIS:

image

Once the wizard finishes you can go back to the MMC snap-in and fiddle around.  The first thing we need to do is create an entry for a Relying Party.  This will allow us to create a web application to work with it.

image

When creating an RP we have a couple options to provide configuration data.

image

Since we are going to create a web application from scratch we will enter in manual data.  If you already have the application built and have Federation Metadata available for it, by all means just use that.

We need a name:

image

Very original, eh?

Next we need to decide on what profile we will be using.  Since we are building an application from scratch we can take advantage of the 2.0 profile, but if we needed backwards compatibility for a legacy application we should select the 1.0/1.1 profile.

image

Next we specify the certificate to encrypt our claims sent to the application.  We only need the public key of the certificate.  When we run FedUtil.exe we can specify which certificate we want to use to decrypt the incoming tokens.  This will be the private key of the same certificate.  For the sake of this, we’ll skip it.

image

The next step gets a little confusing.  It asks which protocols we want to use if we are federating with a separate STS.  In this case since we aren’t doing anything that crazy we can ignore them and continue:

image

We next need to specify the RP’s identifying URI.

image

Allow anyone and everyone, or deny everyone and add specific users later?  Allow everyone…

image

When we finish we want to edit the claim rules:

image

This dialog will allow us to add mappings between claims and the data within Active Directory:

image

So lets add a rule.  We want to Send LDAP Attributes as Claims

image

First we specify what data in Active Directory we want to provide:

image

Then we specify which claim type to use:

image

And ADFS is configured!  Lets create our Relying Party.  You can follow these steps: Making an ASP.NET Website Claims Aware with the Windows Identity Foundation.  To get the Federation Metadata for ADFS navigate to the URL that the default website is mapped to + /FederationMetadata/2007-06/FederationMetadata.xml.  In my case it’s https://web1.nexus.internal.test/FederationMetadata/2007-06/FederationMetadata.xml.

Once you finish the utility it’s important that we tell ADFS that our new RP has Metadata available.  Double click on the RP to get to the properties.  Select Monitoring:

image

Add the URL for the Metadata and select Monitor relying party.  This will periodically call up the URL and download the metadata in the event that it changes.

At this point we can test.  Hit F5 and we will redirect to the ADFS page.  It will ask for domain credentials and redirect back to our page.  Since I tested it with a domain admin account I got this back:

image

It works!

For more information on ADFS 2.0 check out http://www.microsoft.com/windowsserver2008/en/us/ad-fs-2-overview.aspx or the WIF Blog at http://blogs.msdn.com/b/card/

Happy coding!

Installing IIS 7.5 on Windows 7 from the Command Line

This is more of a place for me to store something I use fairly often, but can never remember off the top of my head.  This script, when run as administrator, will install all the features of IIS for developing on Windows 7.  Mind you, this is the prettified* version so it’s web-readable.

START /WAIT DISM /Online /Enable-Feature
/FeatureName:IIS-ApplicationDevelopment
/FeatureName:IIS-ASP
/FeatureName:IIS-ASPNET
/FeatureName:IIS-BasicAuthentication
/FeatureName:IIS-CGI
/FeatureName:IIS-ClientCertificateMappingAuthentication
/FeatureName:IIS-CommonHttpFeatures
/FeatureName:IIS-CustomLogging
/FeatureName:IIS-DefaultDocument
/FeatureName:IIS-DigestAuthentication
/FeatureName:IIS-DirectoryBrowsing
/FeatureName:IIS-FTPExtensibility
/FeatureName:IIS-FTPServer
/FeatureName:IIS-FTPSvc
/FeatureName:IIS-HealthAndDiagnostics
/FeatureName:IIS-HostableWebCore
/FeatureName:IIS-HttpCompressionDynamic
/FeatureName:IIS-HttpCompressionStatic
/FeatureName:IIS-HttpErrors
/FeatureName:IIS-HttpLogging
/FeatureName:IIS-HttpRedirect
/FeatureName:IIS-HttpTracing
/FeatureName:IIS-IIS6ManagementCompatibility
/FeatureName:IIS-IISCertificateMappingAuthentication
/FeatureName:IIS-IPSecurity
/FeatureName:IIS-ISAPIExtensions
/FeatureName:IIS-ISAPIFilter
/FeatureName:IIS-LegacyScripts
/FeatureName:IIS-LegacySnapIn
/FeatureName:IIS-LoggingLibraries
/FeatureName:IIS-ManagementConsole
/FeatureName:IIS-ManagementScriptingTools
/FeatureName:IIS-ManagementService
/FeatureName:IIS-Metabase
/FeatureName:IIS-NetFxExtensibility
/FeatureName:IIS-ODBCLogging
/FeatureName:IIS-Performance
/FeatureName:IIS-RequestFiltering
/FeatureName:IIS-RequestMonitor
/FeatureName:IIS-Security
/FeatureName:IIS-ServerSideIncludes
/FeatureName:IIS-StaticContent
/FeatureName:IIS-URLAuthorization
/FeatureName:IIS-WebDAV
/FeatureName:IIS-WebServer
/FeatureName:IIS-WebServerManagementTools
/FeatureName:IIS-WebServerRole
/FeatureName:IIS-WindowsAuthentication
/FeatureName:IIS-WMICompatibility
/FeatureName:WAS-ConfigurationAPI
/FeatureName:WAS-NetFxEnvironment
/FeatureName:WAS-ProcessModel
/FeatureName:WAS-WindowsActivationService

*Interesting that “prettified” is a word according to Live Writer.

Blank page instead of the SharePoint Central Administration site

If you're getting a blank page when you are trying to access SharePoint Central Administration site, then check your IIS settings. To be more specific, check the authentication settings for SharePoint Central Administration website in IIS. Make sure that you have Windows Authentication enabled and Anonymous Authentication disabled.

This must be the shortest blog post I have ever written. But taking into consideration that it was written on the first day of work after the holiday season, it's not so bad. Happy New Year everyone!!! J

ASP.NET Application Deployment Best Practices &amp;ndash; Part 1

Over the last few months I have been collecting best practices for deploying ASP.NET applications to production.  The intent was to create a document that described the necessary steps needed to deploy consistent, reliable, secure applications that are easily maintainable for administrators.  The result was an 11 page document.  I would like to take a couple excerpts from it and essentially list what I believe to be key requirements for production applications.

The key is consistency.

  • Generate new encryption keys

The benefit to doing this is that internal hashing and encrypting schemes use different keys between applications. If an application is compromised, the private keys that can get recovered will have no effect on other applications. This is most important in applications that use Forms Authentication such as the member’s section. This Key Generator app is using built-in .NET key generation code in the RNGCryptoServiceProvider.

  • Version and give Assemblies Strong Names

Use AssemblyInfo.cs file:

[assembly: AssemblyTitle("NameSpace.Based.AssemblyTitle")]
[assembly: AssemblyDescription("This is My Awesome Assembly…")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("My Awesome Company")]
[assembly: AssemblyProduct("ApplicationName")]
[assembly: AssemblyCopyright("Copyright © 2009")]
[assembly: AssemblyTrademark("TM Application Name")]
[assembly: AssemblyCulture("en-CA")]

Strong names and versioning is the backbone of .NET assemblies. It helps distinguish between different versions of assemblies, and provides copyright attributes to code we have written internally. This is especially helpful if we decide to sell any of our applications.

  • Deploy Shared Assemblies to the GAC
    • Assemblies such as common controls
    • gacutil.exe -I "g:\dev\published\myApp\bin\myAssembly.dll"

If any assemblies are created that get used across multiple applications they should be deployed to the GAC (Global Assembly Cache). Examples of this could be Data Access Layers, or common controls such as the Telerik controls. The benefit to doing this is that we will not have multiple copies of the same DLL in different applications. A requirement of doing this is that the assembly must be signed and use a multipart name.

  • Pre-Compile Site: [In Visual Studio] Build > Publish Web Site

Any application that is in production should be running in a compiled state. What this means is that any application should not have any code-behind files or App_Code class files on the servers. This will limit damage if our servers are compromised, as the attacker will not be able to modify the source.

  • Encrypt SQL Connections and Connection Strings

Encrypt SQL Connection Strings

Aspnet_regiis.exe -pe connectionStrings -site myWebSite -app /myWebApp

Encrypt SQL Connections

Add ‘Encrypt=True’ to all connection strings before encrypting

SQL Connections contain sensitive data such as username/password combinations for access to database servers. These connection strings are stored in web.config files which are stored in plain-text on the server. If malicious users access these files they will have credentials to access the servers. Encrypting the strings will prevent the ability to read the config section.

However, encrypting the connection string is only half of the issue. SQL transactions are transmitted across the network in plain-text. Sensitive data could be acquired if a network sniffer was running on a compromised web server. SQL Connections should also be encrypted using SSL Certificates.

  • Use key file generated by Strong Name Tool:

C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin\sn.exe

“sn.exe -k g:\dev\path\to\app\myAppKey.snk”

Signing an assembly provides validation that the code is ours. It will also allow for GAC deployment by giving the assembly a signature. The key file should be unique to each application, and should be kept in a secure location.

  • Set retail=”true” in machine.config

<configuration>

<system.web>

<deployment retail="true"/>

</system.web>

</configuration>

In a production environment applications do not want to show exception errors or trace messages. Setting the retail property to true is simple way to turn off debugging, tracing, and force the application to use friendly error pages.

In part 2 I continue my post on more best practices for deployment to a production environment.

The Fine Line Between Insanity and Clarity

The BBSM (Building Broadband Service Manager) is a Windows 2000 box that acts as a gateway to the internet for customer access.  It handles that login page when you connect to the open WiFi network.  It is the most convoluted piece of [insert noun here].  The guy who signs my paycheck had asked me a few weeks back to redesign said login page in keeping with corporate designs.  It was also requested that it be mobile browser friendly.  Classic ASP, running JScript (yes, JScript), in IIS 5 on Windows 2000 behind ISA Server 2000.  The new layout was done in about an hour, and it looks pretty good.  It has been 3 weeks and I still can't get the freakin mobile code working.

In a moment of insanity (clarity?) I got the bright idea to install .NET on the box and rewrite all the pages from scratch.  Rewriting took a couple hours, and the mobile support works.  Go to set it up on the box (which must be done via USB key, via Ops guy, via physically walking to box in DataCentre {which I don't have access to}) and come to find permission errors for the ASPNET account doing COM stuff.  Needless to say I hate COM Interop with a passion.  I even sunk to the level of giving the ASPNET account full admin privileges.  Turns out Windows 2000 does not like COM Interop either.

"It looks nice if you use a laptop" was my statement to the boss.  His response was "everyone is using PDA's and their iPhones.  Maybe 10 customers use laptops."

Moral of the story: If the original code was written in the same year you turned 11, run.  Quickly.