Stamp_Guy has asked for the wisdom of the Perl Monks concerning the following question:

I'm not sure this is strictly about perl, but here it goes:
I'm trying to set up a system in which a user logs in to a directory using an .htaccess file. When that person is logged in, I need to make it so no one else can log in. When she logs out, then someone else could log in. I don't have a clue where to start in making something like this. Could someone point me in the right direction?

Replies are listed 'Best First'.
Re: Security issues
by Mission (Hermit) on May 29, 2001 at 04:12 UTC
    You will most likely get many responses, but I'll speak in generalities and allow the 'elders' in this community to point you to specifics, since I know of only a few.

    First off, read the perldoc perlsec - all about security in general in Perl. Next do a super search for ssecurity, and watch the links flow. That's the basics of the reading you'll have to do.

    Now for the basic concept. You will need to utilize a database, or a text file that will log when someone has logged in. Every time your script is run, the FIRST thing you do is to check it against who is currently logged in. If someone is logged in, then you ignore the request.

    For simplicty sake you can use a simple text file. In that text file store the username that the person logged into as, the IP address and a session ID (there are lots of good ways to do a session ID... MD5 is one way, but again just do a search on Session ID and read awhile.) Each time someone logs into your system, and everytime the script is run, re-verify that all three 'keys' are the same (Session ID, Username, and IP.) This should allow you to ID a user logged in.

    Next step, (if you're using a text file) would be FLOCK. Lock the file until the person logs out, or until a certain amount of time has elapsed... just incase they don't logout, or have a crash etc.

    Hopefully this will get you thinking along the right track. I also expect to have many people give you differing opinions, so pick the best from all of our responses and good luck!

    - Mission
    "Heck I don't know how to do it either, but do you think that's going to stop me?!!"
Re: Security issues
by merlyn (Sage) on May 29, 2001 at 04:17 UTC
    The following things are not clear in your question:
    • Whether you are talking about "basic auth" for "logged in", or some other mechanism
    • What you mean by "no one else can login". Do you mean with "any" user ID, or with that particular user ID (duplicate login)?
    • How much scripting you can do. Is this mod_perl or just straight CGI?

    -- Randal L. Schwartz, Perl hacker

      To clarify:
      I'm referring to basic authentication.
      Same id and password.
      This is just straight CGI.
        You're going to have to bend your constraints a bit to make this work. First, give up on basic authentication. It does nothing to prevent multiple people from being logged in simultaneously.

        An approach that might work relies on "branding" each browser with a unique cookie value. (merlyn has an article that demonstrates how to do this.)

        Once you can brand each browser, it's a matter of bookkeeping to ensure that only one browser is logged in at a time. The logic goes something like this:

        • When a browser accesses a CGI in your "highlander" directory, the CGI first verifies that the browser has a unique id cookie. If unable to establish an id cookie, the CGI can deny service with an "Allow cookies!" message.
        • Next, the CGI determines if anyone is already logged in. If so, the CGI spits back a "Sorry" response.
        • If nobody is logged in, the browser presents a login form.
        • When the form is submitted, the CGI first checks to see if anyone sneaked in in the meantime. If so, the CGI emits a "Sorry, not quick enough" response. Otherwise, the CGI verifies the username and password, then performs some bookkeeping to note that this particular browser is logged in. (There are race conditions here that you'll need to be careful with).
        • When the CGI sees that the requesting browser is logged in, instead of a "login" form, it presents a "logout" button. When invoked, the logout action merely does a bit of bookkeeping to note that the given browser isn't logged in anymore.
        • All access to "content" is via the same CGI. Keep the content in a directory that isn't web accessible.
        You're still going to have to deal with logging out users who log in, then wander off to dinner. The CGI can do this by including a "last accessed" timestamp for the logged-in user, logging them out if the timestamp gets stale.

        Then the answer is "not possible". You'll have to change one of your parameters. There's no way to know if the same basic-auth is being used by multiple browsers. And if someone says "but what about IP", remember those behind corporate firewalls and on AOL.

        -- Randal L. Schwartz, Perl hacker

        In order to do custom authentication you will need to recompile Apache with the auth_external module included. The auth_external source comes with Apache but by default it is not included in the compiled version.

        Don't know about you, but for us the need to recompile Apache (on an old, no-longer-supported version of NCR Unix) was a show-stopper. We told the client that we could not do what they wanted without recompiling, and they said forget about it then.

Re: Security issues
by dws (Chancellor) on May 29, 2001 at 04:22 UTC
    I'm skipping ahead a bit, but there is a question that you might wish to keep in mind as you get this problem sorted out.
    • What should happen if someone who is logged in wanders off without logging out?
    How you choose to answer this will affect the shape of your solution.

Re: Security issues
by Xxaxx (Monk) on May 29, 2001 at 10:44 UTC
    Just a crazy thought...
    But, what about programmatically changing the .htpasswd file?

    If when some one logs in you change the .htpasswd file to require an unknown (to the users) username:password combination, that should prevent users from accessing html pages in the .htaccess folder. Then when that person logs out the .htpasswd file is returned to a known username:password.

    This might work in some limited sense.
    But you'll have to seriously address PWS's question: "What do you intend to do if someone leaves without logging out?"

    Claude

      Yeah, that was my thought too, but the problem is file locking. Apache isn't going to honor any lock you put on the file, so with multiple httpd's hitting that .htaccess your definately going to get a mangled read somewhere along the line.

      Update: That would be a cool Apache module wouldn't it? mod_dynamic_htaccess.

        I really like this idea. Is there any way around that problem? If anyone has any ideas, I'm all ears!
      This approach would probably not work. When using basic authentication, the browser caches the password and resends it every time the browser visits a new page.

      If you change the .htpasswd file then it could easily lock out a singleton user as well.

      Even if Apache Server caches its own copy of the password, my understanding is that a server can dump its cache.

      It is easier to ride the horse in the direction it is going, as Ken Kesey used to say. Basic authentication doesn't test for duplicate logins and convoluted hacks to get it to do so are not a fruitful path to pursue.

      Update: Another issue is that if Apache does cache the password then changing the .htpasswd file won't accomplish anything. Duplicate users will still be able to get in because Apache won't know that the .htpasswd file has been temporarily changed.