SabreDAV IMAP Authentication Backend

1,203 views
Skip to first unread message

Robert George

unread,
Jan 19, 2012, 1:37:09 AM1/19/12
to sabredav...@googlegroups.com
I wanted to easily integrate SabreDAV into my system, rather than maintaining a separate user list. So I decided to make use of the existing authentication system I have in place my sending authentication through my IMAP server. I wrote a simple plugin to do just this. It takes a single argument to specify the IMAP host to authenticate against, (in the format specified for the imap_open $mailbox argument. See: http://php.net/manual/en/function.imap-open.php). Here's an example:
    $authBackend = new Sabre_DAV_Auth_Backend_IMAP("{mail.example.com}");


The following is the code for anyone else to enjoy (on my system its in /usr/share/php/Sabre/DAV/Auth/Backend/IMAP.php):

<?php
// Auth Class
class Sabre_DAV_Auth_Backend_IMAP extends Sabre_DAV_Auth_Backend_AbstractBasic
{
       protected $imap_server;
       public function __construct($imap_server)
        {
                $this->imap_server = $imap_server;
        }
       protected function validateUserPass($username, $password)
        {
                try
                {
                        $imap = imap_open($this->imap_server,$username,$password,OP_HALFOPEN);
                }
                catch (Exception $e)
                {
                        return false;
                }
                imap_close( $imap );
                return true;
        }
}


?>

Evert Pot

unread,
Jan 19, 2012, 6:29:38 AM1/19/12
to sabredav...@googlegroups.com
Hi Robert,

This is pretty cool!

I would recommend though that you cache the result of the login. WebDAV tends to use a *lot* of HTTP requests, and for every http request you will also now login to the IMAP server.

Evert

--
You received this message because you are subscribed to the Google Groups "SabreDAV Discussion" group.
To view this discussion on the web visit https://groups.google.com/d/msg/sabredav-discuss/-/1WBeUyNfR_gJ.
To post to this group, send email to sabredav...@googlegroups.com.
To unsubscribe from this group, send email to sabredav-discu...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/sabredav-discuss?hl=en.

Robert George

unread,
Jan 19, 2012, 9:06:39 PM1/19/12
to sabredav...@googlegroups.com
Evert,

You have a really good point. I didn't even think about it. I have modified the code to cache the login data in the users table.
In order to make it work right, I added two options: a reference to the PDO object, and the cache timeout interval in seconds. I also had to add a field to the users table to include a timestamp. ( ALTER TABLE users ADD COLUMN modtime TIMESTAMP; )

The auth backend is now called as follows:
    $authBackend = new Sabre_DAV_Auth_Backend_IMAP("{mail.example.com}",$pdo,60);

The updated IMAP.php is as follows:

<?php
// Auth Class
class Sabre_DAV_Auth_Backend_IMAP extends Sabre_DAV_Auth_Backend_AbstractBasic
{
        protected $imap_server;
        protected $pdo;
        protected $timeout;

        public function __construct($imap_server, $pdo, $timeout)
        {
                $this->imap_server = $imap_server;
                $this->pdo = $pdo;
                $this->timeout = $timeout;
        }

        protected function validateUserPass($username, $password)
        {
                $logindigest = hash("md5","$username:$password");
                $stmt = $this->pdo->prepare('SELECT username FROM users WHERE username = ? AND digesta1 = ? AND modtime > DATE_SUB(NOW(), INTERVAL ? SECOND)');
                $stmt->execute(array($username,$logindigest,$this->timeout));
                $result = $stmt->fetchAll();
                if ( count($result) === 1 )
                {
                        return true;
                }
                else
                {
                        try
                        {
                                $imap = imap_open($this->imap_server,$username,$password,OP_HALFOPEN);
                        }
                        catch (Exception $e)
                        {
                                return false;
                        }
                        $stmt = $this->pdo->prepare('REPLACE INTO users (username,digesta1) VALUES( ? , ? )');
                        $stmt->execute(array($username,$logindigest));

Michael Kliewe

unread,
Jan 20, 2012, 7:04:46 AM1/20/12
to sabredav...@googlegroups.com
I also have written my own Auth Backend (using a custom database user table), and I have added a local APC cache. Maybe that's better than your SQL caching because if you have many users your SQL server gets a lot of queries. Caching the authentication result in APC for a minute or so removes network I/O and load on the SQL server.

So if you have installed APC you could think about that.
http://php.net/manual/de/book.apc.php

Robert George

unread,
Jan 20, 2012, 11:40:14 AM1/20/12
to sabredav...@googlegroups.com
Michael,
Since SabreDAV is using the database for everything, I don't see how using it for caching the login information would result any significant increase in load.

Evert Pot

unread,
Jan 20, 2012, 1:41:06 PM1/20/12
to sabredav...@googlegroups.com
Out of the box SabreDAV will do a lot of stuff directly on the database, mainly because I didn't yet want to commit to adding a default caching layer.

As it stands I feel the default PDO backends are not as efficient as they could be. Whenever I integrate SabreDAV at a customer, I tend to always rewrite the backends, and make them cache all sorts of things.

On Jan 20, 2012, at 5:40 PM, Robert George wrote:

> Michael,
> Since SabreDAV is using the database for everything, I don't see how using it for caching the login information would result any significant increase in load.
>

> --
> You received this message because you are subscribed to the Google Groups "SabreDAV Discussion" group.

> To view this discussion on the web visit https://groups.google.com/d/msg/sabredav-discuss/-/RRjo5VyQ4QsJ.

Reply all
Reply to author
Forward
0 new messages