Commit 82180d07b0f9ebee6e5c638986dfd8aef443cea5

Authored by nbm
1 parent 0534150b

Add an ActiveDirectory-specific authentication provider that handles AD

features and quirks better.


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@4827 c91229c3-7414-0410-bfa2-8a42b809f60b
plugins/ktstandard/ldap/activedirectoryauthenticationprovider.inc.php 0 → 100644
  1 +<?php
  2 +
  3 +require_once(KT_LIB_DIR . '/authentication/authenticationprovider.inc.php');
  4 +require_once(KT_LIB_DIR . '/authentication/Authenticator.inc');
  5 +
  6 +class KTActiveDirectoryAuthenticationProvider extends KTAuthenticationProvider {
  7 + var $sName = "ActiveDirectory authentication provider";
  8 + var $sNamespace = "ktstandard.authentication.adprovider";
  9 + var $bGroupSource = true;
  10 +
  11 + // {{{ KTActiveDirectoryAuthenticationProvider
  12 + function KTActiveDirectoryAuthenticationProvider() {
  13 + $this->aConfigMap = array(
  14 + 'servername' => _('LDAP Server'),
  15 + 'basedn' => _('Base DN'),
  16 + 'domain' => _('LDAP Server Domain'),
  17 + 'searchuser' => _('LDAP Search User'),
  18 + 'searchpassword' => _('LDAP Search Password'),
  19 + );
  20 + return parent::KTAuthenticationProvider();
  21 + }
  22 + // }}}
  23 +
  24 + // {{{ showSource
  25 + function showSource($oSource) {
  26 + $aConfig = unserialize($oSource->getConfig());
  27 + if (empty($aConfig)) {
  28 + $aConfig = array();
  29 + }
  30 + $sRet = "<dl>\n";
  31 + foreach ($this->aConfigMap as $sSettingName => $sName) {
  32 + $sRet .= " <dt>$sName</dt>\n";
  33 + $sValue = KTUtil::arrayGet($aConfig, $sSettingName, _("Unset"));
  34 + $sRet .= " <dd>" . $sValue . "</dd>\n";
  35 + }
  36 + $sRet .= "</dl>\n";
  37 + return $sRet;
  38 + }
  39 + // }}}
  40 +
  41 + // {{{ showUserSource
  42 + function showUserSource($oUser, $oSource) {
  43 + return '<a href="?action=editUserSource&user_id=' . $oUser->getId() .'">' . _('Edit LDAP info') . '</a>';
  44 + }
  45 + // }}}
  46 +
  47 + // {{{ do_editUserSource
  48 + function do_editUserSource() {
  49 + $submit = KTUtil::arrayGet($_REQUEST, 'submit');
  50 + if (KTUtil::arrayGet($submit, 'save')) {
  51 + return $this->_do_saveUserSource();
  52 + }
  53 +
  54 + $user_id = KTUtil::arrayGet($_REQUEST, 'user_id');
  55 + $oUser =& $this->oValidator->validateUser($user_id);
  56 +
  57 + $this->oPage->setBreadcrumbDetails(_("editing LDAP details"));
  58 + $oTemplate = $this->oValidator->validateTemplate('ktstandard/authentication/ldapedituser');
  59 +
  60 + $oAuthenticationSource = KTAuthenticationSource::getForUser($oUser);
  61 +
  62 + $dn = $oUser->getAuthenticationDetails();
  63 +
  64 + $fields = array();
  65 + $fields[] = new KTStringWidget(_('Distinguished name'), _('The location of this user in the LDAP tree'), 'dn', $dn, $this->oPage, true);
  66 +
  67 + $aTemplateData = array(
  68 + 'context' => &$this,
  69 + 'fields' => $fields,
  70 + 'user' => $oUser,
  71 + );
  72 + return $oTemplate->render($aTemplateData);
  73 + }
  74 + // }}}
  75 +
  76 + // {{{ _do_saveUserSource
  77 + function _do_saveUserSource() {
  78 + $user_id = KTUtil::arrayGet($_REQUEST, 'user_id');
  79 + $oUser =& $this->oValidator->validateUser($user_id);
  80 +
  81 + $dn = KTUtil::arrayGet($_REQUEST, 'dn', "");
  82 + if (empty($dn)) {
  83 + $this->errorRedirecToMain("Failed to validate LDAP details");
  84 + }
  85 + $oUser->setAuthenticationDetails($dn);
  86 + $oUser->update();
  87 + $this->successRedirectTo("editUser", _("Details updated"),
  88 + sprintf('user_id=%d', $oUser->getId()));
  89 + }
  90 + // }}}
  91 +
  92 + // {{{ do_editSourceProvider
  93 + function do_editSourceProvider() {
  94 + require_once(KT_LIB_DIR . '/widgets/fieldWidgets.php');
  95 + $this->oPage->setBreadcrumbDetails(_("editing LDAP settings"));
  96 + $oTemplate = $this->oValidator->validateTemplate('ktstandard/authentication/ldapeditsource');
  97 + $iSourceId = KTUtil::arrayGet($_REQUEST, 'source_id');
  98 + $oSource = KTAuthenticationSource::get($iSourceId);
  99 + $aConfig = unserialize($oSource->getConfig());
  100 + $fields = array();
  101 + $fields[] = new KTStringWidget(_('Server name'), 'The host name or IP address of the LDAP server', 'servername', $aConfig['servername'], $this->oPage, true);
  102 + $fields[] = new KTStringWidget(_('Base DN'), 'FIXME', 'basedn', $aConfig['basedn'], $this->oPage, true);
  103 + $fields[] = new KTStringWidget(_('Domain'), 'FIXME', 'domain', $aConfig['domain'], $this->oPage, true);
  104 + $fields[] = new KTStringWidget(_('Search User'), 'FIXME', 'searchuser', $aConfig['searchuser'], $this->oPage, true);
  105 + $fields[] = new KTStringWidget(_('Search Password'), 'FIXME', 'searchpassword', $aConfig['searchpassword'], $this->oPage, true);
  106 + $aTemplateData = array(
  107 + 'context' => &$this,
  108 + 'fields' => $fields,
  109 + 'source' => $oSource,
  110 + );
  111 + return $oTemplate->render($aTemplateData);
  112 + }
  113 + // }}}
  114 +
  115 + // {{{ do_performEditSourceProvider
  116 + function do_performEditSourceProvider() {
  117 + $iSourceId = KTUtil::arrayGet($_REQUEST, 'source_id');
  118 + $oSource = KTAuthenticationSource::get($iSourceId);
  119 + $aConfig = array();
  120 + foreach ($this->aConfigMap as $k => $v) {
  121 + $sValue = KTUtil::arrayGet($_REQUEST, $k);
  122 + if ($sValue) {
  123 + $aConfig[$k] = $sValue;
  124 + }
  125 + }
  126 + $oSource->setConfig(serialize($aConfig));
  127 + $oSource->update();
  128 + $this->successRedirectTo('viewsource', _("Configuration updated"), 'source_id=' . $oSource->getId());
  129 + }
  130 + // }}}
  131 +
  132 + // {{{ getAuthenticator
  133 + function &getAuthenticator($oSource) {
  134 + return new ActiveDirectoryAuthenticator($oSource);
  135 + }
  136 + // }}}
  137 +
  138 + // {{{ _do_editUserFromSource
  139 + function _do_editUserFromSource() {
  140 + $oTemplate = $this->oValidator->validateTemplate('ktstandard/authentication/ldapadduser');
  141 + $oSource =& KTAuthenticationSource::get($_REQUEST['source_id']);
  142 + $id = KTUtil::arrayGet($_REQUEST, 'id');
  143 +
  144 + $aConfig = unserialize($oSource->getConfig());
  145 + $aAttributes = array ("dn", "samaccountname", "givenname", "sn", "userprincipalname", "telephonenumber");
  146 +
  147 + $oAuthenticator = $this->getAuthenticator($oSource);
  148 + $aResults = $oAuthenticator->getUser($id);
  149 +
  150 + $fields = array();
  151 + $fields[] = new KTStaticTextWidget(_('LDAP DN'), _('The location of the user within the LDAP directory.'), 'dn', $aResults[$aAttributes[0]], $this->oPage);
  152 + $fields[] = new KTStringWidget(_('Username'), _('The username the user will enter to gain access to KnowledgeTree. e.g. <strong>jsmith</strong>'), 'ldap_username', $aResults[$aAttributes[1]], $this->oPage, true);
  153 + $fields[] = new KTStringWidget(_('Name'), _('The full name of the user. This is shown in reports and listings. e.g. <strong>John Smith</strong>'), 'name', join(" ", array($aResults[$aAttributes[2]], $aResults[$aAttributes[3]])), $this->oPage, true);
  154 + $fields[] = new KTStringWidget(_('Email Address'), _('The email address of the user. Notifications and alerts are mailed to this address if <strong>email notifications</strong> is set below. e.g. <strong>jsmith@acme.com</strong>'), 'email_address', $aResults[$aAttributes[4]], $this->oPage, false);
  155 + $fields[] = new KTCheckboxWidget(_('Email Notifications'), _('If this is specified then the user will have notifications sent to the email address entered above. If it is not set, then the user will only see notifications on the <strong>Dashboard</strong>'), 'email_notifications', true, $this->oPage, false);
  156 + $fields[] = new KTStringWidget(_('Mobile Number'), _('The mobile phone number of the user. If the system is configured to send notifications to cellphones, then this number will have an SMS delivered to it with notifications. e.g. <strong>999 9999 999</strong>'), 'mobile_number', $aResults[$aAttributes[5]], $this->oPage, false);
  157 + $fields[] = new KTStringWidget(_('Maximum Sessions'), _('As a safety precaution, it is useful to limit the number of times a given account can log in, before logging out. This prevents a single account being used by many different people.'), 'max_sessions', '3', $this->oPage, true);
  158 +
  159 + $aTemplateData = array(
  160 + 'context' => &$this,
  161 + 'fields' => $fields,
  162 + 'source' => $oSource,
  163 + 'search_results' => $aSearchResults,
  164 + 'dn' => $aResults[$aAttributes[0]],
  165 + 'samaccountname' => $aResults['samaccountname'],
  166 + );
  167 + return $oTemplate->render($aTemplateData);
  168 + }
  169 + // }}}
  170 +
  171 + // {{{ _do_createUserFromSource
  172 + function _do_createUserFromSource() {
  173 + $oSource =& KTAuthenticationSource::get($_REQUEST['source_id']);
  174 + $dn = KTUtil::arrayGet($_REQUEST, 'dn');
  175 + $samaccountname = KTUtil::arrayGet($_REQUEST, 'samaccountname');
  176 + $name = KTUtil::arrayGet($_REQUEST, 'name');
  177 + if (empty($name)) { $this->errorRedirectToMain(_('You must specify a name for the user.')); }
  178 + $username = KTUtil::arrayGet($_REQUEST, 'ldap_username');
  179 + if (empty($name)) { $this->errorRedirectToMain(_('You must specify a new username.')); }
  180 + // FIXME check for non-clashing usernames.
  181 +
  182 + $email_address = KTUtil::arrayGet($_REQUEST, 'email_address');
  183 + $email_notifications = KTUtil::arrayGet($_REQUEST, 'email_notifications', false);
  184 + if ($email_notifications !== false) $email_notifications = true;
  185 + $mobile_number = KTUtil::arrayGet($_REQUEST, 'mobile_number');
  186 + $max_sessions = KTUtil::arrayGet($_REQUEST, 'max_sessions', '3');
  187 + // FIXME check for numeric max_sessions... db-error else?
  188 +
  189 + $oUser =& User::createFromArray(array(
  190 + "Username" => $username,
  191 + "Name" => $name,
  192 + "Email" => $email_address,
  193 + "EmailNotification" => $email_notifications,
  194 + "SmsNotification" => false, // FIXME do we auto-act if the user has a mobile?
  195 + "MaxSessions" => $max_sessions,
  196 + "authenticationsourceid" => $oSource->getId(),
  197 + "authenticationdetails" => $dn,
  198 + "authenticationdetails2" => $samaccountname,
  199 + "password" => "",
  200 + ));
  201 +
  202 + if (PEAR::isError($oUser) || ($oUser == false)) {
  203 + $this->errorRedirectToMain(_("failed to create user."));
  204 + exit(0);
  205 + }
  206 +
  207 + $this->successRedirectToMain(_('Created new user') . ': ' . $oUser->getUsername());
  208 + exit(0);
  209 + }
  210 + // }}}
  211 +
  212 + // {{{ do_addUserFromSource
  213 + function do_addUserFromSource() {
  214 + $submit = KTUtil::arrayGet($_REQUEST, 'submit');
  215 + if (!is_array($submit)) {
  216 + $submit = array();
  217 + }
  218 + if (KTUtil::arrayGet($submit, 'chosen')) {
  219 + $id = KTUtil::arrayGet($_REQUEST, 'id');
  220 + if (!empty($id)) {
  221 + return $this->_do_editUserFromSource();
  222 + } else {
  223 + $this->oPage->addError(_("No valid LDAP user chosen"));
  224 + }
  225 + }
  226 + if (KTUtil::arrayGet($submit, 'create')) {
  227 + return $this->_do_createUserFromSource();
  228 + }
  229 + $oSource =& KTAuthenticationSource::get($_REQUEST['source_id']);
  230 + $oTemplate = $this->oValidator->validateTemplate('ktstandard/authentication/ldapsearchuser');
  231 +
  232 + $fields = array();
  233 + $fields[] = new KTStringWidget(_("User's name"), _("The user's name, or part thereof, to find the user that you wish to add"), 'name', '', $this->oPage, true);
  234 +
  235 + $oAuthenticator = $this->getAuthenticator($oSource);
  236 + $name = KTUtil::arrayGet($_REQUEST, 'name');
  237 + if (!empty($name)) {
  238 + $aSearchResults = $oAuthenticator->searchUsers($name, array('cn', 'dn', $sIdentifierField));
  239 + if (PEAR::isError($aSearchResults)) {
  240 + $this->oPage->addError($aSearchResults->getMessage());
  241 + $aSearchResults = null;
  242 + }
  243 + }
  244 +
  245 + $aTemplateData = array(
  246 + 'context' => &$this,
  247 + 'fields' => $fields,
  248 + 'source' => $oSource,
  249 + 'search_results' => $aSearchResults,
  250 + 'identifier_field' => $sIdentifierField,
  251 + );
  252 + return $oTemplate->render($aTemplateData);
  253 + }
  254 + // }}}
  255 +
  256 + // {{{ do_addGroupFromSource
  257 + function do_addGroupFromSource() {
  258 + $submit = KTUtil::arrayGet($_REQUEST, 'submit');
  259 + if (!is_array($submit)) {
  260 + $submit = array();
  261 + }
  262 + if (KTUtil::arrayGet($submit, 'chosen')) {
  263 + $id = KTUtil::arrayGet($_REQUEST, 'id');
  264 + var_dump($id);
  265 + if (!empty($id)) {
  266 + return $this->_do_editGroupFromSource();
  267 + } else {
  268 + $this->oPage->addError(_("No valid LDAP group chosen"));
  269 + }
  270 + }
  271 + if (KTUtil::arrayGet($submit, 'create')) {
  272 + return $this->_do_createGroupFromSource();
  273 + }
  274 + $oSource =& KTAuthenticationSource::get($_REQUEST['source_id']);
  275 + $oTemplate = $this->oValidator->validateTemplate('ktstandard/authentication/ldapsearchgroup');
  276 +
  277 + $fields = array();
  278 + $fields[] = new KTStringWidget(_("Group's name"), _("The group's name, or part thereof, to find the group that you wish to add"), 'name', '', $this->oPage, true);
  279 +
  280 + $oAuthenticator = $this->getAuthenticator($oSource);
  281 + $name = KTUtil::arrayGet($_REQUEST, 'name');
  282 + if (!empty($name)) {
  283 + $oAuthenticator = $this->getAuthenticator($oSource);
  284 + $aSearchResults = $oAuthenticator->searchGroups($name);
  285 + }
  286 +
  287 + $aTemplateData = array(
  288 + 'context' => &$this,
  289 + 'fields' => $fields,
  290 + 'source' => $oSource,
  291 + 'search_results' => $aSearchResults,
  292 + 'identifier_field' => 'displayName',
  293 + );
  294 + return $oTemplate->render($aTemplateData);
  295 + }
  296 + // }}}
  297 +
  298 + // {{{ _do_editGroupFromSource
  299 + function _do_editGroupFromSource() {
  300 + $oTemplate = $this->oValidator->validateTemplate('ktstandard/authentication/ldapaddgroup');
  301 + $oSource =& KTAuthenticationSource::get($_REQUEST['source_id']);
  302 + $id = KTUtil::arrayGet($_REQUEST, 'id');
  303 +
  304 + $aConfig = unserialize($oSource->getConfig());
  305 +
  306 + $oAuthenticator = $this->getAuthenticator($oSource);
  307 + $aAttributes = $oAuthenticator->getGroup($id);
  308 +
  309 + $fields = array();
  310 + $fields[] = new KTStaticTextWidget(_('LDAP DN'), _('The location of the group within the LDAP directory.'), 'dn', $aAttributes['dn'], $this->oPage);
  311 + $fields[] = new KTStringWidget(_('Group Name'), _('The name the group will enter to gain access to KnowledgeTree. e.g. <strong>accountants</strong>'), 'ldap_groupname', $aAttributes['cn'], $this->oPage, true);
  312 + $fields[] = new KTCheckboxWidget(_('Unit Administrators'),_('Should all the members of this group be given <strong>unit</strong> administration privileges?'), 'is_unitadmin', false, $this->oPage, false);
  313 + $fields[] = new KTCheckboxWidget(_('System Administrators'),_('Should all the members of this group be given <strong>system</strong> administration privileges?'), 'is_sysadmin', false, $this->oPage, false);
  314 +
  315 + $aTemplateData = array(
  316 + 'context' => &$this,
  317 + 'fields' => $fields,
  318 + 'source' => $oSource,
  319 + 'search_results' => $aSearchResults,
  320 + 'dn' => $dn,
  321 + );
  322 + return $oTemplate->render($aTemplateData);
  323 + }
  324 + // }}}
  325 +
  326 + // {{{ _do_createGroupFromSource
  327 + function _do_createGroupFromSource() {
  328 + $oSource =& KTAuthenticationSource::get($_REQUEST['source_id']);
  329 + $dn = KTUtil::arrayGet($_REQUEST, 'dn');
  330 + $name = KTUtil::arrayGet($_REQUEST, 'ldap_groupname');
  331 + if (empty($name)) { $this->errorRedirectToMain(_('You must specify a name for the group.')); }
  332 +
  333 + $is_unitadmin = KTUtil::arrayGet($_REQUEST, 'is_unitadmin', false);
  334 + $is_sysadmin = KTUtil::arrayGet($_REQUEST, 'is_sysadmin', false);
  335 +
  336 + $oGroup =& Group::createFromArray(array(
  337 + "name" => $name,
  338 + "isunitadmin" => $is_unitadmin,
  339 + "issysadmin" => $is_sysadmin,
  340 + "authenticationdetails" => $dn,
  341 + ));
  342 +
  343 + if (PEAR::isError($oGroup) || ($oGroup == false)) {
  344 + $this->errorRedirectToMain(_("failed to create group."));
  345 + exit(0);
  346 + }
  347 +
  348 + $this->successRedirectToMain(_('Created new group') . ': ' . $oGroup->getName());
  349 + exit(0);
  350 + }
  351 + // }}}
  352 +}
  353 +
  354 +class ActiveDirectoryAuthenticator extends Authenticator {
  355 + /**
  356 + * The LDAP server to connect to
  357 + */
  358 + var $sLdapServer;
  359 + /**
  360 + * The base LDAP DN to perform authentication against
  361 + */
  362 + var $sBaseDN;
  363 + /**
  364 + * The LDAP accessor class
  365 + */
  366 + var $oLdap;
  367 +
  368 + /**
  369 + * Creates a new instance of the ActiveDirectoryAuthenticator
  370 + *
  371 + *
  372 + */
  373 + function ActiveDirectoryAuthenticator($oSource) {
  374 + $this->oSource =& $oSource;
  375 + $aConfig = unserialize($oSource->getConfig());
  376 + $this->sLdapServer = $aConfig['servername'];
  377 + $this->sBaseDN = $aConfig['basedn'];
  378 + $this->sLdapDomain = $aConfig['domain'];
  379 + $this->sSearchUser = $aConfig['searchuser'];
  380 + $this->sSearchPassword = $aConfig['searchpassword'];
  381 +
  382 + require_once('Net/LDAP.php');
  383 + $config = array(
  384 + 'dn' => $this->sSearchUser,
  385 + 'password' => $this->sSearchPassword,
  386 + 'host' => $this->sLdapServer,
  387 + 'base' => $this->sBaseDN,
  388 + );
  389 +
  390 + $this->oLdap =& Net_LDAP::connect($config);
  391 + }
  392 +
  393 + /**
  394 + * Authenticate the user against the LDAP directory
  395 + *
  396 + * @param string the user to authenticate
  397 + * @param string the password to check
  398 + * @return boolean true if the password is correct, else false
  399 + */
  400 + function checkPassword($oUser, $sPassword) {
  401 + $dn = $oUser->getAuthenticationDetails();
  402 + $config = array(
  403 + 'host' => $this->sLdapServer,
  404 + 'base' => $this->sBaseDN,
  405 + );
  406 + $oLdap =& Net_LDAP::connect($config);
  407 + $res = $oLdap->reBind($dn, $sPassword);
  408 + return $res;
  409 + }
  410 +
  411 +
  412 + /**
  413 + * Searched the directory for a specific user
  414 + *
  415 + * @param string the username to search for
  416 + * @param array the attributes to return from the search
  417 + * @return array containing the users found
  418 + */
  419 + function getUser($dn) {
  420 + if (PEAR::isError($this->oLdap)) {
  421 + return $this->oLdap;
  422 + }
  423 + $aAttributes = array('cn', 'samaccountname', "givenname", "sn", "userprincipalname", "telephonenumber");
  424 +
  425 + $oEntry = $this->oLdap->getEntry($dn, $aAttributes);
  426 + $aAttr = $oEntry->attributes();
  427 + $aAttr['dn'] = $oEntry->dn();
  428 +
  429 + foreach ($aAttr as $k => $v) {
  430 + $aRet[strtolower($k)] = $v;
  431 + }
  432 + return $aRet;
  433 + }
  434 +
  435 + /**
  436 + * Searches the LDAP directory for users matching the supplied search string.
  437 + *
  438 + * @param string the username to search for
  439 + * @param array the attributes to return from the search
  440 + * @return array containing the users found
  441 + */
  442 + function searchUsers($sSearch) {
  443 + if (PEAR::isError($this->oLdap)) {
  444 + return $this->oLdap;
  445 + }
  446 +
  447 + $aParams = array(
  448 + 'scope' => 'sub',
  449 + 'attributes' => array('cn', 'dn', 'samaccountname'),
  450 + );
  451 + $rootDn = $this->sBaseDN;
  452 + if (is_array($rootDn)) {
  453 + $rootDn = join(",", $rootDn);
  454 + }
  455 + $sFilter = sprintf('(&(objectClass=user)(|(samaccountname=*%s*)(cn=*%s*)))', $sSearch, $sSearch);
  456 + $oResult = $this->oLdap->search($rootDn, $sFilter, $aParams);
  457 + if (PEAR::isError($oResult)) {
  458 + return $oResult;
  459 + }
  460 + $aRet = array();
  461 + foreach($oResult->entries() as $oEntry) {
  462 + $aAttr = $oEntry->attributes();
  463 + $aAttr['dn'] = $oEntry->dn();
  464 + $aRet[] = $aAttr;
  465 + }
  466 + return $aRet;
  467 + }
  468 +
  469 + function searchGroups($sSearch) {
  470 + if (PEAR::isError($this->oLdap)) {
  471 + return $this->oLdap;
  472 + }
  473 +
  474 + $aParams = array(
  475 + 'scope' => 'sub',
  476 + 'attributes' => array('cn', 'dn', 'displayName'),
  477 + );
  478 + $rootDn = $oAuthenticator->sBaseDN;
  479 + if (is_array($rootDn)) {
  480 + $rootDn = join(",", $rootDn);
  481 + }
  482 + $sFilter = sprintf('(&(objectClass=group)(cn=*%s*))', $sSearch);
  483 + $oResults = $this->oLdap->search($rootDn, $sFilter, $aParams);
  484 + $aRet = array();
  485 + foreach($oResults->entries() as $oEntry) {
  486 + $aAttr = $oEntry->attributes();
  487 + $aAttr['dn'] = $oEntry->dn();
  488 + $aRet[] = $aAttr;
  489 + }
  490 + return $aRet;
  491 + }
  492 +
  493 + function getGroup($dn, $aAttributes = null) {
  494 + if (empty($aAttributes)) {
  495 + $aAttributes = array('cn');
  496 + }
  497 + if (PEAR::isError($this->oLdap)) {
  498 + return $this->oLdap;
  499 + }
  500 +
  501 + $oEntry = $this->oLdap->getEntry($dn, $aAttributes);
  502 + if (PEAR::isError($oEntry)) {
  503 + return $oEntry;
  504 + }
  505 + $aAttr = $oEntry->attributes();
  506 + $aAttr['dn'] = $oEntry->dn();
  507 + return $aAttr;
  508 + }
  509 +
  510 + function synchroniseGroup($oGroup) {
  511 + $oGroup =& KTUtil::getObject('Group', $oGroup);
  512 + $dn = $oGroup->getAuthenticationDetails();
  513 + $aAttr = $this->getGroup($dn, array('member'));
  514 + if (PEAR::isError($aAttr)) {
  515 + return $aAttr;
  516 + }
  517 + $aMembers = KTUtil::arrayGet($aAttr, 'member', array());
  518 + if (!is_array($aMembers)) {
  519 + $aMembers = array($aMembers);
  520 + }
  521 + $aUserIds = array();
  522 + foreach ($aMembers as $sMember) {
  523 + $iUserId = User::getByAuthenticationSourceAndDetails($this->oSource, $sMember, array('ids' => true));
  524 + if (PEAR::isError($iUserId)) {
  525 + continue;
  526 + }
  527 + $aUserIds[] = $iUserId;
  528 + }
  529 + $oGroup->setMembers($aUserIds);
  530 + }
  531 +}
  532 +
... ...