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,6 +367,15 @@ class Group extends KTEntity { | ||
| 367 | ), $aOptions); | 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 | function &createFromArray($aOptions) { return KTEntityUtil::createFromArray('Group', $aOptions); } | 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,6 +32,7 @@ class KTLDAPBaseAuthenticationProvider extends KTAuthenticationProvider { | ||
| 32 | var $sNamespace = "ktstandard.authentication.ldapprovider"; | 32 | var $sNamespace = "ktstandard.authentication.ldapprovider"; |
| 33 | 33 | ||
| 34 | var $aAttributes = array ("cn", "uid", "givenname", "sn", "mail", "mobile"); | 34 | var $aAttributes = array ("cn", "uid", "givenname", "sn", "mail", "mobile"); |
| 35 | + var $aMembershipAttributes = array ("memberOf"); | ||
| 35 | 36 | ||
| 36 | // {{{ KTLDAPBaseAuthenticationProvider | 37 | // {{{ KTLDAPBaseAuthenticationProvider |
| 37 | function KTLDAPBaseAuthenticationProvider() { | 38 | function KTLDAPBaseAuthenticationProvider() { |
| @@ -480,6 +481,83 @@ class KTLDAPBaseAuthenticationProvider extends KTAuthenticationProvider { | @@ -480,6 +481,83 @@ class KTLDAPBaseAuthenticationProvider extends KTAuthenticationProvider { | ||
| 480 | exit(0); | 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 | class KTLDAPBaseAuthenticator extends Authenticator { | 563 | class KTLDAPBaseAuthenticator extends Authenticator { |
| @@ -544,6 +622,40 @@ class KTLDAPBaseAuthenticator extends Authenticator { | @@ -544,6 +622,40 @@ class KTLDAPBaseAuthenticator extends Authenticator { | ||
| 544 | return $res; | 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 | * Searched the directory for a specific user | 661 | * Searched the directory for a specific user |
| @@ -619,6 +731,43 @@ class KTLDAPBaseAuthenticator extends Authenticator { | @@ -619,6 +731,43 @@ class KTLDAPBaseAuthenticator extends Authenticator { | ||
| 619 | return $aRet; | 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 | function searchGroups($sSearch) { | 771 | function searchGroups($sSearch) { |
| 623 | if (PEAR::isError($this->oLdap)) { | 772 | if (PEAR::isError($this->oLdap)) { |
| 624 | return $this->oLdap; | 773 | return $this->oLdap; |