adsObj = new AuthADS($cfg['domain'], $cfg['dc'], $secure); $this->adsObj->connect(isset($cfg['ctrluser']) ? $cfg['ctrluser'] : false, isset($cfg['ctrlpasswd']) ? $cfg['ctrlpasswd'] : false); if(!isset($cfg['groupsrc'])) $cfg['groupsrc'] = self::GRP_SRC_AD; switch(strtolower($cfg['groupsrc'])) { case self::GRP_SRC_AD: $cfg['groupsrc'] = self::GRP_SRC_AD; break; default: $cfg['groupsrc'] = self::GRP_SRC_DB; break; } $this->cfg = $cfg; } public function createUser(iUser $user) { throw new \BadMethodCallException('unsupported operation', 901); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::loginUser() */ public function loginUser($login, $password, $lifetime = 0) { $system = \MCMS\System::getInstance(); if(!$this->adsObj->authenticate($login, $password) || empty($password)) return -2; $adsUsr = $this->adsObj->getUserByName($login); //var_dump($adsUsr); $id = $this->sid2int($adsUsr['objectSid']); //var_dump($id); $user = $this->getUser($id); //var_dump($user); $authString = $user->id . ':' . sha1($user->seed); setcookie($this->cookyKey, $authString, $lifetime); return $user; $usrGrp = $this->adsObj->userGroups($login); $db = $system->getDB(); $result = $db->table($this->accTable)->select(array('login' => $adsUsr['objectguid'])); // TODO: multipage login if($result->getRowCount() == 0) { $data = array( 'login' => $adsUsr['objectguid'],'password' => '-','state' => 0, 'authtoken' => sha1(rand(0, 999999999)),'email' => '-', 'seed' => 101 + rand(0, 99800),'masteradmin' => 0,'failed_login_count' => 0); $result = $db->table($this->accTable)->insert($data); $data['id'] = $db->getInsertId(); } else { $search = array('login' => $adsUsr['objectguid']); $data2 = array('authtoken' => sha1(rand(0, 999999999))); $db->table($this->accTable)->update($data2, $search); $data = $result->fetchArray(); $data['authtoken'] = $data2['authtoken']; } $authString = $data['id'] . ':' . $data['authtoken']; setcookie($this->cookyKey, $authString, $lifetime); return $this->getUser((int) $data['id']); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::logoutUser() */ public function logoutUser() { $system = \MCMS\System::getInstance(); $session = $system->getSession(); $session->clear('', $this->cookyKey); setcookie($this->cookyKey, '', time() - 3600); } protected function sid2int($sid) { $parts = explode('-',$sid); return (int) $parts[count($parts)-1]; } protected function int2sid($id) { $prefix = bin2hex($this->adsObj->getDomainSid(true)); $prefix_1 = substr($prefix,0,2); $prefix_2 = substr($prefix,2,2); $prefix_3 = substr($prefix,4); $prefix_2 = dechex(hexdec($prefix_2)+1); if (strlen($prefix_2)%2 != 0) $prefix_2 = '0'.$prefix_2; $prefix = $prefix_1.$prefix_2.$prefix_3; $hexid = dechex($id); while (strlen($hexid) < 8) $hexid = '0'.$hexid; $hexid = $prefix.AuthADS::convertLittleEndian($hexid); return $hexid; } /** * Fetches a user from the data storage. * If the user could not be found, the method returns null. * * @param $id mixed * login string or the user id integer, use (int) -1 or empty to get the * current user * @return iUser the user specified or null if none is found or none was logged in */ public function getUser($id = -1) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); if($id === -1) { // current user $session = $system->getSession(); $authString = $session->get('', $this->cookyKey, NULL); if(is_null($authString)) { if(!empty($_COOKIE[$this->cookyKey])) $authString = $_COOKIE[$this->cookyKey]; } if(!is_null($authString)) { if(preg_match('#^([0-9]+):([A-Za-z0-9]+)$#', $authString, $match)) { $id = (int) $match[1]; $token = $match[2]; if($id > 0) { $user = $this->getUser((int) $id); if ($match[2] == sha1($user->seed)) return $user; } } } return NULL; } else { // selected user $prefix = bin2hex($this->adsObj->getDomainSid(true)); $prefix_1 = substr($prefix,0,2); $prefix_2 = substr($prefix,2,2); $prefix_3 = substr($prefix,4); $prefix_2 = dechex(hexdec($prefix_2)+1); if (strlen($prefix_2)%2 != 0) $prefix_2 = '0'.$prefix_2; $prefix = $prefix_1.$prefix_2.$prefix_3; $hexid = dechex($id); while (strlen($hexid) < 8) $hexid = '0'.$hexid; $hexid = $prefix.AuthADS::convertLittleEndian($hexid); try { $adUser = $this->adsObj->getUserBySID($hexid, true); $id = $this->sid2int($adUser['objectSid']); $cond = array('id' => $id); $result = $db->table($this->accTable)->select($cond); if($result->getRowCount() == 0) { $result->close(); $data = array( 'id' => $id, 'login' => $adUser['sAMAccountName'], 'seed' => 1000 + rand(0, 98000), 'state' => 0, 'masteradmin' => false, 'authtoken' => '', 'email' => '', 'password' => '-', 'failed_login_count' => 0 ); if ($db->getDialect() == \Mammut\DB\DB::DIALECT_MSSQL) $db->query("SET IDENTITY_INSERT {$this->accTable} ON"); $db->table($this->accTable)->insert($data); if ($db->getDialect() == \Mammut\DB\DB::DIALECT_MSSQL) $db->query("SET IDENTITY_INSERT {$this->accTable} OFF"); $result = $db->table($this->accTable)->select($cond); } $data = $result->fetchObject(); $result->close(); $user = new UserADS($data->id); $user->login = $adUser['sAMAccountName']; $user->seed = $data->seed; $user->email = isset($adUser['mail']) ? $adUser['mail'] : (isset($adUser['userPrincipalName']) ? $adUser['userPrincipalName'] : false); // Administrator UID is 500 in AD/Windows $user->masteradmin = ($user->id == 500) || $data->masteradmin; return $user; } catch (\LengthException $e) { return NULL; } } return NULL; } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getUserList() */ public function getUserList(array $filer = array()) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); $users = $this->adsObj->listUsers(); // sort($users, SORT_LOCALE_STRING); $ulist = array(); foreach($users as $user) { $usr = $this->getUser($this->sid2int($user['objectsid'])); array_push($ulist, $usr); } return $ulist; } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::removeUser() */ public function removeUser(iUser $user) { throw new BadMethodCallException('unsupported operation', 901); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::setUserAttr() */ public function setUserAttr($id, $attrname, $value) { throw new BadMethodCallException('unsupported operation', 901); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getUserAttr() */ public function getUserAttr($id, $attrname) { } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::createGroup() */ public function createGroup(iGroup $group) { throw new BadMethodCallException('unsupported operation', 901); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getGroup() */ public function getGroup($id) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); if($this->cfg['groupsrc'] = self::GRP_SRC_AD) { $prefix = bin2hex($this->adsObj->getDomainSid(true)); $prefix_1 = substr($prefix,0,2); $prefix_2 = substr($prefix,2,2); $prefix_3 = substr($prefix,4); $prefix_2 = dechex(hexdec($prefix_2)+1); if (strlen($prefix_2)%2 != 0) $prefix_2 = '0'.$prefix_2; $prefix = $prefix_1.$prefix_2.$prefix_3; $hexid = dechex($id); while (strlen($hexid) < 8) $hexid = '0'.$hexid; $hexid = $prefix.AuthADS::convertLittleEndian($hexid); try { $adGroup = $this->adsObj->getGroupBySID($hexid, true); $id = $this->sid2int($adGroup['objectSid']); $cond = array('id' => $id); $result = $db->table($this->grpTable)->select($cond); if($result->getRowCount() == 0) { $result->close(); $data = array( 'id' => $id, 'name' => $adGroup['sAMAccountName'], 'state' => 0 ); if ($db->getDialect() == \Mammut\DB\DB::DIALECT_MSSQL) $db->query("SET IDENTITY_INSERT {$this->grpTable} ON"); $db->table($this->grpTable)->insert($data); if ($db->getDialect() == \Mammut\DB\DB::DIALECT_MSSQL) $db->query("SET IDENTITY_INSERT {$this->grpTable} OFF"); $result = $db->table($this->grpTable)->select($cond); } $data = $result->fetchObject(); $result->close(); $group = new GroupADS(); $group->id = $data->id; $group->name = $adGroup['sAMAccountName']; return $group; } catch (\LengthException $e) { return NULL; } } else { $db = $system->getDB(); $id = (int) $id; if($id <= -1) throw new Exception("invalid group id"); else { $cond = array('id' => $id); $result = $db->table($this->grpTable)->select($cond); if($result->getRowCount() == 0) return NULL; $grp = $result->fetchObject('MMGroupDefault'); $this->_addGroupData($grp); return $grp; } return NULL; } } /** * Adds the additional settings stored in the local database * * @param iGroup $grp * the group object */ private function _addGroupData(iGroup &$grp) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); $acls = $db->table('acl')->select(array('account_id' => 0,'group_id' => $grp->getId()))->fetchObjectList(); foreach($acls as $acl) $grp->setPriv($acl->site_id, $acl->instance, $acl->key, true); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getGroupList() */ public function getGroupList(array $filer = array()) { if($this->cfg['groupsrc'] = self::GRP_SRC_AD) { $groups = $this->adsObj->listGroups(); $result = array(); foreach($groups as $group) { // simple filter for non-domain objects if (strpos($group['distinguishedname'] ,',CN=Builtin,') !== false) continue; $g = new GroupADS(); $g->setId($this->sid2int($group['objectsid'])); $g->setName($group['name']); array_push($result, $g); } return $result; } else { $result = $db->table($this->grpTable)->select(); $grps = $result->fetchObjectList('MMGroupDefault'); return $grps; } } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::updateGroup() */ public function updateGroup(iGroup $group) { if($this->cfg['groupsrc'] = 'ads') throw new BadMethodCallException('unsupported operation', 901); else { } } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::removeGroup() */ public function removeGroup(iGroup $group) { if($this->cfg['groupsrc'] = 'ads') throw new BadMethodCallException('unsupported operation', 901); else { $system = \MCMS\System::getInstance(); $db = $system->getDB(); $id = $group->getId(); $db->isTransactionSupported() and $db->startTransaction(); $db->table('groupmembers')->delete(array('group_id' => $id)); $db->table('acl')->delete(array('account_id' => 0,'group_id' => $id)); $db->table('groupsettings')->delete(array('id' => $id)); $db->table('grouptextsettings')->delete(array('id' => $id)); $db->table('groupbinsettings')->delete(array('id' => $id)); $db->isTransactionSupported() and $db->commit(); // TODO: add module/plugin hook } } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::userGrantPriv() */ public function userGrantPriv(iUser $usr, $siteId, $instance, $key, $value = NULL) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::userHasPriv() */ public function userHasPriv(iUser $usr, $siteId = NULL, $instance = false, $key = false, $strict = false) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); if(is_null($usr) || $usr === false) return false; if($usr instanceof iUser) { $id = $usr->getId(); if($usr->masteradmin == true) return true; } else $id = (int) $usr; // check if the number of master admin groups is bigger than none if($db->getObject("SELECT COUNT(groupmembers.account_id) AS c FROM groups JOIN groupmembers ON groups.id = groupmembers.group_id WHERE groupmembers.account_id={$id} AND groups.masteradmin=" . $db->escapeValue(true))->c > 0) return true; // get all groups which contains the user and have the privileges $keyfield = $db->escapeColumnName('key'); $instancefield = $db->escapeColumnName('instance'); $condition = $db->escapeColumnName('site_id') . '=' . $db->escapeValue($siteId) . ' AND ' . $db->escapeColumnName('instance') . '=' . $db->escapeValue($instance) . ' AND ' . $keyfield . '=' . $db->escapeValue($key); $privs = $db->getObjectList("SELECT DISTINCT " . $db->escapeTableName($this->membTable) . '.' . $db->escapeColumnName('account_id') . ',' . $db->escapeTableName($this->membTable) . '.' . $db->escapeColumnName('group_id') . ',' . $db->escapeTableName('acl') . '.' . $db->escapeColumnName('site_id') . ',' . $db->escapeColumnName('instance') . ',' . $db->escapeTableName('acl') . '.' . $db->escapeColumnName('key') . ',' . $db->escapeTableName('acl') . '.' . $db->escapeColumnName('value') . " FROM acl JOIN groupmembers ON acl.group_id = groupmembers.group_id WHERE groupmembers.account_id ={$id} AND {$condition} UNION SELECT DISTINCT * FROM acl WHERE account_id ={$id} AND group_id =0 AND {$condition}"); foreach($privs as $p) { if($p->site_id == $siteId && $p->instance == $instance && $p->key == $key) // check to be sure return true; } return false; // nothing found, not privileged } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::userClearPriv() */ public function userClearPriv(iUser $usr, $siteId = -1) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); if($siteId >= 0) $db->table('acl')->delete(array('account_id' => $id,'group_id' => 0)); else $db->table('acl')->delete(array( 'account_id' => $id,'group_id' => 0,'site_id' => $siteId)); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::groupGrantPriv() */ public function groupGrantPriv(iGroup $grp, $siteId, $instance, $key, $value = NULL) { $system = System::getInstance(); $db = $system->getDB(); $db->table('acl')->insert(array( 'site_id' => $siteId,'account_id' => 0,'group_id' => $grp->getId(), 'instance' => $instance,'key' => $key,'value' => is_null(value) ? 0 : (int) $value)); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::groupHasPriv() */ public function groupHasPriv(iGroup $grp, $siteId = NULL, $instance = false, $key = false, $strict = false) { $system = System::getInstance(); $db = $system->getDB(); $id = (int) $grp->getId(); $privs = $db->getObjectList("SELECT DISTINCT * FROM acl WHERE account_id=0 AND group_id ={$id}"); foreach($privs as $p) { if($p->site_id == $siteId && $p->instance == $instance && $p->key == $key) // check to be sure return true; } return false; // nothing found, not privileged } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::groupClearPriv() */ public function groupClearPriv(iGroup $grp, $siteId = -1) { $system = \MCMS\System::getInstance(); $db = $system->getDB(); if($siteId >= 0) $db->table('acl')->delete(array('account_id' => 0,'group_id' => $grp->getId())); else $db->table('acl')->delete(array( 'account_id' => 0,'group_id' => $grp->getId(),'site_id' => $siteId)); } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getUserEditOptions() */ public function getUserEditOptions() { return 0; } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getGroupEditOptions() */ public function getGroupEditOptions() { if($this->cfg['groupsrc'] = 'ads') return 0; else return iPlugInAuth::FEATURE_CREATE_GROUP & iPlugInAuth::FEATURE_UPDATE_GROUP & iPlugInAuth::UE_UPDATE_GROUPMEMBER & iPlugInAuth::FEATURE_DELETE_GROUP; } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getUserGroups() */ public function getUserGroups($id) { $result = array(); if ($id instanceof UserADS) $id = $id->getId(); $sid = $this->int2sid($id); $adUser = $this->adsObj->getUserBySID($sid,true); foreach ($adUser['memberOf'] as $groupPath) { $group = $this->adsObj->getGroupByDN($groupPath); $gid = $this->sid2int($group['objectSid']); $result[] = $gid; } return $result; } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuth::getGroupMembers() */ public function getGroupMembers($id) { if($this->cfg['groupsrc'] = self::GRP_SRC_AD) { $result = array(); if ($id instanceof GroupADS) $id = $id->getId(); $sid = $this->int2sid($id); $adGroup = $this->adsObj->getGroupBySID($sid,true); if (!isset($adGroup['member'])) return array(); if (is_string($adGroup['member'])) { try { $user = $this->adsObj->getUserByDN($adGroup['member']); $uid = $this->sid2int($this->sid2int($user['objectSid'])); $result[] = $uid; } catch (\LengthException $e) {} } else { foreach ($adGroup['member'] as $userPath) { try { $user = $this->adsObj->getUserByDN($userPath); $uid = $this->sid2int($this->sid2int($user['objectSid'])); $result[] = $uid; } catch (\LengthException $e) {} } } return $result; } else { return array(); } } /** * (non-PHPdoc) * * @see \MCMS\Interfaces\iPlugInAuthSynced::syncUserList() */ public function syncUserList() { /* $users = $this->getUserList(); $db = \MCMS\System::getInstance()->getDB(); foreach($users as $usr) { $adData = $usr->getADData(); $cond = array('login' => $adData['objectguid']); $result = $db->table($this->accTable)->select($cond); if($result->getRowCount() > 1) { echo "user: " . $usr->getLogin() . "\n"; echo "\tinvalid row count (" . $result->getRowCount() . ")\n"; } elseif($result->getRowCount() == 0) { echo "user: " . $usr->getLogin() . "\n"; echo "\tmissing row, adding...\n"; } elseif($result->getRowCount() == 1) { // echo "\tchecking row...\n"; } $result->close(); } $result = $db->table($this->accTable)->select(); while($row = $result->fetchObject()) { $usr = $this->adsObj->getUserByGUID($row->login); if(empty($usr)) echo "found row without ad entry: {$row->login}...\n"; }*/ } public function syncGroupList() { } /** * Returns the configuration of the group source * * @return string ads or db */ public function getGroupType() { return $this->cfg['groupsrc']; } public function executeCronRun(array $runParam) { echo "Running user management cron tasks\n"; var_dump($runParam); echo "Syncing users\n"; $this->syncUserList(); echo "Syncing groups\n"; $this->syncGroupList(); } }