Generating Random Passwords In ColdFusion Based On Sets Of Valid Characters

Posted January 24, 2007 at 3:25 PM

Tags: ColdFusion

Richard White over on CF-Talk asked about generating random passwords in ColdFusion based on his particular business rules. These rules included:

  1. Must be exactly 8 characters in length
  2. Must have at least 1 number
  3. Must have at least 1 uppercase letter
  4. Must have at least 1 lower case letter

Tom Chiverton suggested using ASCII values and randomization, which is a great suggestion. In fact, it is one that I have used myself many times in the past. However, I created this demo based on explicitly defined sets of character data as I feel that it has some benefits; it is more readable and allows for more flexibility in what the character sets are (just my opinion).

That being said, here is the algorithm I came up with in ColdFusion to generate the random passwords:

 Launch code in new window » Download code as text file »

  • <!---
  • We have to start out be defining what the sets of valid
  • character data are. While this might not look elegant,
  • notice that it gives a LOT of power over what the sets
  • are without writing a whole lot of code or "condition"
  • statements.
  • --->
  •  
  • <!--- Set up available lower case values. --->
  • <cfset strLowerCaseAlpha = "abcdefghijklmnopqrstuvwxyz" />
  •  
  • <!---
  • Set up available upper case values. In this instance, we
  • want the upper case to correspond to the lower case, so
  • we are leveraging that character set.
  • --->
  • <cfset strUpperCaseAlpha = UCase( strLowerCaseAlpha ) />
  •  
  • <!--- Set up available numbers. --->
  • <cfset strNumbers = "0123456789" />
  •  
  • <!--- Set up additional valid password chars. --->
  • <cfset strOtherChars = "~!@##$%^&*" />
  •  
  • <!---
  • When selecting random value, we want to be able to easily
  • choose from the entire set. To this effect, we are going
  • to concatenate all the previous valid character sets.
  • --->
  • <cfset strAllValidChars = (
  • strLowerCaseAlpha &
  • strUpperCaseAlpha &
  • strNumbers &
  • strOtherChars
  • ) />
  •  
  •  
  • <!---
  • Create an array to contain the password ( think of a
  • string as an array of character).
  • --->
  • <cfset arrPassword = ArrayNew( 1 ) />
  •  
  •  
  • <!---
  • When creating a password, there are certain rules that we
  • need to follow (as deemed by the business logic). That is,
  • the password must:
  •  
  • - must be exactly 8 characters in length
  • - must have at least 1 number
  • - must have at least 1 uppercase letter
  • - must have at least 1 lower case letter
  • --->
  •  
  •  
  • <!--- Select the random number from our number set. --->
  • <cfset arrPassword[ 1 ] = Mid(
  • strNumbers,
  • RandRange( 1, Len( strNumbers ) ),
  • 1
  • ) />
  •  
  • <!--- Select the random letter from our lower case set. --->
  • <cfset arrPassword[ 2 ] = Mid(
  • strLowerCaseAlpha,
  • RandRange( 1, Len( strLowerCaseAlpha ) ),
  • 1
  • ) />
  •  
  • <!--- Select the random letter from our upper case set. --->
  • <cfset arrPassword[ 3 ] = Mid(
  • strUpperCaseAlpha,
  • RandRange( 1, Len( strUpperCaseAlpha ) ),
  • 1
  • ) />
  •  
  •  
  • <!---
  • ASSERT: At this time, we have satisfied the character
  • requirements of the password, but NOT the length
  • requirement. In order to do that, we must add more
  • random characters to make up a proper length.
  • --->
  •  
  •  
  • <!--- Create rest of the password. --->
  • <cfloop
  • index="intChar"
  • from="#(ArrayLen( arrPassword ) + 1)#"
  • to="8"
  • step="1">
  •  
  • <!---
  • Pick random value. For this character, we can choose
  • from the entire set of valid characters.
  • --->
  • <cfset arrPassword[ intChar ] = Mid(
  • strAllValidChars,
  • RandRange( 1, Len( strAllValidChars ) ),
  • 1
  • ) />
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Now, we have an array that has the proper number of
  • characters and fits the business rules. But, we don't
  • always want the first three characters to be of the
  • same order (by type). Therefore, let's use the Java
  • Collections utility class to shuffle this array into
  • a "random" order.
  •  
  • If you are not comfortable using the Java class, you
  • can create your own shuffle algorithm.
  • --->
  • <cfset CreateObject( "java", "java.util.Collections" ).Shuffle(
  • arrPassword
  • ) />
  •  
  •  
  • <!---
  • We now have a randomly shuffled array. Now, we just need
  • to join all the characters into a single string. We can
  • do this by converting the array to a list and then just
  • providing no delimiters (empty string delimiter).
  • --->
  • <cfset strPassword = ArrayToList(
  • arrPassword,
  • ""
  • ) />

I ran that a bunch of times and here is the list of passwords it created:

RQ5nYqR1
QL3!g8TD
*dZWd5rP
I5Jvna!5
MqG%T38b
IgD1BLq^
!~51gpZC

As you can see, it is quite random (at least for my powers of perception) and each one complies with the business rules laid out. Of course, if your business rules change, you would have to update the algorithm as needed (and anyone let me know if they want to see a demo of that (based on their business rules)).

Download Code Snippet ZIP File

Comments (8)  |  Post Comment  |  Ask Ben  |  Permalink  |  Other Searches  |  Print Page




Keep your Web site content fresh and your overhead costs low with Savvy Content Manager

Reader Comments

Not that it matters but you should remove the letters "o", "i" and "s" from the strLowerCaseAlpha variable so the end user won't confuse their uppercase values with 0, 1 and 5.

Posted by Sam Mitchell on Jan 24, 2007 at 4:47 PM


Sam,

While I am not sure I am completely on board with that decision (but I do completely understand it), your comment goes quite nicely with the idea behind using character sets rather than spans of ASCII values. By using a set of characters, it makes it so easy to pick and choose which characters don't make the cut.

Nicely done.

Posted by Ben Nadel on Jan 24, 2007 at 4:53 PM


I'd second Sam's comment but also include the lower case L from exclusion as on some fonts that looks the same as a 1 or capital I, not that I've ever confused them before ;)

Posted by Phil Duba on Jan 24, 2007 at 5:07 PM


When I first responded, I forgot that we were GENERATING passwords and was thinking just about passwords in general, which is why I was hesitant to get on board with the character restricitions. But now that I remember we are dealing with generating (hey, I have a lot on my mind), I totally agree. No need to confuse the end user.

Posted by Ben Nadel on Jan 24, 2007 at 5:22 PM


Thanks a ton for your code. I was looking to create a cfscript function to do this so I did the simple mods on what you wrote to make it a function. Here is the code I created from the code in the original comment.

<cfscript>
/** generatePassword - this function will produce a randomly genereated password
* that is 8 characters long and includes at least one number, lower case letter,
* and upper case letter
*
* none cfscript code found at http://www.bennadel.com/blog/488-Generating-Random-Passwords-In-ColdFusion-Based-On-Sets-Of-Valid-Characters.htm
* adapted to cfscript code by Andy Marks
*
* @return the generated password
*/
function generatePassword()
{
var strLowerCaseAlpha = "abcdefghijklmnopqrstuvwxyz";
var strUpperCaseAlpha = UCase( strLowerCaseAlpha );
var strNumbers = "0123456789";
var strOtherChars = "!@##$%&*";
var strAllValidChars = (strLowerCaseAlpha & strUpperCaseAlpha & strNumbers & strOtherChars);
var arrPassword = ArrayNew(1);
var strPassword = "";
var intChar = 0;

arrPassword[ 1 ] = Mid(strNumbers,RandRange( 1, Len( strNumbers ) ),1);
arrPassword[ 2 ] = Mid(strLowerCaseAlpha,RandRange( 1, Len( strLowerCaseAlpha ) ),1);
arrPassword[ 3 ] = Mid(strUpperCaseAlpha,RandRange( 1, Len( strUpperCaseAlpha ) ),1);
for(intChar = ArrayLen(arrPassword) + 1; intChar LTE 8; intChar = intChar + 1)
{
arrPassword[ intChar ] = Mid(strAllValidChars,RandRange( 1, Len( strAllValidChars ) ),1);
}
CreateObject( "java", "java.util.Collections" ).Shuffle(arrPassword);
strPassword = ArrayToList(arrPassword,"");
return strPassword;
}
</cfscript>

Posted by Andy on May 1, 2007 at 3:05 PM


Looks good dude. The only modification I would suggest is to pass in a password length (gt 4) to the function. Right now, you have hard coded 8. It might be a nice little dynamic feature. But looks good.

Posted by Ben Nadel on May 1, 2007 at 3:19 PM


Freakin' awesome dude! Love it and using it! You helped a bunch!

Posted by Chris Chin on May 3, 2007 at 7:09 PM


Player. Glad to help. Hit me up if you get stuck anywhere.

Posted by Ben Nadel on May 3, 2007 at 7:28 PM


Post Comment  |  Ask Ben


Home   |   Web Log   |   ColdFusion   |   Projects   |   Resume   |   Job Form   |   Search   |   Contact
Epicenter Consulting - Custom Software Solutions for Business Evolution HostMySite.com - The Leader In ColdFusion Hosting