Archive of UserLand's first discussion group, started October 5, 1998.

#security Script Supports Realms

Author:Alan German
Posted:4/10/1999; 3:58:41 PM
Topic:#security Script Supports Realms
Msg #:4941
Prev/Next:4940 / 4942

I like the idea of membership that Frontier provides. I also like the cookie approach once authentication with a username and password has been established. But I had a situation where I needed to manage user accounts without the need or desire for users to "sign-up" to a website. I define the accounts/passwords and hand them out to users as they are "authorized."

With the help of the Frontier Users list participants, I came up with a #security script that performs basic http authentication for a "realm" (as is typical in most web servers) without the email loop, yet it takes full advantage of the membership stuff.

The version reprinted here was revised 4.12.99, 9.25am ET. The local assignment to members (the first line of the script) is now wrapped in a try. This allows the script to exist in the website with or without the #members item. If the #members item is not present, no authentication is required for access. This makes it easy to start and top authentication on a site.

This script has not been tested in any environment other than the one it was developed for. This "environment" consists of a website GDB in the WWW folder in the Guest Databases folder. The name of the GDB, the name of the user group in members.root, the name of the cookie, and the name of the "realm" (or match string in the path) are all the same.

That is, if I have a GDB named "foo.root", the #members item in that database is "foo". There is a group table in members.root named "foo", and the name of the cookie for that group is "foo". The path to the GDB also must contain "foo". I don't know how virtual hosting or monkeying with #urls tables will affect this.

This script is not warranted in any way. If it breaks, you get to keep both pieces. ;-)

Install this script in a script object named #security at the root of your GDB website:

local (members);
try {
	members = address(parentOf (this^)+".[\"#members"]")^}
else {
	return (true)};
on unauthorized () {
	code = 401;
	responseHeaders.["WWW-Authenticate"] = "Basic realm=\"" + string.urlEncode (members) + """;
	responseBody = webserver.util.buildErrorPage ("401 UNAUTHORIZED", "You must be authenticated before accessing this service");
	scriptError ("!return")};
on hasGoodCookie () { //modified copy from mR.members.checkMembership
	if not defined (requestHeaders.cookies) {
		return (false)};
	local (myCookieName = adrmembers^.cookieName);
	local (innerCaseCookieName = string.innerCaseName (myCookieName));
	if defined (requestHeaders.cookies.[innerCaseCookieName]) {
		myCookieName = innerCaseCookieName}
	else {
		if not defined (requestHeaders.cookies.[myCookieName]) {
			return (false)}};
	local (s = string.urlDecode (requestHeaders.cookies.[myCookieName]));
	local (mailaddress = string.nthField (s, "\t", 1));
	local (password = string.nthField (s, "\t", 2));
	local (adrmember = @adrmembers^.users.[mailaddress]);
	bundle { //set adrmember thru callback, if it's defined
		try {
			local (adrcallback = @adrmembers^.callbacks.getMemberTableAddress);
			if defined (adrcallback^) {
				adrmember = adrcallback^ (mailaddress)}}};
	if not defined (adrmember^) {
		return (false)};
	if defined (adrmember^.blocked) {
		if adrmember^.blocked {
			scriptError ("The account, \"" + mailaddress + "" has been blocked from access to this service.")}};
	if not defined (adrmember^.password) {
		return (false)};
	return (string.upper (adrmember^.password) == string.upper (password))};
local (adrMembers = mainResponder.members.getMembershipTable (members));
if not hasGoodCookie () {
	if not webserver.util.parseAuth (parentOf (client)) {
		unauthorized ()};
	try {
		mainResponder.members.getMemberTableWithPassword (members, username, password)}
	else {
		unauthorized ()};
	mainResponder.members.setCookie (username, password, adrmembers, parentOf (client));
	if not defined (requestHeaders.cookies) {
		new (tableType, @requestHeaders.cookies)};
	local (myCookieName = adrmembers^.cookieName);
	local (innerCaseCookieName = string.innerCaseName (myCookieName));
	with adrmembers^ {
		requestHeaders.cookies.[innerCaseCookieName] = string.urlEncode (username + "\t" + password)}};
return (true)

This page was archived on 6/13/2001; 4:49:18 PM.

© Copyright 1998-2001 UserLand Software, Inc.