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));
|
$url->setQueryVariables(array('method' => 'authenticate', 'version' => self::API_VERSION));
|
||||||
$request->setUrl($url);
|
$request->setUrl($url);
|
||||||
$request->setAuth($this->rc->user->get_username(), $this->rc->decrypt($_SESSION['password']));
|
$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();
|
$response = $request->send();
|
||||||
$status = $response->getStatus();
|
$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.
|
services. Currently the only supported method of authentication is OpenID Connect.
|
||||||
|
|
||||||
Because Kolab backends do not support token authentication it is required
|
Because Kolab backends do not support token authentication it is required
|
||||||
to use master user (sasl proxy) authentication, i.e. you have to put
|
to use master user (sasl proxy) authentication where possible and service
|
||||||
master user credentials in plugin's config. For the same reason and also because
|
user credentials in other places. See IMPLEMENTATION NOTES below for details.
|
||||||
the same master user does not work in Postfix, you have to specify SMTP connection
|
|
||||||
parameters/user+password.
|
|
||||||
|
|
||||||
Plugin requires libkolab plugin and HTTP/Request2 library.
|
Plugin requires libkolab plugin and HTTP/Request2 library.
|
||||||
Plugin contains BSD-licensed https://github.com/firebase/php-jwt (v5.0.0) 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.
|
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
|
TODO
|
||||||
----
|
----
|
||||||
|
|
||||||
- SMTP auth
|
|
||||||
- LDAP addressbook
|
- LDAP addressbook
|
||||||
- kolab_delegation (LDAP auth)
|
- kolab_delegation (LDAP auth)
|
||||||
- Chwala auth (+Seafile, +WebDAV)
|
- Chwala+Seafile
|
||||||
|
- Chwala+WebDAV
|
||||||
- Freebusy auth
|
- Freebusy auth
|
||||||
- Mattermost auth
|
- Mattermost auth
|
||||||
- Improved token validation
|
- Extended token validation
|
||||||
|
|
|
@ -34,17 +34,15 @@ class kolab_sso extends rcube_plugin
|
||||||
*/
|
*/
|
||||||
public function init()
|
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.
|
$this->add_hook('startup', array($this, 'startup'));
|
||||||
if (!($this->rc instanceof rcmail)) {
|
$this->add_hook('authenticate', array($this, 'authenticate'));
|
||||||
return;
|
|
||||||
|
$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)
|
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) {
|
if (!$internal) {
|
||||||
$args['user'] = $email;
|
$args['user'] = $email;
|
||||||
$args['pass'] = 'fake-sso-password';
|
$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('storage_connect', array($this, 'storage_connect'));
|
||||||
$this->add_hook('managesieve_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('smtp_connect', array($this, 'smtp_connect'));
|
||||||
|
$this->add_hook('chwala_authenticate', array($this, 'chwala_authenticate'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $args;
|
return $args;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Login_after hook handler
|
* Shutdown handler
|
||||||
*/
|
*/
|
||||||
public function login_after($args)
|
public function shutdown()
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
// Between startup and authenticate the session is destroyed.
|
// Between startup and authenticate the session is destroyed.
|
||||||
// So, we save the data later than that.
|
// 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));
|
$_SESSION['sso_data'] = $this->rc->encrypt(json_encode($this->data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $args;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,6 +209,21 @@ class kolab_sso extends rcube_plugin
|
||||||
return $args;
|
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
|
* Login form object
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue