Commit b5242101f9ee393cbc332a8bbeed102f2561be26

Authored by Neil Blakey-Milner
1 parent 2e18ca8b

Add auto-signup for LDAP/ActiveDirectory authentication provider

(including auto-creating AD groups).


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@5876 c91229c3-7414-0410-bfa2-8a42b809f60b
lib/groups/Group.inc
... ... @@ -367,6 +367,15 @@ class Group extends KTEntity {
367 367 ), $aOptions);
368 368 }
369 369  
  370 + function getByAuthenticationSourceAndDetails($oSource, $sDetails, $aOptions = null) {
  371 + $iSourceId = KTUtil::getId($oSource);
  372 + return KTEntityUtil::getByDict('Group', array(
  373 + 'authentication_source_id' => $iSourceId,
  374 + 'authentication_details_s1' => $sDetails,
  375 + ), $aOptions);
  376 + }
  377 +
  378 +
370 379 function &createFromArray($aOptions) { return KTEntityUtil::createFromArray('Group', $aOptions); }
371 380 }
372 381  
... ...
plugins/ktstandard/ldap/ldapbaseauthenticationprovider.inc.php
... ... @@ -32,6 +32,7 @@ class KTLDAPBaseAuthenticationProvider extends KTAuthenticationProvider {
32 32 var $sNamespace = "ktstandard.authentication.ldapprovider";
33 33  
34 34 var $aAttributes = array ("cn", "uid", "givenname", "sn", "mail", "mobile");
  35 + var $aMembershipAttributes = array ("memberOf");
35 36  
36 37 // {{{ KTLDAPBaseAuthenticationProvider
37 38 function KTLDAPBaseAuthenticationProvider() {
... ... @@ -480,6 +481,83 @@ class KTLDAPBaseAuthenticationProvider extends KTAuthenticationProvider {
480 481 exit(0);
481 482 }
482 483 // }}}
  484 +
  485 + // {{{ autoSignup
  486 + function autoSignup($sUsername, $sPassword, $aExtra, $oSource) {
  487 + $oAuthenticator =& $this->getAuthenticator($oSource);
  488 + $dn = $oAuthenticator->checkSignupPassword($sUsername, $sPassword);
  489 +
  490 + if (PEAR::isError($dn)) {
  491 + return;
  492 + }
  493 + if (!is_string($dn)) {
  494 + return;
  495 + }
  496 +
  497 + if (empty($dn)) {
  498 + return;
  499 + }
  500 +
  501 + $aResults = $oAuthenticator->getUser($dn);
  502 + $sUserName = $aResults[$this->aAttributes[1]];
  503 + $sName = $aResults[$this->aAttributes[0]];
  504 + $sEmailAddress = $aResults[$this->aAttributes[4]];
  505 + $sMobileNumber = $aResults[$this->aAttributes[5]];
  506 +
  507 + $oUser = User::createFromArray(array(
  508 + "Username" => $sUserName,
  509 + "Name" => $sName,
  510 + "Email" => $sEmailAddress,
  511 + "EmailNotification" => true,
  512 + "SmsNotification" => false, // FIXME do we auto-act if the user has a mobile?
  513 + "MaxSessions" => 3,
  514 + "authenticationsourceid" => $oSource->getId(),
  515 + "authenticationdetails" => $dn,
  516 + "authenticationdetails2" => $sUserName,
  517 + "password" => "",
  518 + ));
  519 +
  520 + if (PEAR::isError($oUser)) {
  521 + return;
  522 + }
  523 +
  524 + if (!is_a($oUser, 'User')) {
  525 + return;
  526 + }
  527 +
  528 + $this->_createSignupGroups($dn, $oSource);
  529 +
  530 + return $oUser;
  531 + }
  532 +
  533 + function _createSignupGroups($dn, $oSource) {
  534 + $oAuthenticator =& $this->getAuthenticator($oSource);
  535 + $aGroupDNs = $oAuthenticator->getGroups($dn);
  536 + foreach ($aGroupDNs as $sGroupDN) {
  537 + $oGroup = Group::getByAuthenticationSourceAndDetails($oSource, $sGroupDN);
  538 + if (PEAR::isError($oGroup)) {
  539 + $oGroup = $this->_createGroup($sGroupDN, $oSource);
  540 + if (PEAR::isError($oGroup)) {
  541 + continue;
  542 + }
  543 + }
  544 + $oAuthenticator->synchroniseGroup($oGroup);
  545 + }
  546 + }
  547 +
  548 + function _createGroup($dn, $oSource) {
  549 + $oAuthenticator =& $this->getAuthenticator($oSource);
  550 + $aGroupDetails = $oAuthenticator->getGroup($dn);
  551 + $name = $aGroupDetails['cn'];
  552 + $oGroup =& Group::createFromArray(array(
  553 + "name" => $name,
  554 + "isunitadmin" => false,
  555 + "issysadmin" => false,
  556 + "authenticationdetails" => $dn,
  557 + "authenticationsourceid" => $oSource->getId(),
  558 + ));
  559 + return $oGroup;
  560 + }
483 561 }
484 562  
485 563 class KTLDAPBaseAuthenticator extends Authenticator {
... ... @@ -544,6 +622,40 @@ class KTLDAPBaseAuthenticator extends Authenticator {
544 622 return $res;
545 623 }
546 624  
  625 + function checkSignupPassword($sUsername, $sPassword) {
  626 + $aUsers = $this->findUser($sUsername);
  627 + if (empty($aUsers)) {
  628 + return false;
  629 + }
  630 + if (count($aUsers) !== 1) {
  631 + return false;
  632 + }
  633 + $dn = $aUsers[0]['dn'];
  634 + $config = array(
  635 + 'host' => $this->sLdapServer,
  636 + 'base' => $this->sBaseDN,
  637 + );
  638 + $oLdap =& Net_LDAP::connect($config);
  639 + $res = $oLdap->reBind($dn, $sPassword);
  640 + if ($res === true) {
  641 + return $dn;
  642 + }
  643 + return $res;
  644 + }
  645 +
  646 + function getGroups($dn) {
  647 + if (PEAR::isError($this->oLdap)) {
  648 + return $this->oLdap;
  649 + }
  650 +
  651 + $oEntry = $this->oLdap->getEntry($dn, array('memberOf'));
  652 + if (PEAR::isError($oEntry)) {
  653 + return $oEntry;
  654 + }
  655 + $aAttr = $oEntry->attributes();
  656 + return $aAttr['memberOf'];
  657 + }
  658 +
547 659  
548 660 /**
549 661 * Searched the directory for a specific user
... ... @@ -619,6 +731,43 @@ class KTLDAPBaseAuthenticator extends Authenticator {
619 731 return $aRet;
620 732 }
621 733  
  734 + function findUser($sUsername) {
  735 + global $default;
  736 + if (PEAR::isError($this->oLdap)) {
  737 + return $this->oLdap;
  738 + }
  739 +
  740 + $aParams = array(
  741 + 'scope' => 'sub',
  742 + 'attributes' => array('cn', 'dn', 'samaccountname'),
  743 + );
  744 + $rootDn = $this->sBaseDN;
  745 + if (is_array($rootDn)) {
  746 + $rootDn = join(",", $rootDn);
  747 + }
  748 + $sObjectClasses = "|";
  749 + foreach ($this->aObjectClasses as $sObjectClass) {
  750 + $sObjectClasses .= sprintf('(objectClass=%s)', trim($sObjectClass));
  751 + }
  752 + $sSearchAttributes = "|";
  753 + foreach ($this->aSearchAttributes as $sSearchAttribute) {
  754 + $sSearchAttributes .= sprintf('(%s=%s)', trim($sSearchAttribute), $sUsername);
  755 + }
  756 + $sFilter = sprintf('(&(%s)(%s))', $sObjectClasses, $sSearchAttributes);
  757 + $default->log->debug("Search filter is: " . $sFilter);
  758 + $oResult = $this->oLdap->search($rootDn, $sFilter, $aParams);
  759 + if (PEAR::isError($oResult)) {
  760 + return $oResult;
  761 + }
  762 + $aRet = array();
  763 + foreach($oResult->entries() as $oEntry) {
  764 + $aAttr = $oEntry->attributes();
  765 + $aAttr['dn'] = $oEntry->dn();
  766 + $aRet[] = $aAttr;
  767 + }
  768 + return $aRet;
  769 + }
  770 +
622 771 function searchGroups($sSearch) {
623 772 if (PEAR::isError($this->oLdap)) {
624 773 return $this->oLdap;
... ...