<?php // ۞// text { encoding:utf-8 ; bom:no ; linebreaks:unix ; tabs:4sp ; }
if (realpath ($_SERVER['SCRIPT_FILENAME'] ) == realpath ( __FILE__ )) {
@include $_SERVER['DOCUMENT_ROOT'].'/inc/source-dump.php';
source_dump(__FILE__); }
/*
pajamas
modular authentication system
For full details, usage instructions, etc, see the accomanying readme.
If you you got this without a readme, check out the link below.
If you need help, mail me @ corz.org, or if you think a solution to your
issue would be valuable to others, drop a comment on the pajamas page..
https://corz.org/server/security/pajamas.php
Have fun!
;o)
ps.. Big thanks to PCheese for all the help with the OOP.
d00D! I get it now! And I hope you like where I took it. ;o)
(c) 2004->tomorrow! ~ cor + corz.org ;o)
Please view the license for this free software, here:
https://corz.org/free-scripts-licence.nfo
*/
/*
pajamas authentication..
*/
class pajamas {
/*
version
Currently, we have the bare bones of the thing, and it works great!
There may yet be bugs, and all bug reports are wholeheartedly welcomed.
*/
var $_version = '0.3';
/* public properties.. */
/*
default module
(string) name of module file (minus .php extension)
current choices are 'plain' or 'pj' (the best)
If, for some insane reason, you don't have access to a JavaScript-
capable browser, use 'plain', otherwise, use 'pj'.
the plain module can be configured in exactly the same way as
the pajamas module, and has many of its features, too; sessions, IP
check, time-out, etc., the only difference being that the password is
sent over the wire in plain text.
Though unlike HTTP basic authentication, which send the password with
every single request, with the plain module, the password travels over
the wires one time only.
*/
var $_default_module = 'pj';
/*
password
(string) default: 'password';
a quick and dirty way to store your password..
or you could keep it in a database, or include from another file,.
include '/some/other/place/config.php'; and set it externally..
$auth->_login_password = 'MyPassword';
Passwords are case-sensitive.
*/
var $_login_password = 'password';
/*
IP address check?
boolean (true/false) default: true;
normally, we check the IP address of the authorising browser. However, if the user
is behind a proxy farm (very unusual), this will break his session, as his IP will
change with (possibly) each request. If you have users behind proxy farms, (or you
are) set this to false, or else advise them to use *yet another* proxy (two proxies).
*/
var $_check_ip = true;
/*
do time-out?
boolean default: true;
we can specify a time-out for the session. if you set this to false,
the session is live until the client's browser is quit, or they log out.
*/
var $_do_time_out = true;
/*
time-out
integer (in minutes) default: 60;
an hour is reasonable, anything goes. the demo uses 0.5 (30 seconds)
*/
var $_session_time = 60;
/*
big luser
integer (max failed attempts) default: 10;
they tried and tried, but it just isn't happening. Or else they are taking the p*ss.
A script perhaps, some brute force. Whatever, it would probably be best for everyone
if we halted them in their tracks after how many failed login attempts?
*/
var $_big_luser = 10;
/*
kick bad users?
boolean (true/false) default: false;
optionally we can prevent even correct logins from browsers that repeatedly sent bad logins..
If you set this to true, after($_big_luser) failed login attempts, the property
"$auth->_bad_user" will be set to true. Now, even a correct login will fail to authenticate.
You can check for bad users, and then do what you like with them..
if ($auth->_bad_user) { die('go away!');
If you leave kick_bad_users set to false, a correct login will override all previous bad logins.
The idea is, someone may be attempting to login from your terminal, and fail, so they receive
a message informing them of the futility of it, *hopefully* they will stop now. If the *real*
admin comes along, he should be able to log straight in, and shouldn't have the inconvenience
of restarting the browser just because some twat was fooling around. But you can disable this
behaviour by simply setting this to true.
*/
var $_kick_bad_users = false;
/*
show error messages?
boolean (true/false) default: true;
pj generates some messages for the various error conditions, you can use these however
you like, and latest message is always in "_auth_message"
If you like, you can have pj display these messages just above the login form,
so the user is aware that their password was incorrect, or whatever..
*/
var $_do_messages = true;
/*
create containing forms?
boolean (true/false) default: true;
If you are already inside a form, set this to false to avoid nesting forms,
which will break xhtml valiadation, among other things (including the md5)..
$auth->_createForms = false;
Remember you can also pass "true" to your form input function, to have a
simple, div-less output, like this..
echo $auth->getLoginForm(true);
*/
var $_createForms = true;
/*
autocomplete="off"
boolean (true/false) default: true; (doesn't validate, but hey!)
a good, mostly supported proprietary Internet Explorer property.
This will break strict xhtml validation (which is annoying), but you may feel
that it's worth it. With this set to true, browsers will not annoy you to try
and save the password (which, at least with the 'pj' module, is a one-shot
mish-mash that will become useless the instant you logout).
It will only break your xhtml validation until you login, of course.
Set this to true to add 'autocomplete="off"' to your password field. TADA!
One of the rare occasions where Internet Explorer leads the way! If you are
obsessed with strict xhtml 1.0 validation, screw your users and set this to
false.
btw: if you known an xhtml-friendly way to do this, MAIL ME! ;o)
*/
var $_no_autocomplete = true;
/*
code loaction.
(string) default: '';
Some modules may require included code.
In "pj", this sets the default location of javascript MD5 functions file and
will be used to create the script tag that includes the JavaScript MD5
functions on your page, like this..
echo $auth->getAuthCode();
You can override the location by setting this..
$auth->_code_location = 'inc/md5.js';
*before* you echo the code. relative or absolute paths are fine, just like a
regular javascript include.
*/
var $_code_location = '';
/*
a simple error catcher.
boolean (true/false) default: true;
session errors of level "E_NOTICE" (type 8) will be caught and stored,
rather than spew onto your page. use..
echo $auth->getErrors();
to see them, or pipe that somewhere else. essentially this saves having
your pages all messed up when you are testing your pj implementation on
a server with error level E_ALL set (all development servers, yeah?),
mainly for "session already started" type errors. It was annoying!
we throw errors into a global variable because a) I use this system for
errors anyway, (my debug script throws me a pop-up if it finds anything in
$GLOBALS['errors'], and b) variables inside error handlers are a disaster!
*/
var $_error_catcher = true;
/*
Private properties.
DO NOT CHANGE THESE.
You shouldn't change anything above either;
set it externally like so..
$auth->_do_time_out = false;
*/
var $_auth_message = '';
var $_auth_module = ''; // a pointer to *real* auth class
var $_bad_user = false;
var $_default_uid = 'pajamas';
var $_is_authenticated = null; // start out in unknown (unset) state
var $_module_loaded = false;
var $_modules_path = 'modules/';
var $_interface = 'advanced'; // 'advanced' or 'simple'
// constructor..
function pajamas ($uniqueid='') {
if (!empty($uniqueid) and ctype_alnum($uniqueid)) {
$this->_unique_id = $uniqueid;
} else {
$this->_unique_id = $this->_default_uid;
}
if ($this->_error_catcher) {
$this->startErrorHandler();
}
}
function authModule() {
include $this->_modules_path.$this->_default_module.'.php';
$this->_auth_module = new authModule($this->_unique_id);
// setup its preferences..
// (we could perhaps check module's capabilities and only set those)
if ($this->_interface != 'simple') {
$this->_auth_module->_login_password = $this->_login_password;
$this->_auth_module->_check_ip = $this->_check_ip;
$this->_auth_module->_do_time_out = $this->_do_time_out;
$this->_auth_module->_session_time = $this->_session_time;
$this->_auth_module->_big_luser = $this->_big_luser;
$this->_auth_module->_kick_bad_users = $this->_kick_bad_users;
$this->_auth_module->_do_messages = $this->_do_messages;
$this->_auth_module->_createForms = $this->_createForms;
$this->_auth_module->_no_autocomplete = $this->_no_autocomplete;
}
$this->_module_loaded = true;
}
function auth_user() {
if (!$this->_module_loaded) { $this->authModule(); }
if ($this->_is_authenticated) { return true; }
$auth_status = $this->_auth_module->auth_user();
$this->_auth_message = $this->_auth_module->_auth_message;
if ($auth_status) {
$this->_is_authenticated = true;
return true;
} else {
$this->_is_authenticated = false;
return false;
}
}
function getAuthCode() {
// this will need to load before authentication,
// so we set it here, and now overriding works as expected.
$this->_auth_module->_code_location = $this->_code_location;
$html = $this->_auth_module->getAuthCode();
if (!empty($html)) { return $html; }
else { return ''; }
}
function getLoginForm($simple=false) {
return $this->_auth_module->getLoginForm($simple);
}
function getLogoutButton($simple=false) {
return $this->_auth_module->getLogoutButton($simple);
}
function getSelf() {
return $_SERVER['SCRIPT_NAME'];
}
function getBadUser() {
return $this->_auth_module->_bad_user;
}
function remainingTime() {
if ($this->_do_time_out) {
$now = explode(' ',microtime());
$time = $now[1].substr($now[0],2,2);
settype($time, 'double'); // 100th/second..
return (($this->_session_time * 6000) - ($time - $_SESSION['auth'.$this->_unique_id]['login_at'])) / 100;
} else { return false; }
}
/*
a simple session error catcher..
*/
function getErrors() {
if (!empty($GLOBALS['errors']['pajamas'])) {
return $GLOBALS['errors']['pajamas'];
}
}
function startErrorHandler() {
set_error_handler(array($this, 'handle_error'));
}
function handle_error($type, $string, $file, $line, $vars) {
switch (TRUE) {
case ($type == 8 and stristr($string, 'session')): // doesn't look so clever with only one case!
if (empty($GLOBALS['errors']['pajamas'])) { $GLOBALS['errors']['pajamas'] = ''; }
$GLOBALS['errors']['pajamas'] .= 'NOTICE! session error on line '.$line.' of '.$file.': '.$string;
return true;
break; // *ahem*
default:
return false; // better let php handle this one.
}
}
} // end class pajamas()
class pajamasSimple extends pajamas {
function pajamasSimple($uniqueid='') {
if (!empty($uniqueid) and strstr($uniqueid, '-')) {
$simple_prefs = explode('-', $uniqueid);
$uniqueid = trim($simple_prefs[0]);
if (!empty($simple_prefs[1])) { $my_module = trim($simple_prefs[1]); }
}
parent::pajamas($uniqueid);
$this->_interface = 'simple';
if (!empty($my_module)) { $this->_default_module = $my_module; }
if (!$this->_module_loaded) { $this->authModule(); }
if (!empty($this->_auth_module->_code_location)) {
$this->_code_location = $this->_auth_module->_code_location;
}
echo $this->getAuthCode();
if ($this->_auth_module->auth_user()) {
echo $this->_auth_module->getLogoutButton();
} else {
echo $this->_auth_module->getLoginForm();
}
}
}
/*
version history
0.3
fixed bug, not passing variables through to getLogoutButton() and getLoginForm()
0.2
first public release of pajamas engine
0.1
basic authentication module loader. almost works.
*/
?>