SSO + Chwala, and some improvements
Requires: https://github.com/roundcube/roundcubemail/commit/edd9c31d6c69f4f https://git.kolab.org/rC76f9b695c55cb118e317d760965c6e23b44dff86
This commit is contained in:
parent
2efad48657
commit
0abee6c0f0
3 changed files with 89 additions and 37 deletions
|
@ -999,6 +999,10 @@ class kolab_files_engine
|
|||
$url->setQueryVariables(array('method' => 'authenticate', 'version' => self::API_VERSION));
|
||||
$request->setUrl($url);
|
||||
$request->setAuth($this->rc->user->get_username(), $this->rc->decrypt($_SESSION['password']));
|
||||
|
||||
// Allow plugins (e.g. kolab_sso) to modify the request
|
||||
$this->rc->plugins->exec_hook('chwala_authenticate', array('request' => $request));
|
||||
|
||||
$response = $request->send();
|
||||
$status = $response->getStatus();
|
||||
|
||||
|
|
|
@ -5,10 +5,8 @@ This plugin adds possibility to authenticate users via external authentication
|
|||
services. Currently the only supported method of authentication is OpenID Connect.
|
||||
|
||||
Because Kolab backends do not support token authentication it is required
|
||||
to use master user (sasl proxy) authentication, i.e. you have to put
|
||||
master user credentials in plugin's config. For the same reason and also because
|
||||
the same master user does not work in Postfix, you have to specify SMTP connection
|
||||
parameters/user+password.
|
||||
to use master user (sasl proxy) authentication where possible and service
|
||||
user credentials in other places. See IMPLEMENTATION NOTES below for details.
|
||||
|
||||
Plugin requires libkolab plugin and HTTP/Request2 library.
|
||||
Plugin contains BSD-licensed https://github.com/firebase/php-jwt (v5.0.0) library.
|
||||
|
@ -36,13 +34,32 @@ For the above "alias" plugin configuration should include 'response_uri' = '/sso
|
|||
and on the provider side configured URI will be https://host/roundcubemail/sso.
|
||||
|
||||
|
||||
IMPLEMENTATION NOTES
|
||||
--------------------
|
||||
|
||||
[IMAP] Because Kolab backend do not support token authentication it is required
|
||||
to use master user (sasl proxy) authentication, i.e. you have to put
|
||||
master user credentials in plugin's config.
|
||||
|
||||
[SMTP] For the same reason and also because the same master user does not work in Postfix,
|
||||
you have to specify SMTP connection parameters/user+password.
|
||||
|
||||
[Freebusy] Authentication into kolab-freebusy service is not yet implemented. A solution for
|
||||
now is to add Roundcube host(s) into trustednetworks.allow option in kolab-freebusy service config.
|
||||
|
||||
[Chwala] Authentication to Chwala will work if it uses the same (session) database as Roundcube.
|
||||
Additionally set $config['fileapi_plugins'] = array('kolab_sso', 'kolab_auth', 'kolab_folders');
|
||||
Authenticating to Seafile/WebDAV storage is not supported (until it's custom user-defined
|
||||
storage with saved password).
|
||||
|
||||
|
||||
TODO
|
||||
----
|
||||
|
||||
- SMTP auth
|
||||
- LDAP addressbook
|
||||
- kolab_delegation (LDAP auth)
|
||||
- Chwala auth (+Seafile, +WebDAV)
|
||||
- Chwala+Seafile
|
||||
- Chwala+WebDAV
|
||||
- Freebusy auth
|
||||
- Mattermost auth
|
||||
- Improved token validation
|
||||
- Extended token validation
|
||||
|
|
|
@ -34,17 +34,15 @@ class kolab_sso extends rcube_plugin
|
|||
*/
|
||||
public function init()
|
||||
{
|
||||
$this->rc = rcube::get_instance();
|
||||
// Roundcube or Chwala
|
||||
if (defined('RCMAIL_VERSION') || defined('FILE_API_START')) {
|
||||
$this->rc = rcube::get_instance();
|
||||
|
||||
// Disable the plugin in Syncroton, iRony, etc.
|
||||
if (!($this->rc instanceof rcmail)) {
|
||||
return;
|
||||
$this->add_hook('startup', array($this, 'startup'));
|
||||
$this->add_hook('authenticate', array($this, 'authenticate'));
|
||||
|
||||
$this->rc->add_shutdown_function(array($this, 'shutdown'));
|
||||
}
|
||||
|
||||
$this->add_hook('startup', array($this, 'startup'));
|
||||
$this->add_hook('ready', array($this, 'ready'));
|
||||
$this->add_hook('login_after', array($this, 'ready'));
|
||||
$this->add_hook('authenticate', array($this, 'authenticate'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -116,7 +114,41 @@ class kolab_sso extends rcube_plugin
|
|||
*/
|
||||
public function authenticate($args, $internal = false)
|
||||
{
|
||||
if (!empty($this->data) && ($email = $this->data['email'])) {
|
||||
// Chwala
|
||||
if (defined('FILE_API_START') && !$internal && empty($args['pass']) && strpos($args['user'], 'RC:') === 0) {
|
||||
// extract session ID and username from the token
|
||||
list(, $sess_id, $user) = explode(':', $args['user']);
|
||||
|
||||
// unset user, set invalid state
|
||||
$args['valid'] = false;
|
||||
$args['user'] = null;
|
||||
|
||||
$session = rcube_session::factory($this->rc->config);
|
||||
|
||||
if ($data = $session->read($sess_id)) {
|
||||
// get SSO data from the existing session
|
||||
$old_session = $_SESSION;
|
||||
session_decode($data);
|
||||
$session_user = $_SESSION['username'];
|
||||
$data = $_SESSION['sso_data'];
|
||||
$_SESSION = $old_session;
|
||||
|
||||
// TODO: allow only configured REMOTE_ADDR?
|
||||
if ($session_user == $user && $data && ($data = json_decode($this->rc->decrypt($data), true)) && ($mode = $data['mode'])) {
|
||||
$driver = $this->get_driver($mode);
|
||||
|
||||
// Session validation, token refresh, etc.
|
||||
if ($this->data = $driver->validate_session($data)) {
|
||||
$args['user'] = $user;
|
||||
$args['pass'] = 'fake-sso-password';
|
||||
$args['valid'] = true;
|
||||
$this->authenticate(array(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Roundcube
|
||||
else if (!empty($this->data) && ($email = $this->data['email'])) {
|
||||
if (!$internal) {
|
||||
$args['user'] = $email;
|
||||
$args['pass'] = 'fake-sso-password';
|
||||
|
@ -130,38 +162,22 @@ class kolab_sso extends rcube_plugin
|
|||
$this->add_hook('storage_connect', array($this, 'storage_connect'));
|
||||
$this->add_hook('managesieve_connect', array($this, 'storage_connect'));
|
||||
$this->add_hook('smtp_connect', array($this, 'smtp_connect'));
|
||||
$this->add_hook('chwala_authenticate', array($this, 'chwala_authenticate'));
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login_after hook handler
|
||||
* Shutdown handler
|
||||
*/
|
||||
public function login_after($args)
|
||||
{
|
||||
// Between startup and authenticate the session is destroyed.
|
||||
// So, we save the data later than that. Here, because of
|
||||
// a redirect after successful login
|
||||
if (!empty($this->data)) {
|
||||
$_SESSION['sso_data'] = $this->rc->encrypt(json_encode($this->data));
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ready hook handler
|
||||
*/
|
||||
public function ready($args)
|
||||
public function shutdown()
|
||||
{
|
||||
// Between startup and authenticate the session is destroyed.
|
||||
// So, we save the data later than that.
|
||||
if (!empty($this->data)) {
|
||||
if (!empty($this->data) && !empty($_SESSION['user_id'])) {
|
||||
$_SESSION['sso_data'] = $this->rc->encrypt(json_encode($this->data));
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -193,6 +209,21 @@ class kolab_sso extends rcube_plugin
|
|||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Chwala_authenticate hook handler
|
||||
*/
|
||||
public function chwala_authenticate($args)
|
||||
{
|
||||
// Instead of normal basic auth with user/pass we'll use
|
||||
// Authorization: Bearer <roundcube session id>
|
||||
$bearer = 'RC:' . session_id() . ':' . $_SESSION['username'];
|
||||
|
||||
$args['request']->setAuth(null);
|
||||
$args['request']->setHeader('Authorization', 'Bearer ' . base64_encode($bearer));
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Login form object
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue