diff -urN mail/config/main.inc.php sso-mail/config/main.inc.php
--- mail/config/main.inc.php	2009-06-18 19:01:24.000000000 +0200
+++ sso-mail/config/main.inc.php	2009-06-24 20:56:47.000000000 +0200
@@ -414,5 +414,14 @@
 // If true all folders will be checked for recent messages
 $rcmail_config['check_all_folders'] = false;
 
+$rcmail_config['master_user'] = 'mail';
+$rcmail_config['master_password'] = 'secret';
+
+$rcmail_config['crowd_config'] = array (
+  'app_name' => 'mail',
+  'app_credential' => 'secret',
+  'service_url' => 'http://localhost:8095/services/SecurityServer?wsdl'
+);
+
 // end of config file
 ?>
diff -urN mail/index.php sso-mail/index.php
--- mail/index.php	2009-05-15 12:24:09.000000000 +0200
+++ sso-mail/index.php	2009-06-24 20:57:43.000000000 +0200
@@ -29,6 +29,7 @@
 
 // include environment
 require_once 'program/include/iniset.php';
+require_once 'include/rcube_crowd.php';
 
 // init application and start session with requested task
 $RCMAIL = rcmail::get_instance();
@@ -70,8 +71,38 @@
   raise_error(array('code' => hexdec($_GET['_code'])), FALSE, TRUE);
 }
 
+
+if (empty($RCMAIL->user->ID) && rcube_crowd::getInstance()->isAuthenticated()) {
+  $RCMAIL->kill_session();
+  $host = $RCMAIL->autoselect_host();
+
+  if (empty($_COOKIE)) {
+    $OUTPUT->show_message("cookiesdisabled", 'warning');
+  }
+  else if ($_SESSION['temp'] &&
+           $RCMAIL->login(rcube_crowd::getInstance()->getRemoteUser(), "crowd", $host)) {
+    unset($_SESSION['temp']);
+    rcube_sess_regenerate_id();
+
+    $RCMAIL->authenticate_session();
+
+    if ($RCMAIL->config->get('log_logins')) {
+      write_log('userlogins', sprintf('Successful CROWD login for %s (id %d) from %s',
+        $RCMAIL->user->get_username(),
+        $RCMAIL->user->ID,
+        $_SERVER['REMOTE_ADDR']));
+    }
+
+    $OUTPUT->redirect();
+  }
+  else {
+    $OUTPUT->show_message('loginfailed', 'warning');
+    $RCMAIL->kill_session();
+  }
+}
+
 // try to log in
-if ($RCMAIL->action=='login' && $RCMAIL->task=='mail') {
+else if ($RCMAIL->action=='login' && $RCMAIL->task=='mail') {
   // purge the session in case of new login when a session already exists 
   $RCMAIL->kill_session(); 
   
@@ -83,8 +114,9 @@
     $OUTPUT->show_message("cookiesdisabled", 'warning');
   }
   else if ($_SESSION['temp'] && !empty($_POST['_user']) && !empty($_POST['_pass']) &&
-           $RCMAIL->login(trim(get_input_value('_user', RCUBE_INPUT_POST), ' '),
-              get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host)) {
+           rcube_crowd::getInstance()->authenticate(trim(get_input_value('_user', RCUBE_INPUT_POST), ' '),
+              get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1')) &&
+	   $RCMAIL->login(rcube_crowd::getInstance()->getRemoteUser(), "crowd", $host)) {
     // create new session ID
     unset($_SESSION['temp']);
     rcube_sess_regenerate_id();
@@ -111,6 +143,7 @@
 
 // end session
 else if (($RCMAIL->task=='logout' || $RCMAIL->action=='logout') && isset($_SESSION['user_id'])) {
+  rcube_crowd::getInstance()->logoff();
   $OUTPUT->show_message('loggedout');
   $RCMAIL->logout_actions();
   $RCMAIL->kill_session();
diff -urN mail/program/include/iniset.php sso-mail/program/include/iniset.php
--- mail/program/include/iniset.php	2009-05-15 12:24:09.000000000 +0200
+++ sso-mail/program/include/iniset.php	2009-06-24 20:51:59.000000000 +0200
@@ -117,3 +117,5 @@
 
 // set PEAR error handling (will also load the PEAR main class)
 PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'rcube_pear_error');
+
+// BEGIN crowd integration
diff -urN mail/program/include/rcmail.php sso-mail/program/include/rcmail.php
--- mail/program/include/rcmail.php	2009-05-15 12:22:29.000000000 +0200
+++ sso-mail/program/include/rcmail.php	2009-06-24 04:41:21.000000000 +0200
@@ -385,7 +385,7 @@
     $conn = false;
     
     if ($_SESSION['imap_host'] && !$this->imap->conn) {
-      if (!($conn = $this->imap->connect($_SESSION['imap_host'], $_SESSION['username'], $this->decrypt_passwd($_SESSION['password']), $_SESSION['imap_port'], $_SESSION['imap_ssl']))) {
+      if (!($conn = $this->imap->connect($_SESSION['imap_host'], $_SESSION['username'] . '*' . $this->config->get('master_user'), $this->config->get('master_password'), $_SESSION['imap_port'], $_SESSION['imap_ssl']))) {
         if ($this->output)
           $this->output->show_message($this->imap->error_code == -1 ? 'imaperror' : 'sessionerror', 'error');
       }
@@ -469,7 +469,7 @@
       $username = $user->data['username'];
 
     // exit if IMAP login failed
-    if (!($imap_login  = $this->imap->connect($host, $username, $pass, $imap_port, $imap_ssl)))
+    if (!($imap_login  = $this->imap->connect($host, $username . '*' . $this->config->get('master_user'), $this->config->get('master_password'), $imap_port, $imap_ssl)))
       return false;
 
     // user already registered -> update user's record
@@ -770,6 +770,10 @@
       $valid = false;
     }
 
+    if (!rcube_crowd::getInstance()->isAuthenticated()) {
+      $valid = false;
+    }
+
     return $valid;
   }
 
diff -urN mail/program/include/rcube_crowd.php sso-mail/program/include/rcube_crowd.php
--- mail/program/include/rcube_crowd.php	1970-01-01 01:00:00.000000000 +0100
+++ sso-mail/program/include/rcube_crowd.php	2009-06-24 20:51:34.000000000 +0200
@@ -0,0 +1,49 @@
+<?php
+
+require_once('Services/Atlassian/HttpAuthenticator.php');
+
+class rcube_crowd
+{
+    static private $instance;
+    private $httpAuthenticator;
+    private $valid;
+
+    static function getInstance()
+    {
+	if (!self::$instance) {
+	    self::$instance = new rcube_crowd();
+	}
+        return self::$instance;
+    }
+
+    function __construct()
+    {
+	$this->httpAuthenticator = new Services_Atlassian_HttpAuthenticator(
+	  rcmail::get_instance()->config->get('crowd_config')
+	);
+    }
+
+    public function isAuthenticated()
+    {
+	if (isset($this->valid)) {
+	    return $this->valid;
+	}
+	$this->valid = $this->httpAuthenticator->isAuthenticated();
+	return $this->valid;
+    }
+
+    public function authenticate($username, $password)
+    {
+	return $this->httpAuthenticator->authenticate($username, $password);
+    }
+
+    public function logoff()
+    {
+	$this->httpAuthenticator->logoff();	
+    }
+
+    public function getRemoteUser()
+    {
+	return $this->httpAuthenticator->getRemoteUser();
+    }
+}
diff -urN mail/program/lib/Services/Atlassian/Crowd/Exception.php sso-mail/program/lib/Services/Atlassian/Crowd/Exception.php
--- mail/program/lib/Services/Atlassian/Crowd/Exception.php	1970-01-01 01:00:00.000000000 +0100
+++ sso-mail/program/lib/Services/Atlassian/Crowd/Exception.php	2009-01-27 14:49:01.000000000 +0100
@@ -0,0 +1,53 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Exception used to incidate a problem authenticating to the Crowd server.
+ *
+ * Services_Atlassian_Crowd is a package to use Atlassian Crowd from PHP
+ *
+ * PHP version 5
+ * 
+ * Copyright (C) 2008 Infinite Campus Inc., Luca Corbo
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @category  Services
+ * @package   Services_Atlassian_Crowd
+ * @author    Infinite Campus, Inc.
+ * @author    Luca Corbo <lucor@php.net>
+ * @copyright 2008 Infinite Campus Inc., Luca Corbo
+ * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache License
+ * @link      http://pear.php.net/packages/Services_Atlassian_Crowd
+ */
+
+/**
+ * PEAR Exception handler and base class
+ */
+require_once 'PEAR/Exception.php';
+
+/**
+ * Services_Atlassian_Crowd_Exception
+ *
+ * @category  Services
+ * @package   Services_Atlassian_Crowd
+ * @author    Infinite Campus, Inc.
+ * @author    Luca Corbo <lucor@php.net>
+ * @copyright 2008 Infinite Campus Inc., Luca Corbo
+ * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache License
+ * @link      http://pear.php.net/packages/Services_Atlassian_Crowd
+ */
+class Services_Atlassian_Crowd_Exception extends PEAR_Exception
+{
+}
+?>
\ No newline at end of file
diff -urN mail/program/lib/Services/Atlassian/Crowd.php sso-mail/program/lib/Services/Atlassian/Crowd.php
--- mail/program/lib/Services/Atlassian/Crowd.php	1970-01-01 01:00:00.000000000 +0100
+++ sso-mail/program/lib/Services/Atlassian/Crowd.php	2009-06-24 11:19:35.000000000 +0200
@@ -0,0 +1,276 @@
+<?php
+/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
+
+/**
+ * Services_Atlassian_Crowd is a package to use Atlassian Crowd from PHP
+ *
+ * Crowd is a web-based single sign-on (SSO) tool 
+ * that simplifies application provisioning and identity management.
+ * 
+ * This package is derived from the PHP Client Library for Atlassian Crowd
+ * class written by Infinite Campus, Inc.
+ * 
+ * PHP version 5
+ * 
+ * Copyright (C) 2008 Infinite Campus Inc., 2008 Luca Corbo
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @category  Services
+ * @package   Services_Atlassian_Crowd
+ * @author    Infinite Campus, Inc.
+ * @author    Luca Corbo <lucor@php.net>
+ * @copyright 2008 Infinite Campus Inc., 2008 Luca Corbo
+ * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache License
+ * @link      http://pear.php.net/packages/Services_Atlassian_Crowd
+ * @link      http://www.atlassian.com/software/crowd
+ * @link      http://confluence.atlassian.com/display/CROWD/SOAP+API
+ * @link      http://confluence.atlassian.com/display/CROWDEXT/Integrate+Crowd+with+PHP
+ */
+
+/**
+ * Exception used to incidate a problem with the Crowd server.
+ */
+require_once 'Services/Atlassian/Crowd/Exception.php';
+
+/**
+ * Class to use Crowd API from PHP
+ * 
+ * @category  Services
+ * @package   Services_Atlassian_Crowd
+ * @author    Infinite Campus, Inc.
+ * @author    Luca Corbo <lucor@php.net>
+ * @copyright 2008 Infinite Campus Inc., 2008 Luca Corbo
+ * @license   http://www.apache.org/licenses/LICENSE-2.0 Apache License
+ * @link      http://pear.php.net/packages/Services_Atlassian_Crowd
+ * @link      http://www.atlassian.com/software/crowd
+ * @link      http://confluence.atlassian.com/display/CROWD/SOAP+API
+ * @link      http://confluence.atlassian.com/display/CROWDEXT/Integrate+Crowd+with+PHP
+ */
+class Services_Atlassian_Crowd
+{
+
+    /**
+     * The Crowd SOAP client
+     *
+     * @var object
+     */
+    protected $crowd_client;
+
+    /**
+     * Array contains the configuration parameters
+     *
+     * @var array
+     */
+    protected $crowd_config;
+    
+    /**
+     * The Crowd application token
+     *
+     * @var string
+     */
+    protected $crowd_app_token;
+
+    /**
+     * The options required in configuration
+     * 
+     * @see __construct
+     * @var array
+     */
+    private $_crowd_required_options = array('app_name', 'app_credential', 'service_url');
+    
+    /**
+     * Create an application client using the passed in configuration parameters.
+     * 
+     * Available options are:
+     * 
+     * - string  app_name:  The username which the application will use when it 
+     *                      authenticates against the Crowd framework as a client.
+     *
+     * - string  app_credential: The password which the application will use when it 
+     *                           authenticates against the Crowd framework 
+     *                           as a client.
+     * 
+     * - string  service_url: The SOAP WSDL URL for Crowd
+     *
+     * @param array $options optional. An array of options used to connect to Crowd.
+     * 
+     * @throws Services_Atlassian_Crowd_Exception if there is an error communicating
+     *                                            with the Crowd security server.
+     */
+    public function __construct($options, $crowd_app_token)
+    {
+        //Check for required parameters 
+        foreach ($this->_crowd_required_options as $option) {
+            if (!array_key_exists($option, $options)) {
+                $exception_message = $option . ' is required!';
+                throw new Services_Atlassian_Crowd_Exception($exception_message); 
+            }    
+        }
+
+        $this->crowd_config = $options;
+
+        // Create the Crowd SOAP client
+        try {
+            $this->crowd_client = new SoapClient($this->crowd_config['service_url']);
+        } catch (SoapFault $fault) {
+            $exception_message = 'Unable to connect to Crowd. Verify the service_url ' . 
+                                 'property is defined and Crowd is running.';
+            throw new Services_Atlassian_Crowd_Exception($exception_message . "\n" .
+                                                         $fault->getMessage(), 
+                                                         $fault);
+        }
+
+	if (isset($crowd_app_token)) {
+	    $this->crowd_app_token = $crowd_app_token;
+	}
+    }
+
+    /**
+     * Authenticates an application client to the Crowd security server.
+     * 
+     * @return string the application token
+     * @throws Services_Atlassian_Crowd_Exception if there is an error communicating
+     *                                            with the Crowd security server.
+     */
+    public function authenticateApplication()
+    {
+        $credential = array('credential' => $this->crowd_config['app_credential']);
+        $name       = $this->crowd_config['app_name'];
+        $param      = array('in0' => array('credential' => $credential,
+                                           'name'       => $name));
+        
+        $exception_message = 'Unable to login to Crowd. Verify the app_name and' . 
+                             'app_credential properties are defined and valid.';
+        try {
+            $resp = $this->crowd_client->authenticateApplication($param);
+            
+            $this->crowd_app_token = $resp->out->token;
+    
+            if (empty($this->crowd_app_token)) {
+                throw new Services_Atlassian_Crowd_Exception($exception_message . "\n" .
+                                                             $fault->getMessage());
+            }
+        } catch (SoapFault $fault) {
+            throw new Services_Atlassian_Crowd_Exception($exception_message . "\n" .
+                                                         $fault->getMessage(), $fault);
+        }
+
+        return $this->crowd_app_token;
+    }
+
+    /**
+     * Authenticates a principal to the Crowd security server 
+     * for the application client.
+     * 
+     * @param string $name           The username to authenticate
+     * @param string $credential     The password of the user to authenticate
+     * @param string $user_agent     The user agent
+     * @param string $remote_address The remote address
+     * 
+     * @return string the principal token
+     * @throws Services_Atlassian_Crowd_Exception if there is an error communicating
+     *                                            with the Crowd security server.
+     */
+    public function authenticatePrincipal($name, $credential, $user_agent, $remote_address)
+    {
+
+        // Build the parameter used to authenticate the principal
+        $param = array('in0' => array('name'  => $this->crowd_config['app_name'],
+                                      'token' => $this->crowd_app_token),
+                       'in1' => array('application' => $this->crowd_config['app_name'],
+                                      'credential'  => array('credential' => $credential),
+                                      'name'        => $name,
+                                      'validationFactors' => array(array('name'  => 'User-Agent',
+                                                                         'value' => $user_agent),
+                                                                   array('name'  => 'remote_address', 
+                                                                         'value' => $remote_address))));
+
+        // Attempt to authenticate the user (principal) via Crowd.
+        try {
+            $resp = $this->crowd_client->authenticatePrincipal($param);
+        } catch (SoapFault $fault) {
+            throw new Services_Atlassian_Crowd_Exception($fault->getMessage(), $fault);
+            
+        }
+
+        // Get the principal's token
+        return $resp->out;
+    }
+
+    /**
+     *  Calls a remote method
+     * 
+     * @param string $method The remote method to call
+     * @param mixed  $args   The parameters to use with remote method
+     * 
+     * @return object | true
+     * @throws Services_Atlassian_Crowd_Exception if there is an error communicating
+     *                                            with the Crowd security server.
+     * 
+     * @method    object isValidPrincipalToken(array($princ_token, $user_agent, $remote_address)) 
+     *                    Determines if the principal's current token is still valid in Crowd.
+     * @method    boolean invalidatePrincipalToken(string $princ_token) 
+     *                    Invalidates a token for for this principal for all application clients in Crowd.
+     * @method    object findPrincipalByToken(string $princ_token) 
+     *                   Finds a principal by token.
+     * @method    object findGroupMemberships(string $princ_name) 
+     *                   Finds all of the groups the specified principal is in.
+     * 
+     */
+    
+    public function __call($method, $args)
+    {
+        if (!is_array($args)) {
+            $args[0] = $args;
+        }
+        
+        //Supported methods of Crowd's API
+        switch ($method) {
+        case 'findGroupMemberships':
+        case 'findPrincipalByToken':
+        case 'invalidatePrincipalToken':
+            $params = array('in0' => array('name'  => $this->crowd_config['app_name'],
+                                           'token' => $this->crowd_app_token),
+                            'in1' => $args[0]);
+            break;
+        case 'isValidPrincipalToken':
+            $params = array('in0' => array('name'  => $this->crowd_config['app_name'],
+                                           'token' => $this->crowd_app_token),
+                            'in1' => $args[0],
+                            'in2' => array(array('name'  => 'User-Agent',
+                                                 'value' => $args[1]),
+                                           array('name'  => 'remote_address', 
+                                                 'value' => $args[2])));
+            break;
+        default:
+            throw new Services_Atlassian_Crowd_Exception(
+                'Method (' . $method . ') is not implemented'
+            );
+            break;
+        }
+                
+        try {
+            $resp = $this->crowd_client->$method($params);
+            if (isset($resp->out)) {
+                return $resp->out;
+            } else {
+                return true;
+            }
+        } catch (SoapFault $fault) {
+            throw new Services_Atlassian_Crowd_Exception($fault->getMessage(),
+                                                         $fault);
+        }
+    }
+}
+?>
diff -urN mail/program/lib/Services/Atlassian/HttpAuthenticator.php sso-mail/program/lib/Services/Atlassian/HttpAuthenticator.php
--- mail/program/lib/Services/Atlassian/HttpAuthenticator.php	1970-01-01 01:00:00.000000000 +0100
+++ sso-mail/program/lib/Services/Atlassian/HttpAuthenticator.php	2009-06-24 13:16:41.000000000 +0200
@@ -0,0 +1,124 @@
+<?php
+
+require_once('Services/Atlassian/Crowd.php');
+
+class Services_Atlassian_HttpAuthenticator
+{
+    private $crowd;
+    private $appToken;
+
+    function __construct($options)
+    {
+    	$config = $crowd_config;
+	$this->appToken = apc_fetch('rcube_crowd.app_token', &$success);
+	$this->crowd = new Services_Atlassian_Crowd($options, $this->appToken);
+	if ($success && isset($this->appToken)) {
+	    $this->appToken = $crowd_app_token;
+	} else {
+	    $this->authenticateApplication();
+	}
+    }
+
+    private function authenticateApplication()
+    {
+	$this->appToken = $this->crowd->authenticateApplication();
+	apc_store('rcube_crowd.app_token', $this->appToken);
+    }
+
+    public function isAuthenticated($retry = true)
+    {
+	$tokenKey = $this->getTokenKey();
+	if (!isset($tokenKey)) {
+	    return false;
+	}
+
+	$userAgent = $this->getUserAgent();
+	$remoteAddress = $this->getRemoteAddress();
+	
+	try {
+	    $valid = $this->crowd->isValidPrincipalToken($tokenKey, $userAgent, $remoteAddress);
+	} catch (Services_Atlassian_Crowd_Exception $e) {
+	    if ($retry) {
+	        $this->authenticateApplication();
+		return $this->isAuthenticated(false);
+	    } else {
+		return false;
+	    }
+	}
+	return $valid;
+    }
+
+    public function authenticate($username, $password, $retry = true)
+    {
+	$userAgent = $this->getUserAgent();
+	$remoteAddress = $this->getRemoteAddress();
+
+	try {
+	    $tokenKey = $this->crowd->authenticatePrincipal($username, $password, $userAgent, $remoteAddress);
+	} catch (Services_Atlassian_Crowd_Exception $e) {
+	    if ($retry) {
+	        $this->authenticateApplication();
+		return $this->authenticate($username, $password, false);
+	    } else {
+		return false;
+	    }
+	}
+	$this->setCrowdCookie($tokenKey);
+	return true;
+    }
+
+    public function logoff()
+    {
+    	try {
+	    $this->crowd->invalidatePrincipalToken($this->getTokenKey());
+	} catch (Services_Atlassian_Crowd_Exception $e) {
+	    // ignore
+	}
+    }
+
+    public function getRemoteUser($retry = true)
+    {
+	$tokenKey = $this->getTokenKey();
+
+	try {
+	    $principal = $this->crowd->findPrincipalByToken($tokenKey);
+	} catch (Services_Atlassian_Crowd_Exception $e) {
+	    if ($retry) {
+	        $this->authenticateApplication();
+		return $this->getRemoteUser(false);
+	    } else {
+		throw $e;
+	    }
+	}
+	return $principal->name;
+    }
+
+    private function getTokenKey()
+    {
+    	return $_COOKIE['crowd_token_key'];
+    }
+
+    private function setCrowdCookie($tokenKey)
+    {
+	setcookie(
+	  'crowd.token_key'     /* name */,
+	  $tokenKey,            /* value */
+	  0,                    /* expire: unix timestamp, 0 means at the end of the browser session */
+	  '/',                  /* path */
+	  null,                 /* domain */
+	  false,                /* secure: only sent over encrypted channel (i.e. HTTPS) */
+	  true                  /* httponly: only through HTTP, no access by JavaScript, etc. */
+	);
+	$_COOKIE['crowd_token_key'] = $tokenKey;
+    }
+
+    private function getUserAgent()
+    {
+    	return $_SERVER['HTTP_USER_AGENT'];
+    }
+
+    private function getRemoteAddress()
+    {
+    	return $_SERVER['HTTP_X_FORWARDED_FOR'];
+    }
+}
