Saturday, June 27, 2009

DotNetOpenAuth v3.2 is done

DotNetOpenAuth v3.2 just came off the presses.  Lots of feature work and a few interop fixes in this release.  The biggest highlights being:

  • Very simple story for both RPs and OPs interested in interoperating with others whether they use sreg or one of the several AX formats (finally!)
  • OAuth 1.0a support
  • PPID generation for OPs to protect customers' privacy.

Go download it.

As usual, see our VersionChanges wiki page for a more complete list of the work done for v3.2.  (There are lots more noteworthy changes that I don't describe above).

Wednesday, June 24, 2009

How to get ILMerge to work with .PFX files

ILMerge is an excellent tool for “linking” multiple assemblies into one.  But one of its switches, /keyfile:, which allows it to sign the resulting merged assembly, only accepts .snk files.  It reports no error if you feed it a password-protected .pfx key-pair file, but the resulting assembly is invalid. 

>ilmerge /keyfile:some.pfx /out:merged\some.dll some.dll someother.dll

>sn -v merged\some.dll

Microsoft (R) .NET Framework Strong Name Utility  Version 3.5.30729.1
Copyright (c) Microsoft Corporation.  All rights reserved.

merged\some.dll is a delay-signed or test-signed assembly

>sn -R merged\some.dll some.pfx

Failed to read token from assembly -- The public key for assembly 'merged\some.dll' was invalid.

So ILMerge was generating an assembly that strong name verification reported was delay-signed, and which sn.exe could not re-sign either. 

I shot an email off to Mike Barnett and he was very responsive and interested in helping.  He suggested that I try an ordinary .snk file (a keypair file not protected with a password) and that worked fine.

So how do you get ILMerge to work with .pfx files?  First extract the public key from the pfx file, then use that public key to have ILMerge delay-sign the merged assembly, then use sn.exe to re-sign.  Not too bad, really:

>sn -p some.pfx some.pub
>ilmerge /keyfile:some.pub /delaysign /out:merged\some.dll some.dll someother.dll
>sn -R merged\some.dll some.pfx
And now we have an ILMerge'd assembly, signed by your PFX file. Hurray!

Saturday, June 20, 2009

Help is coming for the Sreg/AX interop problem for OpenID

Just to get your mouth watering for DotNetOpenAuth v3.2...

V3.2 has a new "behaviors" plugin capability that lets RPs and OPs get additional functionality with very little effort.  For example, OPs can add PPID identifier support very easily with just a few lines of code. 

But of most interest I suspect is the sreg/AX interop behavior, which if activated in your web.config file (1 line), will cause an RP or an OP to see just sreg, yet on the wire do sreg and/or any of the 3 known AX attribute formats in order to maximize interoperability while keeping things extremely simple on the RP or the OP side.  So for example, you can prepare an sreg attribute request and send it to the OP, and if the OP only supports AX (and discovery can tell) then the sreg extension is automatically converted to AX in the right format and sent to the OP, then when the response comes back, the AX response is implicitly translated back to sreg so your web site can just deal with sreg.

If the OP doesn't advertise which attribute extensions and formats it supports, this optional DNOA behavior "spreads" the sreg extension to cover all possibilities to maximize the chance of getting the answer back that you want.  (Woot!)  No more hand writing all that interop code that makes the OpenID attribute extension story so embarrassing.  :)

The behavior does a similar trick for OPs, where all request formats look like sreg, and then when the response is sent out, it is converted back to whatever format the request came in.

You might be asking "Why are we making everything look like sreg?  Why not AX since it's newer/better?"  Fair question.  Sreg covers all the use cases for most OpenID sites at the moment, and since it's a subset of AX in almost every respect, an RP converting from sreg to AX implicitly does not lose any data.  And since it's a simpler extension, the object model to read/write it is simpler, making the RPs and OPs job simpler as well.  It seemed like the right thing for the times.  When AX finally gets its attribute type URI story together we can deprecate this behavior and we can all just use a single AX attribute format.

Friday, June 12, 2009

Reverse engineering ASP.NET Membership passwords and salts

I’m working on a project that was using the ASP.NET SQL Membership and I needed to remove the Membership provider from the system since we wanted more control over the user tables.  Our existing users had passwords that ASP.NET Membership had hashed and salted, and we needed to be able to maintain those user accounts, which means we have to be able to validate logins against the salted passwords. 

I understood how password salts work in general, but I could not find any documentation for how it was implemented exactly in ASP.NET Membership.  Fortunately it wasn’t too hard to figure out, and here is the method that can validate user passwords on the aspnet_Users table without using the Membership.ValidateUser method:

private static HashAlgorithm passwordHasher = HashAlgorithm.Create("SHA1");

private bool ValidateUser(string username, string password)
{
    var user = GlobalApplication.Database.Users.FirstOrDefault(u => u.UserName == username);
    if (user == null) return false;

    byte[] saltBytes = Convert.FromBase64String(user.Membership.PasswordSalt);
    byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
    byte[] bytesToHash = new byte[saltBytes.Length + passwordBytes.Length];
    saltBytes.CopyTo(bytesToHash, 0);
    passwordBytes.CopyTo(bytesToHash, saltBytes.Length);
    byte[] hash = passwordHasher.ComputeHash(bytesToHash);
    string base64Hash = Convert.ToBase64String(hash);
    return user.Membership.Password == base64Hash;
}