Basic Authentication With ColdFusion

Here is an Application.cfc which implements HTTP Basic Authentication:

<cfcomponent output="false">

<cffunction name="onRequestStart" returnType="boolean" output="false">
<cfargument type="String" name="targetPage" required=true/>

<cfset var authHeader = GetPageContext().getRequest().getHeader("Authorization") />
<cfset var authString = "" />

<cfsetting showDebugOutput="false" />

<cfif IsDefined("authHeader")>
<cfset authString = ToString(BinaryDecode(ListLast(authHeader, " "),"Base64")) />
<cfif GetToken(authString,1,":") eq "username" AND GetToken(authString,2,":") eq "password">
<cfreturn true />
</cfif>
</cfif>

<cfheader statusCode="401" statusText="UNAUTHORIZED" />
<cfheader name="WWW-Authenticate" value="Basic realm=""MXUnit""" />
<cfreturn false />

</cffunction>

</cfcomponent>

The above example has the username and password hard coded as "username" and "password", but it can easily be modified to look up credentials where ever you may have them stored. One thing to note is that I'm using GetPageContext() to get the Authorization header. In my first attempt I was using GetHttpRequestData() which worked fine for normal HTTP requests, but was causing SOAP requests to bomb out. I'm not sure what the issue was because, reading the ColdFusion docs, it seems you should be able to use GetHttpRequestData with SOAP requests:

GetHttpRequestData

Description

Makes HTTP request headers and body available to CFML pages. Useful for capturing SOAP request data, which can be delivered in an HTTP header.

So, why might you want to use this? Well, I'm using it to secure an mxunit RemoteFacade.cfc on a shared server that I don't administer. (The RemoteFacade.cfc is used by the mxunit Eclipse plugin, which supports basic authentication.)

One thing to keep in mind about Basic Authentication, it is only secure if you use it over SSL as the username is password are sent over the wire in clear text. So if you do use this approach you may want to put an additional check in your Application.cfc to force secure connections.

Comments
Sami Hoda's Gravatar Nice
# Posted By Sami Hoda | 8/14/08 12:09 AM
Adam Tuttle's Gravatar Nice work, Nathan. Hopefully I'll remember where to find this when I need to use it. ;)
# Posted By Adam Tuttle | 8/14/08 9:34 AM
Ben Nadel's Gravatar Interesting stuff. Do you have to do anything else to have the credentials passed over? I haven't use this technique, but I remember back when I had to integrate with NT login, we had to set a property in IIS (I think) that would pass login info via CGI. Anything you need to set for this to work?
# Posted By Ben Nadel | 8/14/08 1:03 PM
Nathan Mische's Gravatar @Ben, the client handles sending the credentials to the server via the Authorization header. As far as I know you don't have to do anything on the server for this to work. That being said, if you already have basic, digest, or NTLM authorization set up, this may not work. (The web server will most likely intercept the request before it gets to CF.)
# Posted By Nathan Mische | 8/14/08 1:49 PM
Ben Nadel's Gravatar @Nathan,

Sounds good. I'll have to play around with this stuff.
# Posted By Ben Nadel | 8/14/08 1:52 PM
Paul's Gravatar Hi,

Sorry if this is a dumb question. But does this mean the CF now supports Basic Server Authentication? Its just that when i had to configure barclays payment solution with a few years back with CF6; Basic Server Authentication was not supported by CF. I had to use PERL.
# Posted By Paul | 11/17/08 3:55 AM
david's Gravatar I have site that authentication works. southernfarmsupply.com
Then i have test server on local network where I have problem for the exact same site to make authentication.

i know is something silly like variable for the server/location or configuring the CF,or case sensitivity on apache2 linux server vs iis server.

On the apache server where i have problem the login form gets completely skipped and i get unauthorized page.

Please help.

this should be a login form:

<body>
<cfset URLTMP="http://"; &"#CGI.Server_name#" & ":" & "#cgi.SERVER_PORT#" & "#CGI.Script_name#">
<cfif CGI.QUERY_STRING is not "">
<CFset URLFIN=URLTMP & "?#CGI.QUERY_STRING#">
<cfelse>
<CFset URLFIN=URLTMP>
</cfif>
<H2>Please Log In</H2>
<cfoutput>
<form action="#urlfin#" method="Post">
<table>
<tr>
<td>username:</td>
<td><input type="text" name="j_username"></td>
</tr>
<tr>
<td>password:</td>
<td><input type="password" name="j_password"></td>
</tr>
</table>
<br>
<input type="submit" value="Log In">
</form>
</cfoutput>



</body>
</html>
# Posted By david | 11/30/09 12:07 PM
Adam Tuttle's Gravatar There's a bug in your code samples, Nathan. ;)

Consider someone with this password: gd$#fds:fdsa3!

It has a colon in it, so your use of GetToken(..., 2, ":") will result in the user's password appearing to be "gd$#fds". Instead you should use ListRest() (or some other solution), which returns everything after the first list element has been removed, including the list delimiters.
# Posted By Adam Tuttle | 12/29/12 2:22 PM
BlogCFC was created by Raymond Camden. This blog is running version 5.8.001.