diff --git a/framework/Core/lib/Horde/Core/Dav/Auth.php b/framework/Core/lib/Horde/Core/Dav/Auth.php new file mode 100644 index 00000000000..1924473c507 --- /dev/null +++ b/framework/Core/lib/Horde/Core/Dav/Auth.php @@ -0,0 +1,41 @@ + + * @category Horde + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + * @package Core + */ + +/** + * Extends Horde's authentication backend for Sabre to support username hooks. + * + * @author Jan Schneider + * @category Horde + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + * @package Core + */ +class Horde_Core_Dav_Auth extends Horde_Dav_Auth +{ + /** + * Returns information about the currently logged in username. + * + * If nobody is currently logged in, this method should return null. + * + * @return string|null + */ + public function getCurrentUser() + { + $user = $this->_auth->getCredential('userId'); + try { + $user = $GLOBALS['injector']->getInstance('Horde_Core_Hooks') + ->callHook('davusername', 'horde', array($user, false)); + } catch (Horde_Exception_HookNotSet $e) { + } + return $user; + } +} diff --git a/framework/Core/lib/Horde/Core/Factory/DavServer.php b/framework/Core/lib/Horde/Core/Factory/DavServer.php index dc93de23c43..d24cd4a0994 100644 --- a/framework/Core/lib/Horde/Core/Factory/DavServer.php +++ b/framework/Core/lib/Horde/Core/Factory/DavServer.php @@ -38,7 +38,7 @@ public function create(Horde_Injector $injector) ->create() ) ), - $injector->getInstance('Horde_Core_Factory_Identity_UsernameHook') + $injector->getInstance('Horde_Core_Factory_Identity_DavUsernameHook') ); $principals = new DAVACL\PrincipalCollection($principalBackend); $principals->disableListing = $conf['auth']['list_users'] == 'input'; @@ -62,7 +62,7 @@ public function create(Horde_Injector $injector) ); $server->addPlugin( new DAV\Auth\Plugin( - new Horde_Dav_Auth( + new Horde_Core_Dav_Auth( $injector->getInstance('Horde_Core_Factory_Auth')->create() ), 'Horde DAV Server' diff --git a/framework/Core/lib/Horde/Core/Factory/Identity/DavUsernameHook.php b/framework/Core/lib/Horde/Core/Factory/Identity/DavUsernameHook.php new file mode 100644 index 00000000000..a1cd9f85b40 --- /dev/null +++ b/framework/Core/lib/Horde/Core/Factory/Identity/DavUsernameHook.php @@ -0,0 +1,44 @@ + + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + */ + +/** + * A Horde_Injector based Horde_Identity factory that converts the user name + * through the davusername hook. + * + * @category Horde + * @package Core + * @author Jan Schneider + * @license http://www.horde.org/licenses/lgpl21 LGPL 2.1 + */ +class Horde_Core_Factory_Identity_DavUsernameHook extends Horde_Core_Factory_Identity_UsernameHook +{ + /** + * Returns the Horde_Identity instance. + * + * @param string $user The user to use, if not the current user. + * @param string $driver The identity driver. Either empty (use default + * driver) or an application name. + * + * @return Horde_Identity The singleton identity instance. + * @throws Horde_Exception + */ + public function create($user = null, $driver = null) + { + try { + $user = $this->_injector->getInstance('Horde_Core_Hooks') + ->callHook('davusername', 'horde', array($user, true)); + } catch (Horde_Exception_HookNotSet $e) { + } + return parent::create($user, $driver); + } +} diff --git a/framework/Core/package.xml b/framework/Core/package.xml index 68ca9267544..3b0b48dae41 100644 --- a/framework/Core/package.xml +++ b/framework/Core/package.xml @@ -28,10 +28,10 @@ mrubinsk@horde.org yes - 2016-03-08 + 2016-05-02 - 2.23.1 - 2.23.0 + 2.24.0 + 2.24.0 stable @@ -39,6 +39,7 @@ LGPL-2.1 +* [jan] Add classes to support the Horde 6 davusername hook. * [jan] Fix session_regenerate_id() warnings with PHP 7. * [jan] Fix running garbage collection on cached CSS and JS files (Bug #14285). @@ -400,6 +401,9 @@ + + + @@ -408,6 +412,7 @@ + @@ -1821,6 +1826,7 @@ + @@ -1897,6 +1903,7 @@ + @@ -4166,14 +4173,15 @@ - 2.23.1 - 2.23.0 + 2.24.0 + 2.24.0 stable stable - 2016-03-08 + 2016-05-02 LGPL-2.1 +* [jan] Add classes to support the Horde 6 davusername hook. * [jan] Fix session_regenerate_id() warnings with PHP 7. * [jan] Fix running garbage collection on cached CSS and JS files (Bug #14285). diff --git a/horde/config/hooks.php.dist b/horde/config/hooks.php.dist index ca9ecb3460a..af2d6d74ea6 100644 --- a/horde/config/hooks.php.dist +++ b/horde/config/hooks.php.dist @@ -120,6 +120,22 @@ * [throw Horde_Auth_Exception] - Fatal error. * (string) - The converted username. * + * davusername + * ----------- + * This hook is used to dynamically convert between a username for DAV clients + * and a Horde username. + * + * May for example be used to add some realm to user names referring to an IMAP + * server that would otherwise be picked from the login screen. + * + * Parameters in: + * $userId (string): The username. + * $toHorde (boolean): If true, convert from DAV ID to Horde ID. + * Otherwise, do the reverse conversion. + * + * The return value from this hook is as follows: + * (string) - The converted username. + * * x509_validate * ------------- * This hook is called during initial authentication when using the X509 client @@ -619,6 +635,64 @@ class Horde_Hooks // } +// // DAV USERNAME HOOK: See above for description of format. +// public function davusername($userId, $toHorde) +// { +// // Example: append realm to user name +// global $registry; +// +// if (!$userId) { +// return $userId; +// } +// +// $server = $registry->mail->server(); +// $realm = $server['hostspec']; +// if ($toHorde) { +// return (substr($userId, -strlen($realm)) == $realm) +// ? substr($userId, 0, -strlen($realm) - 1) +// : $userId; +// } +// +// return Horde_String::lower($userId) . '@' . $realm; +// } +// +// // The following hook examples may pick up the realm information from +// // above: +// // +// // public function pushapp() +// // { +// // if (strpos($_SERVER['REQUEST_URI'], '/rpc') && +// // preg_match('/@([^\/]*)/', $_SERVER['REQUEST_URI'], $m)) { +// // // Parse the domain part from the user name in the URL, and +// // // save it as the realm. +// // putenv('REALM=' . basename($m[1])); +// // } +// // } +// // +// // public function preauthenticate($userId, $credentials) +// // { +// // global $registry; +// // $result = array('userId' => $userId, 'credentials' => $credentials); +// // if ($credentials['authMethod'] == 'authenticate' && +// // strpos($_SERVER['REQUEST_URI'], '/rpc') && +// // ($realm = getenv('REALM'))) { +// // // If this was realm'ed RPC request, pick the correct server +// // // from IMP's backend configuration. +// // $servers = $registry +// // ->loadConfigFile('backends.php', 'servers', 'imp') +// // ->config['servers']; +// // foreach ($servers as $key => $server) { +// // if (empty($server['disabled']) && +// // $server['hostspec'] == $realm) { +// // $result['credentials']['server'] = $key; +// // break; +// // } +// // } +// // } +// // return $result; +// // } + + // // APPLICATION AUTHENTICATED HOOK: See above for format. // public function appauthenticated() // { diff --git a/horde/docs/CHANGES b/horde/docs/CHANGES index 952961c1220..74e5548f1b3 100644 --- a/horde/docs/CHANGES +++ b/horde/docs/CHANGES @@ -2,6 +2,7 @@ v5.3.0-git ---------- +[jan] Add hook to customize user names for DAV clients. [jan] Show users' full names in user lists. [jan] Only show languages on login page that are supported by the system (Request #10457). diff --git a/horde/docs/UPGRADING b/horde/docs/UPGRADING index 2fe4f27dd96..69d8526050f 100644 --- a/horde/docs/UPGRADING +++ b/horde/docs/UPGRADING @@ -52,6 +52,16 @@ The 'maps' configuration options have been moved to the ``horde`` application configuration. +Hooks (hooks.php) +----------------- + +The following hooks have been added:: + + davusername + +See ``config/hooks.php.dist`` for further details. + + Upgrading Horde from 5.1.x to 5.2 ================================= diff --git a/horde/package.xml b/horde/package.xml index 5ec4d987546..77edeb1815e 100644 --- a/horde/package.xml +++ b/horde/package.xml @@ -39,6 +39,7 @@ LGPL-2 +* [jan] Add hook to customize user names for DAV clients. * [jan] Show users' full names in user lists. * [jan] Only show languages on login page that are supported by the system (Request #10457). * [jan] Add option to always lowercase user names after logging in. @@ -4213,6 +4214,7 @@ 2016-04-05 LGPL-2 +* [jan] Add hook to customize user names for DAV clients. * [jan] Show users' full names in user lists. * [jan] Only show languages on login page that are supported by the system (Request #10457). * [jan] Add option to always lowercase user names after logging in. diff --git a/kronolith/config/hooks.php.dist b/kronolith/config/hooks.php.dist index db13abb8052..53d6cfb9b6b 100644 --- a/kronolith/config/hooks.php.dist +++ b/kronolith/config/hooks.php.dist @@ -31,55 +31,4 @@ class Kronolith_Hooks // // throw new Horde_Exception('Unknown action'); // } - - /** - * Customizes the original CalDAV URLs presented in the user interface. - * - * May for example be used to add some realm to user names that would - * otherwise be picked from the login screen. - * - * The following Horde hook examples may pick this information up, when - * using IMP for authentication: - * - * - * public function pushapp() - * { - * if (strpos($_SERVER['REQUEST_URI'], '/rpc') && - * preg_match('/^(.*)@([^\/]*)(.*)$/', $_SERVER['REQUEST_URI'], $m)) { - * // Restore to the original URL that Horde understands, but save - * // the realm part. - * $_SERVER['REQUEST_URI'] = $m[1] . $m[3]; - * putenv('REALM=' . basename($m[2])); - * } - * } - * - * public function preauthenticate($userId, $credentials) - * { - * $result = array($userId, $credentials); - * if ($credentials['authMethod'] == 'authenticate' && - * strpos($_SERVER['REQUEST_URI'], '/rpc') && - * ($realm = getenv('REALM'))) { - * // If this was realm'ed RPC request, pick the correct server - * // from IMP's backend configuration. Assuming that the used - * // realms match backend keys. - * $result['credentials']['server'] = $realm; - * } - * return $result; - * } - * - * - * @param string $base The base part of the URL. - * @param string $user The user part of the URL. - * @param string $resource The resource part of the URL. - */ -// public function caldav_url($base, $user, $resource) -// { -// // Example 1: return unaltered -// //return $base . '/' . $user . '/' . $resource; -// -// // Example 2: append realm to user name -// $server = $GLOBALS['registry']->mail->server(); -// return $base . '/' . $user . '@' . $server['hostspec'] . '/' . $resource; -// } - } diff --git a/kronolith/docs/CHANGES b/kronolith/docs/CHANGES index 43d0b5e921e..74e3c7081cf 100644 --- a/kronolith/docs/CHANGES +++ b/kronolith/docs/CHANGES @@ -22,7 +22,6 @@ v4.3.0-git [mjr] Enforce case on attendee user part, but add attendee to event if only only the case differs (Bug #13905). [jan] Keep original file names when PUTing events via WebDAV. -[jan] Add hook to customize CalDAV URLs. [jan] Remove configuration options for database tables. [mjr] Honor the UID value sent from EAS clients directly in the message structure. diff --git a/kronolith/docs/UPGRADING b/kronolith/docs/UPGRADING index 984f3641914..d55c9bf2784 100644 --- a/kronolith/docs/UPGRADING +++ b/kronolith/docs/UPGRADING @@ -41,6 +41,7 @@ configurations and database schemes. Log in as an administrator, go to Administration => Configuration and update anything that's highlighted as outdated. + Upgrading Kronolith from 4.x to 5.x =================================== @@ -58,14 +59,6 @@ Resources are now share-based and no longer require an explicit driver selection. The configuration options have been changed to reflect this. -Hooks (hooks.php) ------------------ - -The following hooks have been added:: - - caldav_url - - Upgrading Kronolith from 2.3.x to 3.x ===================================== diff --git a/kronolith/lib/Application.php b/kronolith/lib/Application.php index 209451a6bce..92f656fb84c 100644 --- a/kronolith/lib/Application.php +++ b/kronolith/lib/Application.php @@ -734,7 +734,13 @@ public function davGetCollections($user) { global $calendar_manager, $injector, $registry; - $hordeUser = $registry->convertUsername($user, true); + $hordeUser = $user; + try { + $hordeUser = $injector->getInstance('Horde_Core_Hooks') + ->callHook('davusername', 'horde', array($hordeUser, true)); + } catch (Horde_Exception_HookNotSet $e) { + } + $hordeUser = $registry->convertUsername($hordeUser, true); $shares = $injector->getInstance('Kronolith_Shares') ->listShares($hordeUser); $dav = $injector->getInstance('Horde_Dav_Storage'); diff --git a/kronolith/lib/Calendar.php b/kronolith/lib/Calendar.php index a0d28764157..62a70861456 100644 --- a/kronolith/lib/Calendar.php +++ b/kronolith/lib/Calendar.php @@ -141,30 +141,29 @@ protected function _caldavUrl($id, $interface) { global $conf, $injector, $registry; + $user = $registry->convertUsername($registry->getAuth(), false); try { - $parts = array( - Horde::url( - $registry->get('webroot', 'horde') - . ($conf['urls']['pretty'] == 'rewrite' - ? '/rpc/calendars' - : '/rpc.php/calendars'), - true, - -1 - ), - $registry->convertUsername($registry->getAuth(), false), - $injector->getInstance('Horde_Dav_Storage') - ->getExternalCollectionId($id, $interface) . '/' + $user = $injector->getInstance('Horde_Core_Hooks') + ->callHook('davusername', 'horde', array($user, false)); + } catch (Horde_Exception_HookNotSet $e) { + } + try { + $url = Horde::url( + $registry->get('webroot', 'horde') + . ($conf['urls']['pretty'] == 'rewrite' + ? '/rpc/calendars/' + : '/rpc.php/calendars/'), + true, + -1 ); + $url .= $user . '/'; + $url .= $injector->getInstance('Horde_Dav_Storage') + ->getExternalCollectionId($id, $interface) . '/'; } catch (Horde_Exception $e) { return null; } - try { - return $GLOBALS['injector'] - ->getInstance('Horde_Core_Hooks') - ->callHook('caldav_url', 'kronolith', $parts); - } catch (Horde_Exception_HookNotSet $e) { - return implode('/', $parts); - } + + return $url; } /** diff --git a/kronolith/lib/Form/EditCalendar.php b/kronolith/lib/Form/EditCalendar.php index c9739a7a7e4..4e05aa56ea6 100644 --- a/kronolith/lib/Form/EditCalendar.php +++ b/kronolith/lib/Form/EditCalendar.php @@ -95,17 +95,14 @@ public function __construct($vars, $calendar) } $caldavUrl = $calendarObject->caldavUrl(); if ($caldavUrl) { - $accountParts = array( - Horde::url($accountUrl, true, -1) . 'principals', - $registry->convertUsername($registry->getAuth(), false), - '' - ); + $user = $registry->convertUsername($registry->getAuth(), false); try { - $accountUrl = $injector->getInstance('Horde_Core_Hooks') - ->callHook('caldav_url', 'kronolith', $accountParts); + $user = $injector->getInstance('Horde_Core_Hooks') + ->callHook('davusername', 'horde', array($user, false)); } catch (Horde_Exception_HookNotSet $e) { - $accountUrl = implode('/', $accountParts); } + $accountUrl = Horde::url($accountUrl, true, -1) + . 'principals/' . $user; $this->addVariable( _("CalDAV Subscription URL"), '', 'link', false, false, null, array(array( @@ -125,11 +122,18 @@ public function __construct($vars, $calendar) ) ); } - $webdavUrl = Horde::url($webdavUrl, true, -1) - . ($calendar->get('owner') - ? $registry->convertUsername($calendar->get('owner'), false) - : '-system-') - . '/' . $calendar->getName() . '.ics'; + $webdavUrl = Horde::url($webdavUrl, true, -1); + if ($calendar->get('owner')) { + $user = $registry->convertUsername($calendar->get('owner'), false); + try { + $user = $injector->getInstance('Horde_Core_Hooks') + ->callHook('davusername', 'horde', array($user, false)); + } catch (Horde_Exception_HookNotSet $e) { + } + } else { + $webdavUrl .= '-system-'; + } + $webdavUrl .= '/' . $calendar->getName() . '.ics'; $this->addVariable( _("WebDAV/ICS Subscription URL"), '', 'link', false, false, null, array(array( diff --git a/kronolith/package.xml b/kronolith/package.xml index 7ea5b45c0c1..998414e9fed 100644 --- a/kronolith/package.xml +++ b/kronolith/package.xml @@ -49,7 +49,6 @@ * [jan] Add refresh button to individual calendars and task lists. * [mjr] Enforce case on attendee user part, but add attendee to event if only only the case differs (Bug #13905). * [jan] Keep original file names when PUTing events via WebDAV. -* [jan] Add hook to customize CalDAV URLs. * [jan] Remove configuration options for database tables. * [mjr] Honor the UID value sent from EAS clients directly in the message structure. * [jan] Add entries for Tasks and Agenda to top menu. @@ -2794,7 +2793,6 @@ * [jan] Add refresh button to individual calendars and task lists. * [mjr] Enforce case on attendee user part, but add attendee to event if only only the case differs (Bug #13905). * [jan] Keep original file names when PUTing events via WebDAV. -* [jan] Add hook to customize CalDAV URLs. * [jan] Remove configuration options for database tables. * [mjr] Honor the UID value sent from EAS clients directly in the message structure. * [jan] Add entries for Tasks and Agenda to top menu. diff --git a/kronolith/templates/chunks/calendar.php b/kronolith/templates/chunks/calendar.php index a99b1035403..43b367c2a3f 100644 --- a/kronolith/templates/chunks/calendar.php +++ b/kronolith/templates/chunks/calendar.php @@ -31,18 +31,14 @@ } else { $accountUrl .= '/rpc.php/'; } -$accountParts = array( - Horde::url($accountUrl, true, -1) . 'principals', - $GLOBALS['registry']->convertUsername($GLOBALS['registry']->getAuth(), false), - '' -); +$accountUrl = Horde::url($accountUrl, true, -1) . 'principals/'; +$user = $GLOBALS['registry']->convertUsername($GLOBALS['registry']->getAuth(), false); try { - $accountUrl = $GLOBALS['injector']->getInstance('Horde_Core_Hooks') - ->callHook('caldav_url', 'kronolith', $accountParts); + $user = $GLOBALS['injector']->getInstance('Horde_Core_Hooks') + ->callHook('davusername', 'horde', array($user, false)); } catch (Horde_Exception_HookNotSet $e) { - $accountUrl = implode('/', $accountParts); } - +$accountUrl .= $user; ?>