Authentication Poll & Community Design [PLEASE JOIN!]

Not for 'how-to' coding questions but PHP theory instead, this forum is here for those of us who wish to learn about design aspects of programming with PHP.

Moderator: General Moderators

Your authentication is...

Homegrown
61
91%
PEAR
4
6%
Non-PEAR but third-party
0
No votes
Borrowed from other software coexisting with app
2
3%
 
Total votes: 67

User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

That's interesting how you "lazy load" (really, that's the wrong term) the credentials. I suppose that affords more flexibility. My assertion that authentication = authorization was for the case of the example: for anything besides the admin maintenance script, other users would be authenticated. In your case, it's more of a authtools_quick_authenticate(), and the authorization needs to be called later.

Also, since you've generalized the function a little bit (which is perfectly fine, just isn't as "drop in" anymore), you can't just blindly exit if the user isn't authenticated. After all, anonymous access is perfectly feasible. ;-)

The way the function is written implies that it's something the user would define themself, replacing adapterObject* with their own implementation. Can we inject those through parameters so that this sort of code could be also packaged?

Here's the next iteration:

Code: Select all

// no access control built in
// returns whether or not a user is authenticated,
// and registers appropriate persistence if they are
function authtools_quick_authenticate($data_adapter = false, $session_adapter = false)
{
    $controller = new AuthTools_AuthController();
    
    // give the credentials to the auth controller
    $credentials = new AuthTools_Credentials_Auto();
    $controller->setCredentials($credentials);
    
    // likewise we need some to check the credentials against
    $controller->setDataAdapter($data_adapter);
    
    // determining which commands to execute is inside the controller
    // authentication is NOT binary! but we'll make it so in this case
    $authentication_status = $controller->isAuthenticated();
    $is_authenticated      = $authentication_status->toBool();
    
    // we need to stash in session
    if (!$session_adapter) {
        $session_adapter = new AuthTools_Session_Auto();
    }
    
    // tell the app about the current authentication status
    // NOT the authorization status
    $session_adapter->setAuthenticationStatus($authentication_status);
    
    return $is_authenticated; // for trivial scripts
}
I'm still trying to take out authentication code. That would look like...

Code: Select all

function authtools_quick_authorize($request, $data_adapter, $session_adapter, $output_adapter) {
    $access = new AuthTools_AccessController();
    
    $access->setRequest($request);
    $access->setDataAdapter($data_adapter);
    $access->setSessionAdapter($session_adapter);
    
    // in this case, the object contains useful info on whether or not
    // it's flat out forbidden, or please login.
    $authorization_state = $access->isAuthorized();
    $is_authorized = $authorization_state->toBool();
    
    if (!$is_authorized) {
        // could send to login page, or just say forbidden
        $forward = $authorization_state->forward();
        echo $forward->render();
        exit;
    }
    
    // is authorized
    return true;
}
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Ok ... I am following you. I would like some clarification on your statement that "authentication is NOT binary!" because it seems like it is to me. And why a separate $authentication_status object is needed?

I am also still not clear whether you are using "authorize" means Access Control or something different. As I have said before, I don't like the term "authorize" for a couple of reasons -- the main one being that is sounds too much like authenticate and they both abbreviate to "auth" which is namespace confusion. I also am never clear whether we are authorizing or the user is authorized. I still think that "authorize" sound like an administrative function.
(#10850)
santosj
Forum Contributor
Posts: 157
Joined: Sat Apr 29, 2006 7:06 pm

Post by santosj »

I'm sorry, I was about to make a post towards that, but I had to leave.

I lump adapters in with Plugins, which is wrong, but I'm not familar with MVC model. What I said about Plugins holds true with adapters also.
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Ok ... I am following you. I would like some clarification on your statement that "authentication is NOT binary!" because it seems like it is to me. And why a separate $authentication_status object is needed?
Okay. Even though authentication is not binary or true/false, it usually is treated this way. Practically speaking, there is absolutely no way for a server to know definitively whether or not a user is who he says he is. However, they can be pretty darn good sure that it is that user. But there's always that slight chance (password compromise, cleartext sniffing, etc).

When priviledges get escalated, this can be quite important. Here's an example:

We have two different "factors" of authenticating a person: 1) user/password and 2) remember me token. Obviously, if the user had sent the user and password on that request (or even that session), we'd be pretty sure it is that person. Remember is slightly less certain, but it's good enough for most functions, like reading and posting to a forum.

Now, the user would like to administrate the board. The only factor they have currently is the remember me token. The application requires a valid user/password submission to be associated with the same session. However, it can't tell if we just pass around a boolean $is_authenticated. Thus, the $authentication_status object. This can also apply to things like escalated priviledges timeouts (where presenting your user/pass only lasts for, say, 30 minutes) and only allowing a particular action to be executed over SSH.

Remember, for a usual application, this would be overkill. So we offer the toBool() method for those users.
I am also still not clear whether you are using "authorize" means Access Control or something different.
I'm not exactly sure either. So here's some overall definitions.

1. Access Control - Authentication, authorization, audit, encryption, etc. Basically, Access Control is the WHOLE thing.
2. Authorization - Granting resources (which counts as both information and actions) to only allowed people. This can be implemented using (and here's where the nomenclature gets fuzzy): access control lists (ACL), role-based access control, or authorization policies.
3. Authentication - The verification of the identity of an individual

I don't agree that "authorizing" a user is an administrative function. That's more "modifying access control lists" or "reassigning roles" etc. since the server can do this stuff automatically.

As for the namespace confusion, these two terms really are the most widely used one. Trying to substitute a synonym could be disastrous.

My authorization code is real sketchy. Don't trust it. I was just trying to show how it could be seperated out.
I lump adapters in with Plugins, which is wrong, but I'm not familar with MVC model. What I said about Plugins holds true with adapters also.
Okay. Here's the PoEAA definitions:

Adapters - alters an implementation's interface to match another interface you need to work with. There usually is an existing interface, versus a Gateway which doesn't have one.

Plugin - links classes during configuration rather than compilation. Admittedly, this is less meaningful in an interpreted language. Basically, it means that factories that generate different implementations of the same class are managed from a central point.

Some other relevant terms:

Mapper - sets up communication between two independent objects. Most common is DB Mappers. The domain object doesn't know about the DB, and the DB doesn't know about the domain object. Therefore, no dependencies.

Seperated Interface - Defines an interface in a seperate package from its implementation. The Domain might have a dependency on the Unit of Work interface, but not on the implementation.

Gateway - an object that encapsulates access to an external system or resource. Basically a wrapper.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Ambush Commander wrote:I'm not exactly sure either. So here's some overall definitions.

1. Access Control - Authentication, authorization, audit, encryption, etc. Basically, Access Control is the WHOLE thing.
2. Authorization - Granting resources (which counts as both information and actions) to only allowed people. This can be implemented using (and here's where the nomenclature gets fuzzy): access control lists (ACL), role-based access control, or authorization policies.
3. Authentication - The verification of the identity of an individual

I don't agree that "authorizing" a user is an administrative function. That's more "modifying access control lists" or "reassigning roles" etc. since the server can do this stuff automatically.

As for the namespace confusion, these two terms really are the most widely used one. Trying to substitute a synonym could be disastrous.
Yeah ... I think those are fairly standard book definitions. My problem is that if you look at your definition, Authorization ends up being defined as granting access using access control lists (ACL), role-based access control, or policy-based access control -- that's what always seems silly about using the term Authorization for ... well ... controlling access. Perhaps we should vote on the terms to use to shut-up my complaining. ;)
Ambush Commander wrote:Okay. Even though authentication is not binary or true/false, it usually is treated this way. Practically speaking, there is absolutely no way for a server to know definitively whether or not a user is who he says he is. However, they can be pretty darn good sure that it is that user. But there's always that slight chance (password compromise, cleartext sniffing, etc).

When priviledges get escalated, this can be quite important. Here's an example:

We have two different "factors" of authenticating a person: 1) user/password and 2) remember me token. Obviously, if the user had sent the user and password on that request (or even that session), we'd be pretty sure it is that person. Remember is slightly less certain, but it's good enough for most functions, like reading and posting to a forum.

Now, the user would like to administrate the board. The only factor they have currently is the remember me token. The application requires a valid user/password submission to be associated with the same session. However, it can't tell if we just pass around a boolean $is_authenticated. Thus, the $authentication_status object. This can also apply to things like escalated priviledges timeouts (where presenting your user/pass only lasts for, say, 30 minutes) and only allowing a particular action to be executed over SSH.

Remember, for a usual application, this would be overkill. So we offer the toBool() method for those users.
I'm not sure that dealing with priviledge escalation should be done at that level. That would probably be better handled by some sort of plugin or manually when access is denyed. The authentication status object seems to add complication where it is not needed and complicates the common and simple cases.
(#10850)
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

Yeah ... I think those are fairly standard book definitions. My problem is that if you look at your definition, Authorization ends up being defined as granting access using access control lists (ACL), role-based access control, or policy-based access control -- that's what always seems silly about using the term Authorization for ... well ... controlling access. Perhaps we should vote on the terms to use to shut-up my complaining.
But we can't just redefine "Access Control".

Synonyms for authorization: approval, clearance, consent, endorsement, go-ahead*, green light*, leave, okay, sanction

"Clearance" is okay, but I'd rather use authorization.
I'm not sure that dealing with priviledge escalation should be done at that level. That would probably be better handled by some sort of plugin or manually when access is denyed. The authentication status object seems to add complication where it is not needed and complicates the common and simple cases.
Priviledge escalation is not done at this level. However, it's the only logical place to provide the information necessary for priviledge escalation: the user's authentication state. But I can add a convenience function, I suppose.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Ambush Commander wrote:But we can't just redefine "Access Control".

Synonyms for authorization: approval, clearance, consent, endorsement, go-ahead*, green light*, leave, okay, sanction

"Clearance" is okay, but I'd rather use authorization.
I don't want to redefine Access Control, it's more how it gets used with these types of systems. There are basically two parts: the larger part that deals with granting or denying access and the smaller identification/authentication part. The first part has to be included on every page, the second is only accessed on demand. For me Authorization is a piece of the larger first part -- not the whole thing. That's why I call the first part Access Control and the second Authentication. Within the larger first Access Control part there are many pieces (ACLs, Policies, Roles, etc.) and there would be a Authorization class in there somewhere.
Ambush Commander wrote:Priviledge escalation is not done at this level. However, it's the only logical place to provide the information necessary for priviledge escalation: the user's authentication state. But I can add a convenience function, I suppose.
I'd rather start simple and add as needed. I think all the info is in the base object already. A priviledge escalation component might extract is in a more usable form though.
(#10850)
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

I'd rather start simple and add as needed. I think all the info is in the base object already. A priviledge escalation component might extract is in a more usable form though.
I think I see what you're getting at: the controller maintains state, rather, it knows about the last authentication attempt. I think it would then be more appropriately be called an AuthenticationManager, rather than a controller, because the classic PoEAA pattern for Application Controller implies all it does is returns an appropriate command and view for a particular request. This also moves more in-line with the OSID definition.

As for starting simple and adding what's needed, if the base structure of the simple use case is fundamentally flawed, we may start having problems when we start adding features (oh no, a hack is needed, otherwise we rewrite the whole thing). I was thinking that we should start testing the current code by attempting to extend it in a logical fashion to encompass all the features we're planning on adding.
I don't want to redefine Access Control, it's more how it gets used with these types of systems. There are basically two parts: the larger part that deals with granting or denying access and the smaller identification/authentication part. The first part has to be included on every page, the second is only accessed on demand. For me Authorization is a piece of the larger first part -- not the whole thing. That's why I call the first part Access Control and the second Authentication. Within the larger first Access Control part there are many pieces (ACLs, Policies, Roles, etc.) and there would be a Authorization class in there somewhere.
Regarding authentication being only accessed on demand, I'd say it's possible to do that, but I really don't see any reason why. You could argue that some pages don't need access control either. They're just plain static HTML files. Since the user is constantly sending their session ID cookie with every request they make, why not authenticate them?

Although... I'm not exactly sure what you're getting at. Sorry.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Ambush Commander wrote:I think I see what you're getting at: the controller maintains state, rather, it knows about the last authentication attempt. I think it would then be more appropriately be called an AuthenticationManager, rather than a controller, because the classic PoEAA pattern for Application Controller implies all it does is returns an appropriate command and view for a particular request. This also moves more in-line with the OSID definition.
OK
Ambush Commander wrote:As for starting simple and adding what's needed, if the base structure of the simple use case is fundamentally flawed, we may start having problems when we start adding features (oh no, a hack is needed, otherwise we rewrite the whole thing). I was thinking that we should start testing the current code by attempting to extend it in a logical fashion to encompass all the features we're planning on adding.
OK
Ambush Commander wrote:Regarding authentication being only accessed on demand, I'd say it's possible to do that, but I really don't see any reason why. You could argue that some pages don't need access control either. They're just plain static HTML files. Since the user is constantly sending their session ID cookie with every request they make, why not authenticate them?
By "on demand" I simply meant that you only ask for credentials when you need them, whereas you always check whether access is allowed. I am assuming that in all of these conversations we are only talking about those "pages" running access control code.
(#10850)
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

:-D Nice to see some agreement. So we call it AuthenticationManager and let it have the more fine-grained authentication information.
By "on demand" I simply meant that you only ask for credentials when you need them, whereas you always check whether access is allowed. I am assuming that in all of these conversations we are only talking about those "pages" running access control code.
I'll grant you that. However...

Here's an interesting problem to pose to you, then. Most websites display something like "Logged in as USERNAME" on most of their pages, even if they have an allow all policy. This is one of the few cases (I can't think of another) where identification/authentication is needed independent of authorization. (another, I suppose, would be enacting user preferences). What then?

Also, there's really no reason not to authenticate a user based on sessions because PHP does that all automatically. It reads the session id cookie, it reads the filesystem session, and then it instantiates it within the program through the super-global array. Trying to avoid actually "authenticating" a user grabs little performance benefit at all.

Edit Here's another iteration to incorporate everything we've discussed:

Code: Select all

<?php

// no access control built in!
// returns whether or not a user is authenticated,
// and registers AuthenticationManager to appropriate persistence if they are.
function authtools_quick_authenticate(
    $data_adapter       = false, // false to use the automatic classes
    $session_adapter    = false,
    $credential_adapter = false)
{
    $manager = new AuthTools_AuthenticationManager();
    
    // give the credentials AuthenticationManager (nothing happens yet)
    if (!$credential_adapter) $credentials = new AuthTools_Credentials_Auto();
    $manager->setCredentials($credentials);
    
    // likewise we need some to check the credentials against (nothing happens)
    // the automatic detection is NOT recommended
    if (!$data_adapter) $data_adapter = new AuthTools_Datasource_AutoMySQL();
    $manager->setDataAdapter($data_adapter);
    
    // the user gets authenticated.
    //   authenticateUser optionally takes a specific authentication command,
    // otherwise, it passes the credentials to a controller which determines
    // which methods should the user be authenticated by
    $manager->authenticateUser();
    
    // propagate the authentication manager. This gives the app a dependency,
    // but it should be trivial to write wrappers for the most important
    // methods: isUserAuthenticated() and getUserId()
    if (!$session_adapter) $session_adapter = new AuthTools_Session_Auto();
    $session_adapter->setAuthenticationManager($authentication_manager
    
    // for small scripts that don't want to interface with the manager
    return $manager->isUserAuthenticated();
}

?>
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Ambush Commander wrote:I'll grant you that. However...

Here's an interesting problem to pose to you, then. Most websites display something like "Logged in as USERNAME" on most of their pages, even if they have an allow all policy. This is one of the few cases (I can't think of another) where identification/authentication is needed independent of authorization. (another, I suppose, would be enacting user preferences). What then?
I think it comes down to a practical matter of where to put things. The USERNAME is in the datasource that the authentication system uses, but once the user is authenticated some minimum set of useful data is maintained using the persistence plugin (usually the session). So once authenticated, the handy way to get user data is via the higher performance access checking code, rather than going back to the datasource each time. So one of the things that needs to be done after credentials are authenticated is the give the persistence code the user data that you want to keep around. That would mainly be access control data, but could also be display stuff as well.

You code looks good to me. The other "voters" should have a chance to comment.
(#10850)
User avatar
Ambush Commander
DevNet Master
Posts: 3698
Joined: Mon Oct 25, 2004 9:29 pm
Location: New Jersey, US

Post by Ambush Commander »

I think it comes down to a practical matter of where to put things. The USERNAME is in the datasource that the authentication system uses, but once the user is authenticated some minimum set of useful data is maintained using the persistence plugin (usually the session). So once authenticated, the handy way to get user data is via the higher performance access checking code, rather than going back to the datasource each time. So one of the things that needs to be done after credentials are authenticated is the give the persistence code the user data that you want to keep around. That would mainly be access control data, but could also be display stuff as well.
Precisely. Things like the user's username go without saying, but preferences and access control data are a little more dubious. And there's always the synchronization problem if these things become out of date.
You code looks good to me. The other "voters" should have a chance to comment.
Okay.
User avatar
RobertGonzalez
Site Administrator
Posts: 14293
Joined: Tue Sep 09, 2003 6:04 pm
Location: Fremont, CA, USA

Post by RobertGonzalez »

I think it looks sweet. Nice and tight, but modular and flexible. It incorporates what is needed and doesn't what is not. This is something that I would drool over in a ready-made app.
User avatar
Christopher
Site Administrator
Posts: 13596
Joined: Wed Aug 25, 2004 7:54 pm
Location: New York, NY, US

Post by Christopher »

Nathaniel and Maugrim_The_Reaper were our other two voters ... comments?
(#10850)
User avatar
Nathaniel
Forum Contributor
Posts: 396
Joined: Wed Aug 31, 2005 5:58 pm
Location: Arkansas, USA

Post by Nathaniel »

I'm not following most of aborint's and Commander's discussion, but the code tends to make things more clear for me.

I hate for you guys to have to baby me through this, but tell me if I have this straight (I commented my questions):

Code: Select all

<?php
function authtools_quick_authenticate(
    $data_adapter       = false, // false to use the automatic classes
    $session_adapter    = false,
    $credential_adapter = false)
{
    $manager = new AuthTools_AuthenticationManager();
   
    // would this be either the session cookie or the $_POST['username'] / $_POST['password']?
    if (!$credential_adapter) $credentials = new AuthTools_Credentials_Auto();
    $manager->setCredentials($credentials);
   
    // this would be the datasource to check the session cookie or $_POST data against...?
    if (!$data_adapter) $data_adapter = new AuthTools_Datasource_AutoMySQL();
    $manager->setDataAdapter($data_adapter);
   
    // ok, makes sense
    $manager->authenticateUser();
   
    // ok, I'm really lost. This isn't returned or added to the $manager object - what is it doing?
    if (!$session_adapter) $session_adapter = new AuthTools_Session_Auto();
    $session_adapter->setAuthenticationManager($authentication_manager
   
    // for small scripts that don't want to interface with the manager
    return $manager->isUserAuthenticated();
}

?>
Also, shouldn't "$session_adapter->setAuthenticationManager($authentication_manager" be "$session_adapter->setAuthenticationManager($manager);", Commander?

I'm with Everah. The fact that I'm following your logic as well as I think I am is marvelous - most of the time I get completely lost looking at others' code.
Post Reply