Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Authentication support for IMAP or LDAP #52

Closed
johan-smits opened this issue Jan 9, 2013 · 22 comments
Closed

Authentication support for IMAP or LDAP #52

johan-smits opened this issue Jan 9, 2013 · 22 comments
Assignees

Comments

@johan-smits
Copy link

Authentication support for IMAP or LDAP for these backends makes it earsier to maintain authentication centralized and maybe automatic creation of users can also be implemented on a successfull authentication.

@phaidros7
Copy link

oh yeah, I opt for this as well. that'd be awesome!

@minami-o
Copy link

minami-o commented Feb 5, 2013

Well I was interested as well in IMAP authentication, and a quick google search led me to the googlegroups sabredav discussion where some knowledgeable developer (Robert George, all credits go to him) posted a simple yet working solution.
Here is the googlegroups discussion.
I adapted the code a tiny bit, so you can just copy and paste the following code in a new file BAIKAL_HOME/Core/Frameworks/SabreDav/lib/Sabre/DAV/Auth/Backend/IMAP.php

    <?php
    namespace Sabre\DAV\Auth\Backend;
    // Auth Class
    class IMAP extends 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));
                            imap_close( $imap );
                            return true;
                    }
            }
    }
    ?>      

Then, in cal.php, in the Backends section, you should replace the default PDO authentication as shown below:
Before:

    $authBackend = new \Sabre\DAV\Auth\Backend\PDO($GLOBALS["DB"]->getPDO());

After:

    $authBackend = new \Sabre\DAV\Auth\Backend\IMAP("{localhost:993/imap/ssl/novalidate-cert}",$GLOBALS["DB"]->getPDO(),60);

Notes:

  • The options "localhost:993/imap/ssl/novalidate-cert" are specific to my configuration, but ymmv. For more info on these options, just check the php manual .
  • With this "patch", the password set at user creation is no longer used: all users have to be defined as mail users as well as baikal users, and their mail password is used to access their calendars
  • Again, I just used the code created by Robert George and fine-tuned it to fit baikal, so all credits should go to him.

I hope this will be of some help ;)

@rphenix
Copy link

rphenix commented Feb 9, 2013

Thanks for posting a solution minami-o. This is exactly what I need to integrate Baikal with php-push2 (z-push).

I can connect using imap_open in a test php script with something similar to this:
$mbox = imap_open("{127.0.0.1:143/imap/notls}", "username", "password");
but when I try and use similar in cal.php I get:
Sabre\DAV\Exception\NotAuthenticated No basic authentication headers were found 1.8.0
this is my entry for cal.php:
$authBackend = new \Sabre\DAV\Auth\Backend\IMAP("{127.0.0.1:143/imap/notls}",$GLOBALS["DB"]->getPDO(),60);

Theres no error in apache log nor any sort of notification of an imap connection attempt in the imap logs any idea?

@michelkaeser
Copy link

Hmm, can't get it to work.

Basically I have adapted the code above to:

  • ignore modtime
  • not update user
  • string_replace username (so -- with . and --- with @) for IMAP auth.

However, mostly everything fails.

May it be cause of running nginx?

I've placed whole baikal standard to /usr/share/baikal and set document root to /usr/share/baikal/html as well as using the provided vhost. Seems to fail at auth however...

@minami-o
Copy link

Apologies, didn't have much time to give, lately.
Actually the code
worked almost out of the box for me, so I didn't have to check for
specific dependencies that might be required.
Before mod'ing it, did you
first try the code I provided as it was?
As per nginx, I'm really
ignorant on how it fits with php and whether the commands that are used
in the code are compatible with your architecture...
Maybe you could
provide error messages or logs to give us an idea of what exactly fails.

Le 2013-02-17 04:27, Michel a écrit :

Hmm, can't get it to work.

Basically I have adapted the code above to:

  • ignore
    modtime
  • not update user
  • string_replace username (so -- with .
    and --- with @) for IMAP auth.

However, mostly everything fails.

May it be cause of running nginx?

I've placed whole baikal
standard to /usr/share/baikal and set document root to
/usr/share/baikal/html as well as using the provided vhost. Seems to
fail at auth however...

Reply to this email directly or view
it on GitHub [1].

Links:

[1]
#52 (comment)

@michelkaeser
Copy link

No need to apologize :) I got it working...had to use another port/options for IMAP connection :) sometimes I still get "throw exception without stack trace", but it doesn't stop anything from working. :)

@minami-o
Copy link

OK good news and good job! :)

Le 2013-02-20 17:25, Michel a écrit
:

No need to apologize :) I got it working...had to use another
port/options for IMAP connection :) sometimes I still get "throw
exception without stack trace", but it doesn't stop anything from
working. :)

Reply to this email directly or view it on GitHub
[1].

Links:

[1]
#52 (comment)

@kingnarias
Copy link

is this also working with CRAM-MD5 ?

@renne
Copy link

renne commented Jun 14, 2014

@minami-o Can you fork Baikal, add the code and create a pull request?

@minami-o
Copy link

Hi Rene,
Unfortunately I've moved from Baikal to my own sabredav solution, before moving to owncloud, to have a more integrated solution (web-, cal- and card-dav, plus other functionalities).
I didn't keep any files from Baikal, so I really can't be of any help to you...

Good luck!

Minami-o

On 14 juin 2014 18:37:37 UTC+02:00, Rene Bartsch notifications@github.com wrote:

@minami-o Can you fork Baikal, add the code and create a pull request?


Reply to this email directly or view it on GitHub:
#52 (comment)

@RustyPixel
Copy link

Have a look at this pull request #204 i have tested it myself and it works, but wait for it to be officially added

@renne
Copy link

renne commented Jun 21, 2014

@jeromeschneider Will you add this pull request?

@stevenroose
Copy link

I'd really like LDAP support. It seems like #321 also is a FR for LDAP support.

@GuidoRed
Copy link

It's now June of 2015 and I have rewroted the code to Baikal 0.2.7 still using Sabre with DB table using username and digest A1 as a md5 hash of (username:realm:password). Using Dovecot IMAP server authentificated against 389 LDAP server I can authentificate users with Baikal as Calendar and Contacts with LDAP accounts, Not easy but works fine.

The changes to files, using the format PATH: and CHANGES:

PATH: .../vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/IMAP.php [Needs to be created]
CHANGES:
----- init of file

<?php

namespace Sabre\DAV\Auth\Backend;
use Sabre\DAV;

/**
 * IMAP authenticator
 *
 * This is an authenticator backend using an IMAP Server authentication (as Dovecot).
 * 
 * The backend IMAP must construct a digest based on a user + password valid connection
 * on the Sabre realm md5(
 *
 * Make sure your IMAP Server is properly configured for this to work.
 * And also after the construct needs to set de UserData (user,password)
 *
 * @copyright Copyright (C) 20015-? Guido based on Minami-O code.
 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
 */
class IMAP extends AbstractBasic
    {
            protected $imap_server;
            protected $pdo;
            protected $tableName;
            protected $username;
            protected $password;

    public function __construct($imap_server,\PDO $pdo, $tableName = 'users') {
        $this->imap_server = $imap_server;
        $this->pdo = $pdo;
        $this->tableName = $tableName;
    }

    public function setUserData ($username, $password) {
        $this->username = $username;
        $this->password = $password;
        return;
    }

    public function getDigestHash($realm,$username) {

         $stmt = $this->pdo->prepare('SELECT username, digesta1 FROM '.$this->tableName.' WHERE username = ?');
         $stmt->execute(array($username));
         $result = $stmt->fetchAll(); # Searching username on PDO
         try {
             $imap = imap_open($this->imap_server,$username,$password,OP_HALFOPEN);  # IMAP verification
         } catch (Exception $e) {  # User is not a valid IMAP account, checking against PDO
             if (!count($result)) 
                 return;
             else 
                 return $result[0]['digesta1'];
         }
         imap_close( $imap );
         $digesta1 = md5( $username . ':' . $realm . ':' . $this->password );
#         if (!count($result)) {  # If not Exist on database
# Add user in PDO
#         } else {
#         $stmt = $this->pdo->prepare('REPLACE INTO users (username,digesta1) VALUES( ? , ? )');
#         $stmt->execute(array($username,$digesta1));  # Update username and digest1
#         } 
         return $digesta1;
    }

---- end of file

PATH: .../Core/Frameworks/Baikal/Core/IMAPBasicAuth.php [Needs to be created]
---- init file

<?php

namespace Baikal\Core;

/**
 * This is an authentication backend that uses an IMAP Server to autentificate users and passwords.
 *
 * @copyright Copyright (C) 2015-? Guido . All rights reserved.
 * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
 */
class IMAPBasicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic {

    /**
     * Reference to IMAP Server
     *
     * @var PDO
     */
    protected $imap_server;

    /**
     * Reference to PDO connection
     *
     * @var PDO
     */
    protected $pdo;

    /**
     * Authentication realm
     *
     * @var string
     */
    protected $authRealm;

    /**
     * PDO table name we'll be using
     *
     * @var string
     */
    protected $tableName;

    /**
     * Creates the backend object.
     *
     * If the filename argument is passed in, it will parse out the specified file fist.
     *
     * @param string $imap_server Connection to IMAP Server
     * @param PDO $pdo
     * @param string $tableName The PDO table name to use
     */
    public function __construct($imap_server, \PDO $pdo, $authRealm, $tableName = 'users') {

        $this->imap_server = $imap_server;
        $this->pdo         = $pdo;
        $this->authRealm   = $authRealm;
        $this->tableName   = $tableName;
    }

    /**
     * Validates a username and password
     *
     * This method should return true or false depending on if login
     * succeeded.
     *
     * @param string $username
     * @param string $password
     * @return bool
     */
    public function validateUserPass($username, $password) {
         $stmt = $this->pdo->prepare('SELECT username, digesta1 FROM '.$this->tableName.' WHERE username = ?');
         $stmt->execute(array($username));
         $result = $stmt->fetchAll(); # Searching username on PDO

         $digesta1 = md5( $username . ':' . $this->authRealm . ':' . $password );
         try {
             $imap = imap_open($this->imap_server,$username,$password,OP_HALFOPEN);
         } catch (Exception $e) {  # Failed access to IMAP, checking agains PDO
             if (!count($result)) return false;
             if( $result[0]['digesta1'] == $digesta1 )
             {
                 $this->currentUser = $username;
                 return true;
             }
             return false;
         }
         imap_close( $imap );
#         if (!count($result)) { # if not exist on PDO
# Add user and digesta1 on table
#         } else {
#         $stmt = $this->pdo->prepare('REPLACE INTO users (username,digesta1) VALUES( ? , ? )');
#         $stmt->execute(array($username,$digesta1)); # Update user and digesta1
#         }
         $this->currentUser = $username;
         return true;

    }
}

---- end of file

PATH: sftp://ccbas2/var/calendario-www/Core/Frameworks/Baikal/WWWRoot/
FILES: cal.php and card.php [Neds to be fixed]
CHANGES:
---- fixing files starting on Backends mark, overwirte code

# Backends
if( BAIKAL_DAV_AUTH_TYPE == "Basic" || preg_match('/Windows-Phone-WebDAV-Client/i', $_SERVER['HTTP_USER_AGENT']) ) {
    $authBackend = new \Baikal\Core\PDOBasicAuth($GLOBALS["DB"]->getPDO(), BAIKAL_AUTH_REALM);
} elseif ( BAIKAL_DAV_AUTH_TYPE == "IMAP" ) {
    $authBackend = new \Baikal\Core\IMAPBasicAuth("{localhost:143/imap/notls}",$GLOBALS["DB"]->getPDO(), BAIKAL_AUTH_REALM);
#    $authBackend = new \Sabre\DAV\Auth\Backend\IMAP("{localhost:993/imap/ssl/novalidate-cert}",$GLOBALS["DB"]->getPDO());
#    $authBackend = new \Sabre\DAV\Auth\Backend\IMAP("{localhost:143/imap/notls}",$GLOBALS["DB"]->getPDO());
} else
    $authBackend = new \Sabre\DAV\Auth\Backend\PDO($GLOBALS["DB"]->getPDO());

---- end fixing

Select the IMAP connecting type that works for you:

  • "{localhost:143/imap/notls}"
  • "{localhost:993/imap/ssl/novalidate-cert}"

-- AND VERY IMPORTANT --- Please do this

PATH: .../Core/Frameworks/Baikal/Model/Config/Standard.php [Needs to be fixed]
CHANGES:
---- fixing file starting on BAIKAL_DAV_AUTH_TYPE field inside public function

formMorphologyForThisModelInstance() { 
        $oMorpho->add(new \Formal\Element\Listbox(array(
            "prop" => "BAIKAL_DAV_AUTH_TYPE",
            "label" => "WebDAV authentication type",
            "options" => array( "Basic","Digest","IMAP" ) #LDAP?
        )));

And That's all, change it and you are ready to connect over IMAP (and LDAP if are integrated)

But to test it, take in count that the web interface is only for admin propos, so other users can't use it. That why you need to test if it works using URLs, as shown:
CalDev: https://<your.baikal.server>/cal.php/calendars//default/
CardDev: https://<your.baikal.server>/card.php/addressbooks//default/
And will ask for a user and a password

Enjoy the mod, and if some one wants to make de branch please give me the proper credits.
El Guido.

@netgusto
Copy link
Member

@GuidoRed Thanks ! Could you maybe provide a pull request, so that we can integrate it in Baïkal ?

@GuidoRed
Copy link

Sorry, I'm not a git user fan neither have the time.

@netgusto
Copy link
Member

@GuidoRed I rewrote your comment so that the code is properly displayed.

@GuidoRed
Copy link

Thanks indeed, more clean and usable. Just do the same in the last part with the CalDev and CardDev URLs to show the hidden code.

@GuidoRed
Copy link

Would be usable to write also a pure LDAP Authentication code?

@ironstas1k
Copy link

@GuidoRed
[Wed Jun 24 14:54:18.838813 2015] [:error] [pid 5439] [client 172.31.2.27:55327] PHP Parse error: syntax error, unexpected end of file, expecting function (T_FUNCTION) in /var/www/baikal/vendor/sabre/dav/lib/DAV/Auth/Backend/IMAP.php on line 62

@anthony-b
Copy link

I managed to get this working on my Synology server but just to make note that the address displayed above: sftp://ccbas2/var/calendario-www/Core/Frameworks/Baikal/WWWRoot/ is actually the root of the Baikal install so this: sftp://ccbas2/var/calendario-www/Core/Frameworks is not needed

@evert
Copy link
Member

evert commented Jan 21, 2016

This issue was moved to fruux/Baikal2#17

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests