Commit b5242101f9ee393cbc332a8bbeed102f2561be26
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
Showing
2 changed files
with
158 additions
and
0 deletions
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; | ... | ... |