Chapter 5. Authentication with passwords

The next step is to password protect parts of the admin site.

What we want, is to do user authentication against the LDAP database installed previously. To do this, I need to enable the LDAP in PHP4, as I will be using some custom php4 scripts to authenticate users.


apt-get install php4-ldap

When this has been accomplished, we can now enable LDAP authentication for parts of the admin-site. Basically, I want to make the scripts that changes the passwords for authenticated users only.

I have decided to place all files associated with this system in the /system directory of the admin site. All files in this directory will be using the login functions.

First up we have the index.php4, which is the main file of the login system. If You are not logged in, You will be presented with a form to do so. If You are logged in, then You will be redirected to the page where You can change passwords.


<?
// index.php4 - login form
session_start();
if (session_is_registered("SESSION")) {
	header("Location: /system/enter_passwords.php4");
	exit();
}
?>
<html>
<head>
<title>admin site login form</title>
</head>
<body>
<h3 align="center">Admin site login form</h3>
<hr>

<center>
<table border="1" cellspacing="5" cellpadding="5">
<form action="login.php4" method="post">
<tr>
<td>Brugernavn</td>
<td><input type="text" size="15" name="f_user"></td>
</tr>
<tr>
<td>Password</td>
<td><input type="password" size="15" name="f_pass"></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" name="submit" value="Log ind"></td>
</tr>
</form>
</table>
</center>
</body>
</html>

Second we have the login.php4 file. This is the file that does the actual login, and sets up a session for You to test on later.


<?
// login.php4 - validation of form

// include some specialized functions.

include("./functions.inc");


// authenticate using the form variables
$status = authenticate($_POST["f_user"], $_POST["f_pass"]);

if ($status == 1) {
	// initiate session
	session_start();

	// register session variables
	session_register("SESSION");

	// include username and password
	session_register("SESSION_UNAME");
	$SESSION_UNAME=$f_user;
	$SESSION_PASS=$f_pass;

	// go to the main page
	header("Location: /system/enter_passwords.php4");
	exit();
} else {
	// user check failed
	header("Location: /system/error.php4?error=$status");
	exit();
}

?>

The login.php4 script used an include file functions.inc, which actually could be split into the files using them, but I'm a bit lazy when I need to do something several places.


<?

// variable
$host_dn   = "dc=abode,dc=dk";
$ou_dn     = "ou=People," . $host_dn;

// convert data from hex to bin.
function hex2bin($data) {
	$len = strlen($data);
	for ($i=0; $i<$len; $i+=2) {
		$newdata .= pack("C", hexdec(substr($data, $i, 2)));
	}
	return($newdata);
}

// create a md5 password as slappasswd would do it
function ldap_md5_password($data) {
	$return_data = "{MD5}" . base64_encode(hex2bin(md5($data)));
	return($return_data);
}

// get password from specified include file
function get_password($filename) {
	$file = "/home/www/admin/include_files/" . $filename;
	$secret_content=file($file);
	$secret = trim($secret_content[0]);
	return($secret);
}

// authenticate the user/password against the LDAP database.
function authenticate($user, $pass)
{
	global $host_dn;
	global $ou_dn;
	// set default values.
	$result = -1;
	$trimuser = trim($user);
	$trimpass = trim($pass);
	$md5pass = ldap_md5_password($trimpass);
	$ldap_admin_dn = "cn=admin," . $host_dn;
	$ldap_admin_pw=get_password("ldap");
	if (empty($ldap_admin_pw)) {
		$result = -2;
		return($result);
	}
	$ds = ldap_connect("localhost");
	if (!$ds) {
		$result = -3;
		return($result);
	}
	$r = ldap_bind($ds, $ldap_admin_dn, $ldap_admin_pw);
	if (!$r) {
		$result = -4;
		return($result);
	}
	$sr = ldap_search($ds, $ou_dn, "uid=$trimuser");
	$info = ldap_get_entries($ds, $sr);
	for ($i = 0; $i < $info["count"]; $i++) {
		$ldap_user = $info[$i]["uid"][0];
		if ($ldap_user == $user) {
			$ldap_password = $info[$i]["userpassword"][0];
			if ($ldap_password == $md5pass) {
				$result = 1;
				break;
			} else {
				$result = 0;
				break;
			}
		}
	}
	ldap_close($ds);
	return($result);
} // end function authenticate($user, $pass)

// change ldap password for a user
function change_ldap_password($user, $pass)
{
	global $host_dn;
	global $ou_dn;
	// set default values.
	$result = -1;
	$trimuser = trim($user);
	$trimpass = trim($pass);
	$md5pass = ldap_md5_password($trimpass);
	$ldap_admin_dn = "cn=admin," . $host_dn;
	$ldap_admin_pw=get_password("ldap");
	if (empty($ldap_admin_pw)) {
		$result = -2;
		return($result);
	}
	$ds = ldap_connect("localhost");
	if (!$ds) {
		$result = -3;
		return($result);
	}
	$r = ldap_bind($ds, $ldap_admin_dn, $ldap_admin_pw);
	if (!$r) {
		$result = -4;
		return($result);
	}
	$sr = ldap_search($ds, $ou_dn, "uid=$trimuser");
	$info = ldap_get_entries($ds, $sr);
	if ($info["count"] != 1) {
		$result = -5;
		return($result);
	}
	$ldap_dn = $info[0]["dn"];
	$newpass["userpassword"] = $md5pass;
	if (ldap_modify($ds, $ldap_dn, $newpass)) {
		$result = 1;
	} else {
		$result = -6;
	}
	ldap_close($ds);
	return($result);
} // end function change_ldap_password($user, $pass)

function change_postgres_password($user, $pass) {
	$trimuser = trim($user);
	$trimpass = trim($pass);
	$pg_admin_user="postgres";
	$pg_admin_pass=get_password("postgres");
	if (!$pg_admin_pass) {
		$result = -2;
		return($result);
	}
	$conn = pg_connect("host=192.168.228.14 dbname=template1 user=$pg_admin_user password=$pg_admin_pass");
	if (!$conn) {
		$result = -3;
		return($result);
	}
	$change_sql = "alter user $user password '$pass'";
	$sql_result = pg_exec($conn, $change_sql);
	if ($sql_result) {
		$result = 1;
	} else {
		$result = -6;
	}
	pg_close($conn);
	return($result);


} // end function change_postgres_password($user, $pass) {

function change_mysql_password($user, $pass) {
	$trimuser = trim($user);
	$trimpass = trim($pass);
	$my_admin_user="root";
	$my_admin_pass=get_password("mysql");
	if (!$my_admin_pass) {
		$result = -2;
		return($result);
	}
	$conn = mysql_connect("localhost", $my_admin_user, $my_admin_pass);
	if (!$conn) {
		$result = -3;
		return($result);
	}
	$select_result = mysql_select_db("mysql", $conn);
	if (!$select_result) {
		$result = -4;
		return($result);
	}
	$change_sql = "set password for $user = PASSWORD('$pass')";
	$sql_result = mysql_query($change_sql, $conn);
	if ($sql_result) {
		$result = 1;
	} else {
		$result = -6;
	}
	mysql_close($conn);
	return($result);
}

?>

It's only the top part that's used in more files when we get to actually changing passwords.

Then we have the logout.php4, which takes care of shutting down a session when asked to do so.


<?
// logout.php4 - destroys sessions and returns to login form

// destroy all session variables
session_start();
session_destroy();

// redirect
header("Location: /index.php4");
exit();
?>

And finally we have the error.php4, which shows the errors encountered in the login system.


<html>
<head>
<title>Error page</title>
</head>
<body>
<?
switch ($error) {
	case -1: 
		$message = "Ingen bruger med det navn.";
		break;
	case 0: 
		$message = "Forkert brugernavn/password.";
		break;
	case 2: 
		$message = "Ikke logget ind.";
		break;
	default: 
		$message = "Ikke specificeret fejl.";
		break;
}
?>
<center>
<? echo "<h2>Fejlkode $error: $message</h2>"; ?>
<br>
<a href="/system/index.php4">Prøv igen</a><br>
</center>
</body>
</html>

When You later want to password protect a page, then You just add the following to the top of the page:


<?
session_start();
if (!session_is_registered("SESSION")) {
	header("Location: /system/error.php4?error=2");
	exit();
}
?>

The above will redirect to the error page if You are not logged in at that point. You will there be able to go to the login-page, to actually do a full login.