Page 1 of 3

Authentication - more oop

Posted: Fri Jul 28, 2006 9:59 am
by Luke
I am writing an (very basic for now) authentication class. I would like some suggestions for classes that could inherit this class and extend its security as well as suggestions to make it more oop.

Here is what I have so far:

Code: Select all

<?php
class Authenticate{
	
	private $data;
	//private $session;
	private $db;
	private $authorized;
	
	public function __construct(Registry $Registry, $use_token=false, $hash="sha1"){
		$this->data 		= $Registry->get('Request');
		//$this->session 		= $Registry->get('Session');
		$this->db 			= $Registry->get('MySQL');
	}
		
	public function verify($input, $match){
		if($this->hash($input) == $match) $this->authorized = true;
	}
	
	public function is_authorized(){
		return $this->authorized;
	}
}
?>
And here is my (primitive) login form

Code: Select all

<?php
include('classes/Registry.inc.php');

$Registry = new Registry('classes/');

$Registry->register('Request');
$Registry->register('Session');
$Registry->register('MySQL', null, 'localhost', 'username', 'password', 'my_database');

$Request = $Registry->get('Request');
$Session = $Registry->get('Session');
$Db = $Registry->get('MySQL');

$Registry->register('Authenticate', null, $Registry);

// Want this to be more oop - I don't like all this...
if($Request->is_post()){
	if($Request->has('username')){
		$input_user = $Request->get('username');
		$select_user = "SELECT * FROM `users` WHERE `username` = '" . $input_user . "';";
		echo $select_user;
		$User = $Db->query($select_user);
		
		if($User->length() == 1){		
			$auth = $Registry->get('Authenticate');
			$auth->verify($Request->get('password'), $User->password);
			if($auth->is_authorized()){
				echo "You are in!";
			}
		}
	}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
    <title>Authenticate</title>
  </head>
  <body>
<pre><?php
print_r($Registry);
//print_r($auth);
?></pre>
	<form name="form" method="post" action="">
	 <input type="text" name="username" value="<?php echo $Request->get('username'); ?>" />
	 <input type="password" name="password" value="" />
	 <input type="hidden" name="" value="" />
	 <input type="submit" value="Login" />
	</form>
  </body>
</html>

Posted: Fri Jul 28, 2006 11:39 am
by Jenk
You can wrap a lot of that into a class quite easily, here is what one of my controllers (currently) looks like:

Code: Select all

if (!empty($_POST['username']) && !empty($_POST['password'])) {
    try {
        $user = new jmt_User($db);  //$db is predefined
        $user->login($_POST['username'], $_POST['password']);
    } catch (AuthenticationException $e) {
        die ('invalid username and or password');
    } catch (Exception $e) {
        var_dump($e);
    }
}
My model and view classes are instantiated after.

the jmt_User class, as you can see, is where the authentication occurs for logging the user in. Other methods include checking permissions etc.

login method is:

Code: Select all

public function login ($user, $pass)
        {
            try {
                $this->db->parseQuery(  'SELECT `permissions`, `userId` '
                                      . 'FROM `users` WHERE `userName` = :1 AND `password` = :2',
                                      $user, md5($pass));
                $this->db->commit();
            } catch (Exception $e) {
                throw $e;
            }
            // store user data
            if ($this->db->numRows() > 0) {
                $this->userName = $row['userName'];
                $this->permissions = $row['permissions'];
                $this->userId = $row['userId'];
            } else {
                throw new AuthenticationException ('Invalid username or password');
            }
        }
(I actually have 3 methods related to logins. Right where I have the comment 'store permissions' that process is split, because I also have a loginWithId() method which is used when the user returns with a cookie containing their userid and a salted password. Both login methods then call upon the 3rd method to store user data. But meh.)

Posted: Fri Jul 28, 2006 12:42 pm
by Luke
Another question: What is the best way to do this? As far as steps go... for the most basic authorization... this is what I do, please correct me if it is flawed:

1. Get username and password from user
2. Select user info from db by username
3. Validate their password is correct
4. Set a variable called authorized in the session to true
5. Check for variable "authorized" on all subsequent pages.

Posted: Fri Jul 28, 2006 2:13 pm
by Jenk
My process:

1. check for $_SESSION['auth'] (or variant)
2. retrieve user details from user, be it cookie, or input.
3. select + validate.
4. setcookie with userid and salted password hash.
5. set session logged in = true.

Posted: Mon Jul 31, 2006 10:15 am
by Yossarian
The Ninja Space Goat wrote:Another question: What is the best way to do this? As far as steps go... for the most basic authorization... this is what I do, please correct me if it is flawed:

1. Get username and password from user
2. Select user info from db by username
3. Validate their password is correct
4. Set a variable called authorized in the session to true
5. Check for variable "authorized" on all subsequent pages.
I use 2 phases:

1 get username, password and PIN no from user
2 check all 3 are correct vs dbase
3 give them a cookie that contains their username

From now on make them login again with PIN (4 numbers)

1 check username (from cookie) and PIN combi (3 strikes and you're out, delete cookie)
2 start a session, set all their navigational/authorization needs in a session cookie
3 on each page check that session is valid

I used a class/idea I found called Sessionara, works nicely.

Posted: Mon Jul 31, 2006 10:18 am
by Luke
what's the advantage of doing it like that?

Posted: Mon Jul 31, 2006 11:11 am
by thiscatis
The Ninja Space Goat wrote:what's the advantage of doing it like that?
could stop users from password trader sites

Posted: Mon Jul 31, 2006 3:15 pm
by Yossarian
The Ninja Space Goat wrote:what's the advantage of doing it like that?
Well, maybe I should have said it was for a private admin area of a cms.

These are the main reasons I recall using this system (over a year ago now):

1. Users logging in/out only have to remember a 4 digit PIN number.
(the username is read in from the cookie)

2. The parts of the app they are allowed to see/use are loaded up along with any preferences as they login.

3. Sessionara contains some other simple security precautions (the users browser/IP is hashed along with the time as they login - then checked on every page request)

4. Now this might NOT be your case, but someone who appeared to be a better coder than I , thought out and wrote the class.

@thiscatis
"could stop users from password trader sites"
I never thought of that...

Posted: Mon Jul 31, 2006 4:51 pm
by Ambush Commander
I wrote a specification for an authentication system for an authentication library that we were working on. (The work on the actual code has been suspended until I can finish a different library, but this spec is fairly complete, so it would be good to look at).

In a nutshell, sessions are all about establishing user identity. So authentication processes, like logging in or logging out affect the session by creating or destroying it.

Posted: Tue Aug 01, 2006 4:23 pm
by Luke
Anybody know of any other good articles about user authentication and security?

I'm trying to figure out how much the authentication class needs to know about everything else in the system... which is proving very difficult. :cry:

Posted: Tue Aug 01, 2006 5:59 pm
by Ambush Commander
I'm trying to figure out how much the authentication class needs to know about everything else in the system... which is proving very difficult.
I would say nothing at all. Most of the time, you'll feed the authentication information to the authorization class, which actually determines whether or not a user has priviledges to do something.

Posted: Tue Aug 01, 2006 6:02 pm
by Luke
So... the authorization class doesn't need to know about the session, or a database connection... nothing?

Posted: Tue Aug 01, 2006 6:06 pm
by Ambush Commander
I wasn't talking about authorization. I was talking about authentication.

Regarding the authorization class, no, it shouldn't need to know about the session unless it needs fine grained control over which types of sessions are allowed to do something (usually demarcated by the origin of the session: remember me or a login?)

The authorization class, at the very least, needs to know who's currently accessing the system (the job of the Authenticator). Then, I presume, it would pull up information about the user's access rights from the database, which is a task that should probably be delegated to its own object.

Posted: Tue Aug 01, 2006 6:12 pm
by Luke
hmm... well thank you for clearing up the difference between authentication and authorization, because I was definately mixing the two up...

Alright.. let me give this a go then...

Posted: Tue Aug 01, 2006 11:07 pm
by Luke
OK... not much has really changed:

Code: Select all

<?php
class Authenticate{
	
	private
	$match,
	$input,
	$authorized=false;
	
	public function __construct(Registry $registry){
		
	}
	public function verify(){
		$this->authorized = ($this->match == $this->input);
	}
	public function set_match($match){
		
		// Store match (get from db or file or something)
		$this->match = $match;
	}
	public function set_input($input){
		
		// Hash and store input
		$this->input = $this->hash($input);
		
	}
	public function is_authorized(){
		
		// This is mainly for readability and scalability
		return $this->authorized;
	}
	public function hash($value, $hash = "sha1"){
		
		// Hash a value with preferred hashing algorithm
		return $hash($value);
	}
}
?>
But this means I have to do something like this on every page that needs authentication:

Code: Select all

<?php

$Template->assign('form_action', '/classes/index.php/login');

$page = 'default';

$auth = $Registry->get('Authenticate');
$request = $Registry->get('Request');
$db = $Registry->get('MySQL');

if($request->is_post()){
	$query = 'SELECT * FROM `users` WHERE `username` = "' . $request->get('username') . '"';
	$user = $db->query($query);
	$auth->set_input($request->get('password'));
	$auth->set_match($user->password);
	$auth->verify();
	$Template->assign('username', $request->get('username'));
	if($auth->is_authorized()) $page = "authorized";
	$Template->assign('message', 'Invalid login: Please try again...');
}
else{
	$Template->assign('message', 'Please log in...');
	$Template->assign('username', '');
}
	$Response->addContent($Template->fetch($action . '/' . $page . '.tpl'));
?>
This is kind of a lot for every page... what can I do to sum all of this up into a class or two that can be easily adapted or extended to allow for one-time token and/or remember me?

How about user authentication systems that are already built... recommend some please.