[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [cobalt-developers] REMOTE_USER variable



Hello,

I am using a .htaccess file to protect a directory/site .  Using
perl/cgi I can obtain the REMOTE_USER variable and store or display this
information.  What I would like to do is display all users that are
currently authenticated to this resource. So in effect I want to display
not only the logged in users REMOTE_USER variable but all REMOTE_USER
variables that are currently logged in. Is this possible? Is anyone
doing something similar?

Well, http doesn't support permanent connections like telnet or ssh do... anyway, you could log all authenticated requests, together with a timestamp, and drop any lines older then 5 minutes (or so). A simple perl script would look like this (usage: "@logged_in_users = get_users($ENV{'REMOTE_USER'});" or simply "... = get_users();").

my $lock_file = "users.lock";
my $users_file = "users";

sub get_users(;$)
{
  my ($new_user) = @_;
  my @new_udata = ();
  my @authenticated = ();

  lock_users();
  if( open(USERS, "<${users_file}") )
  {
    my @udata = <USERS>;
    close(USERS);

    foreach my $user_data (@udata)
    {
      chop $user_data;
      if( $user_data =~ /^([a-zA-Z0-9]+):([0-9]+)$/ )
      {
        my $user_name = $1; my $time_stamp = $2;
        if( $time_stamp >= time() && $user_name ne $new_user )
        {
          push(@new_udata, "${user_name}:${time_stamp}\n");
          push(@authenticated, $user_name);
        }
      }
    }
    if( defined($new_user) )
    {
      # Add this user
      push(@new_data, sprintf("%s:%d\n", $new_user, time() + 5*60));
      push(@authenticated, $new_user);
    }
    if( open(USERS, ">${users_file}") )
    {
      print(USERS @new_udata);
      close(USERS);
    }
    else
    {
error("Couldn't write to ${users_file}: $!\n"); # error() defined elsewhere
    }
  }
  else
  {
    error("Couldn't open ${users_file}: $!\n"); # error() defined elsewhere
  }
  unlock_users();
  return(@authenticated);
}

sub lock_users()
{
  while(-e($lock_file))
  {
    select(undef, undef, undef, 0.1); # wait 0.1s
  }
  if(open(LOCK, ">${lock_file}"))
  {
    print(LOCK "$$\n");
    close(LOCK);
  }
  else
  {
    die("Couldn't open ${lock_file}: $!\n");
  }
}

sub unlock_users()
{
  if(-e($lock_file))
  {
    unlink($lock_file);
  }
}

Ok, so it's not perfect. I would recommend to at least define $SIG{'PIPE'} to something meaningful, and to define error(), of course. Maybe there should be a timeout in lock_users() (it can wait forever...), and some way to deal with a lock file from a killed/aborted process - for example, you could check if the process with the pid from $lock_file is actually still running.

Read you...
       Martin Sojka.