Another Password Regular Expression

Thursday, 16 July 2009 02:00 PM
by Coose

It’s out there thousands of times.  And here it is again.  The thing I couldn’t find in my Googling for a good regular expression was the “3 of 4 conditions”.  There was “all of 3” or “all of 4”, but I couldn’t find “3 of 4”.

So, here’s what I came up with:

^.*(?=.{10,})((?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*\W)|(?=.*[a-z])(?=.*\d)(?=.*\W)|(?=.*[A-Z])(?=.*\d)(?=.*\W)).*$

  • At least 10 characters
  • At least 3 of the following conditions
    • Lowercase alpha character
    • Uppercase alpha character
    • Number
    • Non-alphanumeric character

How it works:

Let’s start by looking at the regular expression required for ALL of the 4 conditions listed above:

^.*(?=.{10,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).*$

Broken up, the expression says this:

^ The beginning of the text…
.* …has zero or more of any characters…
(?=.{10,}) …where is followed by any character at least 10 times…
(?=.*[a-z]) …and where is followed by any character zero or more times which is followed by a lowercase letter…
(?=.*[A-Z]) …and where is followed by any character zero or more times which is followed by a uppercase letter…
(?=.*\d) …and where is followed by any character zero or  more times which is followed by a digit
(?=.*\W) …and where is followed by any character zero or more times which is followed by a non-word character…
.* …and is followed by any character zero or more times…
$ …then the text ends.

So, let’s break down the example input: this.IS.a.t34t.

^ Matches the betting of the text.
.* Matches anything zero or more times. (Call this “Match 0”)  In this case, it matches the entire text.
(?=.{10,}) Makes “Match 0” match all but the last 10 characters.  The expression up to this point is ^.*(?=.{10,}), which matches: this.IS.a.t34t.  It matches anything (Match 0) where there are 10 of any character to the right (“to the right” is a zero-width positive lookahead).
(?=.*[a-z]) Makes sure that “Match 0” is followed by anything or nothing, then a single lowercase character.  this.IS.a.t34t.  “Match 0” is still the red “this”, and the noncapturing lookahead is the blue “a”.
(?=.*[A-Z]) Makes sure that “Match 0” is followed by anything or nothing, then a single uppercase character. this.IS.a.t34t.  “Match 0” is still the red “this”, and the noncapturing lookahead is the blue “I”.
(?=.*\d) Makes sure that “Match 0” is followed by anything or nothing, then a single digit. this.IS.a.t34t.  “Match 0” is still the red “this”, and the noncapturing lookahead is the blue “3”.
(?=.*\W) Makes sure that “Match 0” is followed by anything or nothing, then a single non-word character.  this.IS.a.t34t.  “Match 0” is still the red “this” and the noncapturing lookahead is the blue “.”.
.* Now here’s a twist.  this.IS.a.t34t. “Match 0” is still the red “this” and the second “anything” match (“Match 1”) is the blue “.IS.a.t34t”.
$ …then the text ends.

To demonstrate a little bit, let’s name the matches.  So our expression becomes:

^(?'match_0'.*)(?=.{10,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W)(?'match_1'.*)$

Visualizing this:

Regular Expression Test Bench

So you can see that the first match is grouped and named “match_0” and the second match is grouped named “match_1”.

Ok.  If you’re still with me, that is how we make it match all of the aforementioned conditions.  Now how do we make it match 3 of the 4?  There is no simple declarative mechanism for “3 of 4”, so I used a combination. 

A combination of 3 of 4 items is only 4, so there’s not that much to do.  Remember, we need a combination, in which order is not important. We don’t care about order, just existence.  The formula for the number of items in a combination is

(n!)/(r!(nr)!)

where n is the number of items to choose from (4) and r is the number chosen (3). So (4!) / (3!(4 – 3)!) is 24 / 6 = 4.  There are only 4 combinations in a “3 of 4” scenario: (lowercase, uppercase, digit), (lowercase, uppercase, non-alphanumeric), (lowercase, digit, non-alphanumeric), and (uppercase, digit, non-alphanumeric).

As an aside: if the order of the options is important, it is called a permutation.  The formula for a permutation is

n! / (n – r)!

which gives us 24 / 1 = 24 permutations.  Since we need to use alternation in our regular expression, that’s a lot of typing: (lowercase, uppercase, digit) (lowercase, uppercase, non-alphanumeric) (lowercase, digit, uppercase) (lowercase, digit, non-alphanumeric) (lowercase, non-alphanumeric, uppercase) (lowercase, non-alphanumeric, digit) (uppercase,lowercase, digit) (uppercase,lowercase, non-alphanumeric) (uppercase, digit,lowercase) (uppercase, digit, non-alphanumeric) (uppercase, non-alphanumeric,lowercase) (uppercase, non-alphanumeric, digit) (digit,lowercase, uppercase) (digit,lowercase, non-alphanumeric) (digit, uppercase,lowercase) (digit, uppercase, non-alphanumeric) (digit, non-alphanumeric,lowercase) (digit, non-alphanumeric, uppercase) (non-alphanumeric,lowercase, uppercase) (non-alphanumeric,lowercase, digit) (non-alphanumeric, uppercase,lowercase) (non-alphanumeric, uppercase, digit) (non-alphanumeric, digit,lowercase) (non-alphanumeric, digit, uppercase).

So our expression to require all four conditions is:

^.*(?=.{10,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*\W).*$

Which states that each of the lookaheads must be true, (10 chars)(lower)(upper)(digit)(non-alphanumeric).  What we want is to make a statement like, “10 characters and at least 3 of my 4 conditions”, which with combinations becomes, “10 characters and at least one of my combinations.”  So it would look more like (10 chars)((c1)|(c2)|(c3)|(c4)).

Now replacing with our real regular expression syntax, our final expression is:

^.*(?=.{10,})((?=.*[a-z])(?=.*[A-Z])(?=.*\d)|(?=.*[a-z])(?=.*[A-Z])(?=.*\W)|(?=.*[a-z])(?=.*\d)(?=.*\W)|(?=.*[A-Z])(?=.*\d)(?=.*\W)).*$

With the first combination in red, the second combination in blue, the third combination in orange, and the fourth combination in green.

In my next post, I’ll post my Regular Expression Test Bench.  There are a few of these online also, but I needed one with better visualization.  I needed to see the matches and captures, and highlight each of them in the text independently on demand.  Here is a screenshot of the app.  It’s being deployed as a Click-Once app, so I’ll post the URL soon. :)

Regular Expression Test Bench

Comment on this
Development
|

Encrypting Web.config Connection Strings

Wednesday, 15 July 2009 01:33 PM
by Coose

So, there’s a lot of explanation about this, and it’s all quite confusing.  Here’s a simple way I encrypted the web.config connection strings and how to use it from code.

I run the following snip in LINQPad (great tool…get it).

    1 Configuration config = ConfigurationManager

    2     .OpenMappedExeConfiguration(

    3     new ExeConfigurationFileMap() {

    4         ExeConfigFilename = @"c:\mywebsite\web.config"

    5     },

    6     ConfigurationUserLevel.None

    7 );

    8 

    9 config

   10     .Sections["connectionStrings"]

   11     .SectionInformation

   12     .ProtectSection("DataProtectionConfigurationProvider");

   13 

   14 config.Save();

In LINQPad, you will need to add a reference to System.Configuration.dll, and namespace imports for System.Configuration.

On line 12, you can use the Data Protection API provider (“DataProtectionConfigurationProvider”), or the RSA API Provider(“RSAProtectedConfigurationProvider”).

This makes your web.config a little messy:

<connectionStrings configProtectionProvider="DataProtectionConfigurationProvider">

<EncryptedData>

  <CipherData>

   <CipherValue>AQAAANCMnd8BFdERjHoAw…JG5PT1MoeB2hoxuO8=</CipherValue>

  </CipherData>

</EncryptedData>

</connectionStrings>

But fortunately I don’t have to change connection strings often.

To access the encrypted connection strings from code, you don’t have to do anything different.  That’s right: you don’t have to do anything different.  Use your normal connection string code, and it will transparently retrieve your connection string.

To change your connection strings, you have to decrypt them, modify them, then re-encrypt them.  Again, in LINQPad:

    1 Configuration config = ConfigurationManager

    2     .OpenMappedExeConfiguration(

    3     new ExeConfigurationFileMap() {

    4         ExeConfigFilename = @"c:\mywebsite\web.config"

    5     },

    6     ConfigurationUserLevel.None

    7 );

    8 

    9 config

   10     .Sections["connectionStrings"]

   11     .SectionInformation

   12     .UnProtectSection();

   13 

   14 config.Save();

 

 

 

You see that only line 12 changed.  The provider used to protect the section is encoded in the cipher data, so you don’t need to provide one.

 

So, when your web site is ready to go live, run the above snippet and you will encrypt your connection string without any code modifications.

 

Update: 20 July 2007

You could also just do all of this via command line, and not have to worry about an exe or LINQPad.

To encrypt, aspnet_regiis –pef connectionStrings c:\mywebsite DataProtectionConfigurationProvider.
To decrpty, aspnet_regiis –pdf connectionStrings c:\mywebsite

Comment on this
Development

Making ASP.NET Development Server Listen for Remote Connections

Friday, 17 April 2009 02:51 PM
by Coose

My previous posts here and here talked about compiling Cassini and using it from Visual Studio.  After all that, I found that Cassini doesn’t understand NTLM, and writing it is complicated.  So what to do now?

More...

Comment on this
Development
|

Custom Compiled Cassini from Visual Studio

Friday, 17 April 2009 01:13 PM
by Coose

In my previous post, I described compiling a custom version of Cassini that could listen to external requests, not just loopback.  Now, I want to use that version of Cassini to debug from Visual Studio.  The problem is that the command lines are different.  Visual Studio uses Webdev.WebServer.exe, and issues argument in the format

/port:1234 /path:c:\temp /vpath:/test

Cassini expects arguments in the format

apppath port virtroot

So, in main.cs, I have modified the Main function as so:

   50 public MainForm(String[] args) {

   51     //_portString = "80";

   52     //_virtRoot = "/";

   53     //_appPath = string.Empty;

   54 

   55     // look for arguments in the form of /port:1234, or /path:"abcdefg" or /vpath:/

   56     foreach (string arg in args)

   57     {

   58         if (arg.StartsWith("/port:", StringComparison.OrdinalIgnoreCase)) _portString = arg.Substring(6).Trim();

   59         if (arg.StartsWith("/path:", StringComparison.OrdinalIgnoreCase)) _appPath = arg.Substring(6).Trim();

   60         if (arg.StartsWith("/vpath:", StringComparison.OrdinalIgnoreCase)) _virtRoot = arg.Substring(7).Trim();

   61     }

   62 

   63     try {

   64         if (string.IsNullOrEmpty(_appPath) && args.Length >= 1) _appPath = args[0];

   65         if (string.IsNullOrEmpty(_portString) && args.Length >= 2) _portString = args[1];

   66         if (string.IsNullOrEmpty(_virtRoot) && args.Length >= 3) _virtRoot = args[2];

   67     }

   68     catch {

   69     }

   70 

   71     InitializeForm();

   72 

   73     if (string.IsNullOrEmpty(_appPath)) {

   74         appDirTextBox.Focus();

   75         return;

   76     }

   77 

   78     Start();

   79 }

Now, the application will accept command line arguments in either form.

I copy this cassini-v35.exe to C:\Program Files\Common Files\microsoft shared\DevServer\9.0 and rename it webdev.webserver.exe (making a backup of the old webdev.webserver.exe of course), and now I can launch my custom Cassini from Visual Studio.

Comment on this
Development
| |

Cassini only works on Loopback

Friday, 17 April 2009 12:41 PM
by Coose

I needed a simple ASP.NET web server scenario that I could debug and turn on and off when required.  Reconfiguring IIS is a real pain to do that with, so I tried debugging my scenario with Cassini (also called ASP.NET Development Server, and Visual Studio Web Developer Server, etc).

All was fine until I tried accessing that web site from a remote machine.  Surely they didn’t write Cassini so that it listens on loopback only?  Could they?

They did.

More...

Comment on this
Development