Re: [phplib] current users? From: giancarlo pinerolo (giancarlo <email protected>)
Date: 08/22/01

What I propose is to make Auth a very aseptic class. Kind of
client-server. Loosely coulpled. No html ouptut, no form handling. That
stuff should be handled, eventually, by the application, maybe in
page.inc. (if it is a web
application... Auth has to be a more abstract concept).
If we think to auth as a client-server commodity, what requests auth
(the application), is the client. PHPlib Auth is the server. So Client
(application) side, anyway

And every login/logout being written in a log file

This would solve all the problems with poping-out pages,
back/cancel-login buttons, log/reg mode. In the sense that these have to
be handled application-side.

I have already tranformed it this way,, for my use.

I got some ideas from
http://www-106.ibm.com/developerworks/webservices/library/ws-xpc2/
and
http://www-106.ibm.com/developerworks/webservices/library/ws-xpc2/listing2.html

Basically three methods:

authenticate (an alias for start())
get_account_info
set_account_info

I wrote a lot about this ("Auth: I will not give up on this") on
phplib-core, but nobody commented.
PEAR Auth is wrong too, in this light, because it handles form output,
with
error message, etc

I attach the auth.inc I have been playing with a few hours only (not too
checked..), and page inc.

Giancarlo

Kristian Koehntopp wrote:
>
> On Tue, Aug 21, 2001 at 10:32:21PM -0700, Bryan McGuire wrote:
> > Due to the stateless nature of http, this is dodgy at best. You
> > understand this, and you need to educate your client on the nature of
> > http and its limitations. Suppose that I am browsing an online store
> > and the phone rings.
>
> While you cannot tell who is currently "online" due to the
> stateless nature of http, you could in theory tell which users
> currently have valid authentications. PHPLIB does not properly
> support this, though, because this is a vertical query and
> PHPLIB keeps authentication data in a unstructured session BLOB
> which does not lend itself well to any kind of vertical query.
>
> We already had a similar discussion a few weeks ago on this
> list.
>
> If you want to be able to answer such questions as "how many
> users are currently authenticated", you need to keep
> authentication data outside of the session BLOB in a structured
> table. Only then you will be able to run vertical queries on
> such data efficiently. This is effectively a major rewrite of
> Auth, or a very large subclass of Auth.
>
> Kristian
>
> --
> Abbestellen mit Mail an: phplib-unsubscribe <email protected>
> Kommandoliste mit Mail an: phplib-help <email protected>

<?php
/*
 * Session Management for PHP3
 *
 * Copyright (c) 1998-2000 NetUSE AG
 * Boris Erdmann, Kristian Koehntopp
 * Copyright (c) 1999-2000 Internet Images srl
 * Massimiliano Masserelli
 *
 * $Id: auth.inc,v 1.4 2001/08/16 18:49:57 pingus Exp $
 *
 */

class Auth {
  var $classname = "Auth";
  var $persistent_slots = array("auth");
  
  var $lifetime = 15; ## Max allowed idle time before
                                  ## reauthentication is necessary.
                                  ## If set to 0, auth never expires.
  
  var $refresh = 0; ## Refresh interval in minutes.
                                  ## When expires auth data is refreshed
                                  ## from db using auth_refreshlogin()
                                  ## method. Set to 0 to disable refresh

  var $mode = "log"; ## "log" for login only systems,
                                  ## "reg" for user self registration

  var $magic = ""; ## Used in uniqid() generation

  var $nobody = false; ## If true, a default auth is created...

  var $cancel_login = "cancel_login"; ## The name of a button that can be
                                      ## used to cancel a login form

  ## End of user qualifiable settings.

  var $auth = array(); ## Data array
  var $in = false;
  var $db;

  ##
  ## Initialization
  ##
  function start()
     {
     global $sess, $$cl;
     unset ($uid);
     ## This is for performance, I guess but I'm not sure if it could
     ## be safely removed -- negro
     if (! $this->in)
        {
        $sess->register("auth");
        $this->in = true;
        }
     ## back compatibility: if d_c is set, create db object
     if(isset($this->database_class))
        {
        $class = $this->database_class;
        $this->db = new $class;
        }
     # Check for user supplied automatic login procedure
     if ( $uid = $this->auth_preauth() )
        {
        $this->auth["uid"] = $uid;
        $this->auth["exp"] = time() + (60 * $this->lifetime);
        $this->auth["refresh"] = time() + (60 * $this->refresh);
        return true;
        }
     if (!$this->is_authenticated() && $this->nobody)
        {
        # Authenticate as nobody
        $this->auth["uid"] = "nobody";
        # $this->auth["uname"] = "nobody";
        $this->auth["exp"] = 0x7fffffff;
        $this->auth["refresh"] = 0x7fffffff;
        return true;
        }
     if ($this->is_authenticated())
        {
        $uid = $this->auth["uid"];
        # Valid auth info
        # Refresh expire info
        ## DEFAUTH handling: do not update exp for nobody.
        $this->auth["exp"] = time() + (60 * $this->lifetime);
        return true;
        }
     else
        {
        # User is not (yet) authenticated
        if ( $uid = $this->auth_validatelogin() )
           {
           $this->auth["uid"] = $uid;
           $this->auth["exp"] = time() + (60 * $this->lifetime);
           $this->auth["refresh"] = time() + (60 * $this->refresh);
           return true;
           }
        else
           {
           $this->unauth();
           return false;
           }
        }
     }

/**********

....................
  function start() {
// $cl = $this->cancel_login;
    global $sess, $$cl;

    ## This is for performance, I guess but I'm not sure if it could
    ## be safely removed -- negro
    if (! $this->in) {
      $sess->register("auth");
      $this->in = true;
    }
    
    ## back compatibility: if d_c is set, create db object
    if(isset($this->database_class)) {
      $class = $this->database_class;
      $this->db = new $class;
    }

    # Check current auth state. Should be one of
    # 1) Not logged in (no valid auth info or auth expired)
    # 2) Logged in (valid auth info)
    # 3) Login in progress (if $$cl, revert to state 1)
    if ($this->is_authenticated()) {
      $uid = $this->auth["uid"];
      switch ($uid) {
        case "form":
          # Login in progress
          if ($$cl) {
            # If $$cl is set, delete all auth info
            # and set state to "Not logged in", so eventually
            # default or automatic authentication may take place
            $this->unauth();
            $state = 1;
          } else {
            # Set state to "Login in progress"
            $state = 3;
          }
          break;
        default:
          # User is authenticated and auth not expired
          $state = 2;
          break;
      }
    } else {
      # User is not (yet) authenticated
      $this->unauth();
      $state = 1;
    }

    switch ($state) {
      case 1:
        # No valid auth info or auth is expired
        
        # Check for user supplied automatic login procedure
        if ( $uid = $this->auth_preauth() ) {
          $this->auth["uid"] = $uid;
          $this->auth["exp"] = time() + (60 * $this->lifetime);
          $this->auth["refresh"] = time() + (60 * $this->refresh);
          return true;
        }
        
        # Check for "log" vs. "reg" mode
        switch ($this->mode) {
          case "yes":
          case "log":
            if ($this->nobody) {
              # Authenticate as nobody
              $this->auth["uid"] = "nobody";
              # $this->auth["uname"] = "nobody";
              $this->auth["exp"] = 0x7fffffff;
              $this->auth["refresh"] = 0x7fffffff;
              return true;
            } else {
              # Show the login form
              $this->auth_loginform();
              $this->auth["uid"] = "form";
              $this->auth["exp"] = 0x7fffffff;
              $this->auth["refresh"] = 0x7fffffff;
              $sess->freeze();
              exit;
            }
            break;
          case "reg":
           if ($this->nobody) {
              # Authenticate as nobody
              $this->auth["uid"] = "nobody";
              # $this->auth["uname"] = "nobody";
              $this->auth["exp"] = 0x7fffffff;
              $this->auth["refresh"] = 0x7fffffff;
              return true;
            } else {
            # Show the registration form
              $this->auth_registerform();
              $this->auth["uid"] = "form";
              $this->auth["exp"] = 0x7fffffff;
              $this->auth["refresh"] = 0x7fffffff;
              $sess->freeze();
              exit;
            }
            break;
          default:
            # This should never happen. Complain.
            echo "Error in auth handling: no valid mode specified.\n";
            $sess->freeze();
            exit;
        }
        break;
      case 2:
        # Valid auth info
        # Refresh expire info
        ## DEFAUTH handling: do not update exp for nobody.
        if ($uid != "nobody")
          $this->auth["exp"] = time() + (60 * $this->lifetime);
        break;
      case 3:
        # Login in progress, check results and act accordingly
        switch ($this->mode) {
          case "yes":
          case "log":
            if ( $uid = $this->auth_validatelogin() ) {
              $this->auth["uid"] = $uid;
              $this->auth["exp"] = time() + (60 * $this->lifetime);
              $this->auth["refresh"] = time() + (60 * $this->refresh);
              return true;
            } else {
              $this->auth_loginform();
              $this->auth["uid"] = "form";
              $this->auth["exp"] = 0x7fffffff;
              $this->auth["refresh"] = 0x7fffffff;
              $sess->freeze();
              exit;
            }
            break;
          case "reg":
            if ($uid = $this->auth_doregister()) {
              $this->auth["uid"] = $uid;
              $this->auth["exp"] = time() + (60 * $this->lifetime);
              $this->auth["refresh"] = time() + (60 * $this->refresh);
              return true;
            } else {
              $this->auth_registerform();
              $this->auth["uid"] = "form";
              $this->auth["exp"] = 0x7fffffff;
              $this->auth["refresh"] = 0x7fffffff;
              $sess->freeze();
              exit;
            }
            break;
          default:
            # This should never happen. Complain.
            echo "Error in auth handling: no valid mode specified.\n";
            $sess->freeze();
            exit;
            break;
        }
        break;
      default:
        # This should never happen. Complain.
        echo "Error in auth handling: invalid state reached.\n";
        $sess->freeze();
        exit;
        break;
    }
  }
***********/

  function login_if( $t ) {
    if ( $t ) {
      $this->unauth(); # We have to relogin, so clear current auth info
      $this->nobody = false; # We are forcing login, so default auth is
                             # disabled
      $this->start(); # Call authentication code
    }
  }

  function unauth($nobody = false) {
    $this->auth["uid"] = "";
    $this->auth["perm"] = "";
    $this->auth["exp"] = 0;

    ## Back compatibility: passing $nobody to this method is
    ## deprecated
    if ($nobody) {
      $this->auth["uid"] = "nobody";
      $this->auth["perm"] = "";
      $this->auth["exp"] = 0x7fffffff;
    }
  }
  

  function logout($nobody = "") {
    global $sess;
    
    $sess->unregister("auth");
    unset($this->auth["uname"]);
    $this->unauth($nobody == "" ? $this->nobody : $nobody);
  }

  function is_authenticated() {
    if (
      isset($this->auth["uid"])
        &&
      $this->auth["uid"]
        &&
      (($this->lifetime <= 0) || (time() < $this->auth["exp"]))
    ) {
      # If more than $this->refresh minutes are passed since last check,
      # perform auth data refreshing. Refresh is only done when current
      # session is valid (registered, not expired).
      if (
        ($this->refresh > 0)
         &&
        ($this->auth["refresh"])
         &&
        ($this->auth["refresh"] < time())
      ) {
        if ( $this->auth_refreshlogin() ) {
          $this->auth["refresh"] = time() + (60 * $this->refresh);
        } else {
          return false;
        }
      }

      return $this->auth["uid"];
    } else {
      return false;
    }
  }
    
  ########################################################################
  ##
  ## Helper functions
  ##
  function url() {
    return $GLOBALS["sess"]->self_url();
  }

  function purl() {
    print $GLOBALS["sess"]->self_url();
  }

  ## This method can authenticate a user before the loginform
  ## is being displayed. If it does, it must set a valid uid
  ## (i.e. nobody IS NOT a valid uid) just like auth_validatelogin,
  ## else it shall return false.

  function auth_preauth() { return false; }
  
  ##
  ## Authentication dummies. Must be overridden by user.
  ##
  
  function auth_loginform() { ; }

  function auth_validatelogin() { ; }
  
  function auth_refreshlogin() { ; }

  function auth_registerform() { ; }

  function auth_doregister() { ; }
}
?>

<?php
/*
 * Session Management for PHP3
 *
 * Copyright (c) 1998,1999 NetUSE GmbH
 * Boris Erdmann, Kristian Koehntopp
 *
 * $Id: page.inc,v 1.8 1999/10/27 13:17:35 kk Exp $
 *
 */

function page_open($feature) {
  global $_PHPLIB;

  # enable sess and all dependent features.
  if (isset($feature["sess"])) {
    global $sess;
    $sess = new $feature["sess"];
    $sess->start();
    
    # the auth feature depends on sess
    if (isset($feature["auth"])) {
      global $auth;
      
      if (!isset($auth)) {
        $auth = new $feature["auth"];
      }
  
      
      # the perm feature depends on auth and sess
      if (isset($feature["perm"])) {
        global $perm;
        
        if (!isset($perm)) {
          $perm = new $feature["perm"];
        }

      if (!$auth->start("authenticate"))
         auth_loginform();
      }

      # the user feature depends on auth and sess
      if (isset($feature["user"])) {
        global $user;
        
        if (!isset($user)) {
          $user = new $feature["user"];
        }
        $user->start($auth->auth["uid"]);
      }
    }

    ## Load the auto_init-File, if one is specified.
    if (($sess->auto_init != "") && ($sess->in == "")) {
      $sess->in = 1;
      include($_PHPLIB["libdir"] . $sess->auto_init);
      if ($sess->secure_auto_init != "") {
        $sess->freeze();
      }
    }
  }
}

function page_close() {
  global $sess, $user;

  if (isset($sess)) {
    $sess->freeze();
    if (isset($user)) {
      $user->freeze();
    }
  }
}

function sess_load($session) {
  reset($session);
  while (list($k,$v) = each($session)) {
    $GLOBALS[$k] = new $v;
    $GLOBALS[$k]->start();
  }
}

function sess_save($session) {
  reset($session);
  while (list(,$v) = each($session)) {
    $GLOBALS[$v]->freeze();
  }
}

  ## show login form
  ## this is a CI-less generic login form. Feel free to
  ## customize.
  function auth_loginform() {
    global $sess, $auth, $_PHPLIB, $PHP_SELF;

    include($_PHPLIB["libdir"] . "loginform.new.ihtml");
  }

?>

-- 
Abbestellen mit Mail an:   phplib-unsubscribe <email protected>
Kommandoliste mit Mail an: phplib-help <email protected>