简体   繁体   中英

Apache mod_session_dbd - anyone got it to work?

I am upgrading apache mod_auth_form from 2.0.5 to 2.4. having trouble configuring mod_session_dbd. Need HELP!!

My configuration for httpd.conf - that fails to redirect to the protected main/main.php page even after the user is authenticated by login.php.

Code:

CREATE TABLE `session` ( 
  `id` bigint unsigned      NOT NULL auto_increment, 
  `value`   varchar(512)    NOT NULL DEFAULT '', 
  `expiry`  bigint unsigned       NOT NULL DEFAULT 0, 
  `key`     varchar(256)    NOT NULL DEFAULT '', 
  primary key (id) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

DBDriver mysql 
DBDParams "host=127.0.0.1 port=3306 dbname=aware_db user=apache pass=dhishkhk" 
DBDMin  4 
DBDKeep 8 
DBDMax  20 
DBDExptime 300 
DBDPrepareSQL "select value from session where `key` = %s and (expiry = 0 or expiry > %lld)" selectsession 
DBDPrepareSQL "delete from session where `key` = %s" deletesession 
DBDPrepareSQL "insert into session (value, expiry, `key`) values (%s, %lld,  %s)" insertsession 
DBDPrepareSQL "update session set value = %s, expiry =  %lld, `key` = %s where `key` = %s" updatesession 

<Directory "/var/www/html/main"> 
        Options         -Indexes +FollowSymLinks 

        SSLRequireSSL 
    SetHandler form-login-handler 
    AuthFormLoginRequiredLocation /login.php 
    AuthFormLoginSuccessLocation /main/main.php 
    AuthFormProvider dbd 
AuthFormUsername uid 
AuthFormPassword password 

    AuthType form 
    AuthName "My Login" 
ErrorDocument 401 /login.php 
Session On 
#SessionDBDPerUser On 
SessionDBDCookieName session path=/; 
SessionDBDSelectLabel selectsession 
SessionDBDDeleteLabel deletesession 
SessionDBDInsertLabel insertsession 
SessionDBDUpdateLabel updatesession 

        SessionDBDCookieRemove Off 

        Require                 valid-user 

    ExpiresActive       On 
    ExpiresByType       application/x-java-jnlp-file    "now" 

</Directory>

We write our custom login.php script that is invoked when client first accesses the main page. The script shows a login HTML form, then takes user input (uid and password) to authenticate against SQL user DB as well as LDAP user accounts. Once the uid/password is authenticated, it appears that mod_session is able to set "session" cookie, but is unable to store the session to the "session" table I created. My understanding is that mod_session_dbd is going to match the "session" in the cookie with the info in the session DB table (via the selectsession DBDPrepareSQL) and see the user is already autenticated, and let it go to main page, instead of login.php again as if it were not authenticated (which is what happens with my configuration above).

The apache documentation for mod_session_dbd is minimal and incomplete, and I have not been able to find any working example of mod_session_dbd anywhere on the web that I can use for reference. Don't even know how to debug mod_session_dbd (LogLevel setting does not seem to get traces)... Any help/suggestion would be much appreciated!!

I think the problem here is that your external login script, not being an "Authentication Provider" of mod_auth_form, cannot directly communicate to mod_auth_form that the authentication has succeeded. (The session would be inserted to the DB only after that). This communication can be done indirectly, however. Read on...

I had a similar set up. What I ended up doing was to let my external login script mimic mod_session_dbd and insert the DB entry by itself upon successful authentication. After that, redirect the page to the same protected area again. Use something like (this is PHP code)

header("Location: $toURL");

For the purpose of mod_session_dbd, your session table has to have at least three columns: uuid, session, and expiry. (But the session table will also double as a session-password table for mod_authn_dbd. See discussion below.)

mod_auth_form would generate the uuid for you, in a cookie, as long as you have the following directive. Your script can read off the value from the cookie (eg from your PHP script)

SessionDBDCookieName uuid

mod_auth_form expects the session to have three key-value pairs like this:

Realm-user=foo&Realm-pw=bar&expiry=1453231822000000

(expiry is the number of microseconds since Epoch: ie unix time times 1,000,000)

The above also assumes that you have configured your AuthName as "Realm"

AuthName "Realm"

Now, while the login script cannot communicate the success auth result to mod_auth_form, it can do so indirectly, by having the cookie for uuid with a matching row for the session table.

Next, I configured mod_auth_form to use mod_authn_dbd as the "Authentication Provider". The latter, however, does not do a real authentication (which was already been done by the login script). Instead, it just checks for the existence of a session (a cookie for uuid with a matching row in the session table) in the request.

So, what I did was to add one more column to the session table (called it "session_pw"), and then configure mod_authn_dbd to use the following query for password lookup (I was using MySQL):

AuthFormProvider dbd
AuthDBDUserPWQuery "SELECT session_pw FROM web_sessions WHERE uuid = %s and expiry>unix_timestamp()*1000000"

The trick is to know what mod_authn_dbd expects, and this was not very well documented -- it expects the password (session_pw) value from the above query to have been encrypted by one of the formats that Apache allows (seethis ). In my case, I decided to use crypt, so in the session table, my login script actually insert the following value for session_pw

convert(encrypt(?, 'Cm') using ascii)

where? is bound to the a session password that I generated (just a random number) -- this same value must also be put into the session value shown above (ie replace the placeholder "bar" for the key-value-pair of "Realm-pw").

Once mod_authn_dbd finds that the passwords match, it will let mod_auth_form knows, and the latter will let the request into the protected area. (So here what I did was to use a password check to test that the session exists)

One more trick that I needed was to disable the session insertion and update queries of mod_session_dbd (because my login script now does the insertion). I did this by the following two directives:

# we disable session insertion by mod_auth_form/mod_session_dbd -- login.php will insert the session
DBDPrepareSQL "select %s, %lld,  %s" insertsession
# we disable session update by mod_auth_form/mod_session_dbd
DBDPrepareSQL "select %s, %lld,  %s, %s" updatesession

Finally, I think I can share the schema of my session table in case this can help someone:

CREATE TABLE `web_sessions` (
  `id` int(11)  NOT NULL AUTO_INCREMENT,
  `u_name`      varchar(31) NOT NULL,   -- used for debugging only
  `session_pw`  varchar(256) NOT NULL,  -- encrypte by convert(encrypt(?, 'Cm') using ascii)
  `session`     varchar(256) NOT NULL,  -- mod_session_dbd's value
  `expiry`      bigint NOT NULL,        -- mod_session_dbd's expiry: microsecs since Epoch
  `uuid`        varchar(256) NOT NULL,  -- mod_session_dbd's key: uuid
  UNIQUE KEY `id` (`id`),
  UNIQUE KEY `uuid` (`uuid`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Hope this helps!

I had wanted to put this in a comment to leeyuiwah's answer but as my StackExchange score is not yet high enough to comment, I had to put it in a new answer instead.

I made quite a good attempt at making this work following leeyuiwah's answer (which would be a very valuable one if it could work) and spent more time on it than I feel good about admitting. The first attempt was made in 2018 and then again now in 2020, both times on Apache 2.4. So, the purpose of this answer is mainly to warn others (in the unlikely event that someone else wants to try this) so that they do not need to venture as far down the rabbit hole as I ended up doing.

I would be very happy to be proven wrong about this not working, but I think it is clear that if this was ever possible, it appears to not be possible in 2.4 and presumably not in 2.5 (according to official documentation).

It appears to me that "neutering" the insert and update queries that are detailed in mod_session_dbd documentation, causes the module to not perform it's work, presumably due to a built-in verification of inserted data. If the UUID/expiry timestamp in the database isn't identical to what the module wanted to insert into it, the module will not use it for authentication. Also, as the module is unable to verify that the UUID value and expiry time for the cookie that got inserted into the database is correct, it will discard the UUID for a new one, right on the next request. This means that the UUID that gets inserted via PHP script(as explained in leeyuiwah's answer) is inserted after the module has discarded the UUID for a new one. This seems to fit what the official documentation for mod_session_dbd states:

Due to the limitations of who came first, the chicken or the egg, per user sessions cannot be used to store authentication credentials from a module like mod_auth_form.

I imagine this is deliberate for security reasons.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM