__('LDAP Helper'), 'version' => '006', 'author' => 'Kreativmonkey', 'summary' => __('Hendle LDAP Communication for Processwire'), 'singular' => true, 'autoload' => true ); } public function ___install() { if (!function_exists('ldap_connect')) throw new WireException ('Please make sure that extension php_ldap is loaded.'); } public function init() { if (isset ($this->data ['host'])) { $host = explode(':', str_replace(array( 'ldap://', 'ldaps://' ), array( '', '' ), $this->data ['host'])); $this->protocol = (empty ($this->data ['useSSL'])) ? 'ldap://' : 'ldaps://'; $this->host = $host [0]; $this->port = empty ($host [1]) ? 389 : $host [1]; } $this->debugMode = empty ($this->data ['debug']); if (isset ($this->data ['loginDomain'])) $this->defaultLoginDomain = $this->data ['loginDomain']; if (isset ($this->data ['userdn'])) $this->userdn = $this->data ['userdn']; if (isset ($this->data ['admin'])) $this->admin = $this->data ['admin']; if (isset ($this->data ['secret'])) $this->secret = $this->data ['secret']; if (isset ($this->data ['useV3'])) $this->useV3 = $this->data ['useV3']; if (isset ($this->data ['ldapSetting'])) $this->ldapSetting = $this->data ['ldapSetting']; $this->userDefaultRoles = new WireArray (); if (isset ($this->data ['userDefaultRoles'])) { foreach ($this->data ['userDefaultRoles'] as $x) { $role = $this->roles->get($x); $this->userDefaultRoles->add($role); } } $this->userDefaultRoles->add($this->roles->getGuestRole()); $this->userDefaultRoles = $this->userDefaultRoles->unique(); $this->pages->addHookBefore("delete", $this, "ldapHelperDeleteUser"); $this->addHookAfter('Modules::saveModuleConfigData', $this, 'hookModuleSave'); $this->session->addHookAfter('login', $this, 'ldapHelperLogin'); $this->addHookBefore("Password::setPassword", $this, 'ldapHelperChangePw'); } public function ldapHelperRegistradeUser(Array $user) { $username = $user["username"]; // LDAP user anlegen $info["objectclass"][0] = "top"; $info["objectclass"][1] = "person"; $info["objectclass"][2] = "organizationalPerson"; $info["objectclass"][3] = "inetorgperson"; $info["cn"] = $user["firstname"]; $info["sn"] = $user["lastname"]; $info["givenName"] = $user["username"]; $info["description"] = "ffmyk"; $password = $this->makeSshaPassword($user["password"]); // If you have the plain text password instead, you could use: $info['userPassword'] = $password; // Connect to LDAP Server if(!$connect = $this->ldapHelperConnect()) return false; // bind mit passendem dn für aktulisierenden Zugriff if(!$r= $this->ldapHelperWrite($connect)) return false; // Add User to the Database if(!$r= ldap_add($connect, "uid=$username,$this->userdn", $info)){ $massage = ldap_err2str(ldap_errno($connect)); $this->log->save('ldap_helper', "Create User failed $ldapMassage"); return false; } $this->log->save('ldap_helper', "Create User: $username"); // Verbindung schließen ldap_close($connect); // Registrierung erfolgreich return true; } public function ldapHelperLogin(HookEvent $event){ if($event->return) return; $username = $event->arguments[0]; $password = $event->arguments[1]; if(!$con = $this->ldapHelperConnect()) return; // Connection Failed $user_search = ldap_search($con,"dc=ffmyk,dc=de","(|(uid=$username))"); $user_entry = ldap_first_entry($con, $user_search); $user_dn = ldap_get_dn($con, $user_entry); if(@ldap_bind($con, $user_dn, $password)){ $wireUserName = $this->sanitizer->pageName($username); $user = $this->users->get("name=$wireUserName"); if($user instanceof NullPage){ // Search the LDAP Entry $first_name = ldap_get_values($con, $user_entry, "cn"); $last_name = ldap_get_values($con, $user_entry, "sn"); // Add ldap user to ProcessWire $new_user = new User(); $new_user->of(false); $new_user->name = $wireUserName; $new_user->firstname = $first_name; $new_user->lastname = $last_name; $new_user->pass = $password; $new_user->addRole("user"); $new_user->admin_theme = "AdminThemeReno"; $new_user->save(); $new_user->of(true); } else { // Set new Password $user->of(false); $user->pass = $password; if($user->isChanged('pass')){ $user->save(); $this->message($this->_('Password changed success.')); } $user->of(true); } $user = $this->session->login($wireUserName, $password); $event->return = $user; $this->message($this->_('Logged in via LDAP.')); return; } else { $this->message("Bitte Registriere dich."); } } /** * Change the Password for the LDAP User * $username = Ldap uid * $newPassword = the new Password to set for the User * $newPasswordCnt = double check the new Password * * return * string */ public function ldapHelperChangePw($username, $newPassword, $newPasswordCnt) { $user = wire('users')->get("name=$username"); $dn = $this->userdn; if($user instanceof NullPage) return "User dosn't exist."; if(empty($newPassword) | empty($newPasswordCnt)) { $this->message = "Not enouth values."; return false; } // check if new Password match if($newPassword != $newPasswordCnt) { $this->message = "Password doesn't match."; return false; } // Connect to LDAP Server if(!$con = $this->ldapHelperConnect()) { $this->message = "Verbindungsprobleme, bitte versuche es später noch einmal."; return false; } // Search for the user in the ldap Directory $user_search = ldap_search($con,$dn,"(|(uid=$username))"); // Ressource ID: $user_get = ldap_get_entries($con,$user_search); // array with all entries $user_entry = ldap_first_entry($con, $user_search); // array with ressource $user_dn = ldap_get_dn($con, $user_entry); // uid=$userid,ou=People,dc=ffmyk,dc=de $user_id = $user_get[0]["uid"][0]; // the user ID $user_givenName = $user_get[0]["givenname"][0]; // Given name from user $user_search_array = array("*", "ou", "uid"); $user_search_filter = "(|(uid=$user_id))"; $user_search_opt = ldap_search($con, $user_dn, $user_search_filter, $user_search_array); // array ressource $user_get_opt = ldap_get_entries($con,$user_search_opt); // array with the entrie $encoded_password = $this->makeSshaPassword($newPassword); $entry = array(); $entry["userPassword"] = "$encoded_password"; // bind mit passendem dn für aktulisierenden Zugriff if(!$r= $this->ldapHelperWrite($con)) { $this->message = "Verbindungsprobleme."; return false; } if(ldap_modify($con,$user_dn,$entry) === false){ $error = ldap_error($con); $errno = ldap_errno($con); $this->log->save('ldap_helper', "$username - Your password cannot be change, please contact the administrator."); $this->log->save('ldap_helper', "$errno - $error"); $this->message = "Dein Password konnte nicht gespeichert werden. Bitte kontaktiere den Administrator"; return false; } else { $this->message = "Dein Password wurde geändert, du kannst dich nun mit dem neuen Password einloggen."; return true; } } public function ldapHelperDeleteUser(HookEvent $event) { $page = $event->arguments("page"); if (!$page->id && !$page->template->name === "user") return; // Return if User is not deleted $username = $page->name; // bind mit passendem dn für aktualisierenden Zugriff $connect = $this->ldapHelperConnect(); $r= $this->ldapHelperWrite($connect); $user_search = ldap_search($connect,"dc=ffmyk,dc=de","(|(uid=$user))"); $user_entry = ldap_first_entry($connect, $user_search); // Delete User from LDAP $dn= ldap_get_dn($connect, $user_entry); if(ldap_delete( $connect , $dn )){ $this->message("Delete LDAP User: $username"); $this->log->save('ldap_helper', "Delete User: $username"); } else { $errno = ldap_errno($connect); // Error code $error = ldap_error($connect); // Error text $this->message("Delete LDAP User failed $error ($errno)"); $this->log->save('ldap_helper', "Delete User failed $error ($errno)"); } ldap_close($connect); } protected function makeSshaPassword($password) { mt_srand((double)microtime()*1000000); $salt = pack("CCCC", mt_rand(), mt_rand(), mt_rand(), mt_rand()); $hash = "{SSHA}" . base64_encode(pack("H*", sha1($password . $salt)) . $salt); return $hash; } protected function ldapHelperConnect() { if ($this->debugMode) ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7); // LDAP DebugMode if(!$connection = ldap_connect($this->host, $this->port)) return $this->log->save('LDAP', printf(__("Failed to connect LDAP %d pages."), ldap_err2str(ldap_errno($connection)))); // Annahme: der LDAP Server befindet sich auf diesem Host if ($this->useV3) ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3); // Set LDAP_PROTOCOL_VERSION return $connection; } protected function ldapHelperWrite($ds) { if(empty($ds)) return; return ldap_bind($ds,"$this->admin", "$this->secret"); } public function validateConfiguration() { $connection = $this->ldapHelperConnect(); if (!$connection) { return; } $this->message($this->_('Successfully connected to LDAP server.')); $bind = $this->ldapHelperWrite($connection); $ldapMessage = ldap_err2str(ldap_errno($connection)); $this->message("Bind $ldapMessage"); } public function hookModuleSave(HookEvent $event) { $className = $event->arguments [0]; if ($className != get_class($this)) return; $this->validateConfiguration(); } static public function getModuleConfigInputfields(array $data) { $inputfields = new InputfieldWrapper (); $hostField = wire('modules')->get('InputfieldText'); $hostField->name = 'host'; $hostField->columnWidth = 80; $hostField->label = __('LDAP Server'); $hostField->required = 1; if (isset ($data ['host'])) $hostField->value = $data ['host']; $hostField->description = __('The hostname of your LDAP server. This can be either an ip address or a domain name. Supply a custom port (different than 389) separated with a colon. Examples: 10.0.0.1, controller.domain.com, controller.domain.com:388'); $inputfields->add($hostField); $useSSLField = wire('modules')->get('InputfieldCheckbox'); $useSSLField->name = 'useSSL'; $useSSLField->columnWidth = 20; $useSSLField->label = __('Use SSL?'); $useSSLField->description = __('Connects to the LDAP Server via SSL.'); if (isset ($data ['useSSL']) && $data ['useSSL'] == 1) $useSSLField->checked = 1; $inputfields->add($useSSLField); $defaultLoginDomainField = wire('modules')->get('InputfieldText'); $defaultLoginDomainField->name = 'loginDomain'; $defaultLoginDomainField->label = __('Default Login Domain'); $defaultLoginDomainField->columnWidth = 40; $defaultLoginDomainField->required = 1; if (isset ($data ['loginDomain'])) $defaultLoginDomainField->value = $data ['loginDomain']; $defaultLoginDomainField->description = __('This is the domain name used by default if the user does not supply a domain name. It will be added to the username, e.g. username@domainname.com'); $inputfields->add($defaultLoginDomainField); $adminLoginField = wire('modules')->get('InputfieldText'); $adminLoginField->name = 'userdn'; $adminLoginField->columnWidth = 40; $adminLoginField->label = __('LDAP User DN'); $adminLoginField->required = 1; if (isset ($data ['userdn'])) $adminLoginField->value = $data ['userdn']; $adminLoginField->description = __('The DN for the user. Example: ou=Person,dc=domain,dc=com'); $inputfields->add($adminLoginField); $useV3Field = wire('modules')->get('InputfieldCheckbox'); $useV3Field->name = 'useV3'; $useV3Field->columnWidth = 20; $useV3Field->label = __('Use Protocol V3?'); $useV3Field->description = __('Use LDAP Protocol V3.'); if (isset ($data ['useV3']) && $data ['useV3'] == 1) $useV3Field->checked = 1; $inputfields->add($useV3Field); $adminLoginField = wire('modules')->get('InputfieldText'); $adminLoginField->name = 'admin'; $adminLoginField->columnWidth = 50; $adminLoginField->label = __('LDAP Admin DN'); $adminLoginField->required = 1; if (isset ($data ['admin'])) $adminLoginField->value = $data ['admin']; $adminLoginField->description = __('An LDAP account with access to add/edit/delet users. Example: cn=accountmanager,dc=domain,dc=com'); $inputfields->add($adminLoginField); $secretField = wire('modules')->get('InputfieldText'); $secretField->attr ('type','password'); $secretField->name = 'secret'; $secretField->columnWidth = 50; $secretField->label = __('LDAP Admin Secret'); $secretField->description = __('Needet to use with LDAP Admin to add/edit/delete users.'); if (isset ($data ['secret'])) $secretField->value = $data ['secret']; $inputfields->add($secretField); $ldapSettingField = wire('modules')->get('InputfieldTextarea'); $ldapSettingField->name = 'ldapSetting'; $ldapSettingField->columnWidth = 50; $ldapSettingField->label = __('Entry Setup'); $ldapSettingField->description = __('The Entry Setup for LDAP Users. Includes objectClass, uid, cn... one per Line. Set Variables @variable@.'); if (isset ($data ['ldapSetting'])) $ldapSettingField->value = $data ['ldapSetting']; $inputfields->add($ldapSettingField); $userDefaultRolesField = wire('modules')->get('InputfieldPageListSelectMultiple'); $userDefaultRolesField->name = 'userDefaultRoles'; $userDefaultRolesField->label = __('Default Roles for new Users'); $userDefaultRolesField->description = __('These user roles will be applied to all new LDAP users. Please note that the guest role is applied automatically.'); $userDefaultRolesField->parent_id = wire('roles')->getGuestRole()->parent_id; if (isset ($data ['userDefaultRoles'])) $userDefaultRolesField->value = $data ['userDefaultRoles']; $inputfields->add($userDefaultRolesField); $debugField = wire('modules')->get('InputfieldCheckbox'); $debugField->name = 'debug'; $debugField->collapsed = Inputfield::collapsedYes; $debugField->label = __('Debug Mode'); $debugField->description = __('Turns on the debug mode so you can see the output of PHP\'s ldap module in the apache log.'); if (isset ($data ['debug']) && $data ['debug'] == 1) $debugField->checked = 1; $inputfields->add($debugField); return $inputfields; } }