/** * Create a new sudoer based on name, users, hosts, commands, and options. * Returns null on sudoer creation failure. * * @static * @param $sudoername * @param $users * @param $hosts * @param $commands * @param $options * @return null|OpenStackNovaSudoer */ static function createSudoer( $sudoername, $users, $hosts, $commands, $options ) { global $wgAuth, $wgOpenStackManagerLDAPSudoerBaseDN; OpenStackNovaLdapConnection::connect(); $sudoer = array(); $sudoer['objectclass'][] = 'sudorole'; foreach ( $users as $user ) { $sudoer['sudouser'][] = $user; } foreach ( $hosts as $host ) { $sudoer['sudohost'][] = $host; } foreach ( $commands as $command ) { $sudoer['sudocommand'][] = $command; } foreach ( $options as $option ) { $sudoer['sudooption'][] = $option; } $sudoer['cn'] = $sudoername; $dn = 'cn=' . $sudoername . ',' . $wgOpenStackManagerLDAPSudoerBaseDN; $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $dn, $sudoer ); if ( $success ) { $wgAuth->printDebug( "Successfully added sudoer $sudoername", NONSENSITIVE ); return new OpenStackNovaSudoer( $sudoername ); } else { $wgAuth->printDebug( "Failed to add sudoer $sudoername", NONSENSITIVE ); return null; } }
/** * Create a new sudoer based on name, users, commands, and options. * Returns null on sudoer creation failure. * * @static * @param $sudoername * @param $projectName * @param $users * @param $commands * @param $options * @return null|OpenStackNovaSudoer */ static function createSudoer($sudoername, $projectName, $users, $runasuser, $commands, $options) { global $wgAuth; OpenStackNovaLdapConnection::connect(); $sudoer = array(); $sudoer['objectclass'][] = 'sudorole'; foreach ($users as $user) { $sudoer['sudouser'][] = $user; } foreach ($runasuser as $runas) { $sudoer['sudorunasuser'][] = $runas; } foreach ($commands as $command) { $sudoer['sudocommand'][] = $command; } foreach ($options as $option) { $sudoer['sudooption'][] = $option; } $sudoer['sudohost'][] = 'ALL'; $sudoer['cn'] = $sudoername; $project = OpenStackNovaProject::getProjectByName($projectName); $dn = 'cn=' . $sudoername . ',' . $project->getSudoersDN(); $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $dn, $sudoer); if ($success) { $wgAuth->printDebug("Successfully added sudoer {$sudoername}", NONSENSITIVE); return new OpenStackNovaSudoer($sudoername, $project); } else { $wgAuth->printDebug("Failed to add sudoer {$sudoername}", NONSENSITIVE); return null; } }
/** * Create a new project group based on project name. * * @static * @param $projectname * @return bool */ static function createProjectGroup($projectname) { global $wgAuth; global $wgOpenStackManagerLDAPProjectGroupBaseDN; OpenStackNovaLdapConnection::connect(); $projectGroupName = self::$prefix . $projectname; $projectGroup = array(); $projectGroup['objectclass'][] = 'posixgroup'; $projectGroup['objectclass'][] = 'groupofnames'; $projectGroup['cn'] = $projectGroupName; $projectGroup['gidnumber'] = OpenStackNovaUser::getNextIdNumber($wgAuth, 'gidnumber'); $projectGroupDN = 'cn=' . $projectGroupName . ',' . $wgOpenStackManagerLDAPProjectGroupBaseDN; # TODO: If project group creation fails we need to be able to fail gracefully $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $projectGroupDN, $projectGroup); if ($success) { $wgAuth->printDebug("Successfully added project group {$projectGroupName}", NONSENSITIVE); } else { $wgAuth->printDebug("Failed to add project group {$projectGroupName}: " . ldap_error($wgAuth->ldapconn), NONSENSITIVE); } return $success; }
/** * Create a new project based on project name. This function will also create * all roles needed by the project. * * @static * @param $projectname * @return bool */ static function createProject($projectname) { global $wgAuth; global $wgOpenStackManagerLDAPUser; global $wgOpenStackManagerLDAPProjectBaseDN; OpenStackNovaLdapConnection::connect(); $project = array(); $project['objectclass'][] = 'groupofnames'; $project['objectclass'][] = 'posixgroup'; $project['cn'] = $projectname; $project['owner'] = $wgOpenStackManagerLDAPUser; $project['gidnumber'] = OpenStackNovaUser::getNextIdNumber($wgAuth, 'gidnumber'); $projectdn = 'cn=' . $projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $projectdn, $project); $project = new OpenStackNovaProject($projectname); if ($success) { foreach (self::$rolenames as $rolename) { $role = OpenStackNovaRole::createRole($rolename, $project); # TODO: If role addition fails, find a way to fail gracefully # Though, if the project was added successfully, it is unlikely # that role addition will fail. } $wgAuth->printDebug("Successfully added project {$projectname}", NONSENSITIVE); return true; } else { $wgAuth->printDebug("Failed to add project {$projectname}", NONSENSITIVE); return false; } }
/** * Add a user to LDAP. * Return true if successful. * * @param User $user * @param string $password * @param string $email * @param string $realname * @return bool */ public function addUser($user, $password, $email = '', $realname = '') { $this->printDebug("Entering addUser", NONSENSITIVE); if (!$this->getConf('AddLDAPUsers') || 'local' == $this->getSessionDomain()) { $this->printDebug("Either the user is using a local domain, or the wiki isn't allowing users to be added to LDAP", NONSENSITIVE); // Tell the wiki not to return an error. return true; } if ($this->getConf('RequiredGroups')) { $this->printDebug("The wiki is requiring users to be in specific groups, and cannot add users as this would be a security hole.", NONSENSITIVE); // It is possible that later we can add users into // groups, but since we don't support it, we don't want // to open holes! return false; } $writer = $this->getConf('WriterDN'); if (!$writer) { $this->printDebug("The wiki doesn't have wgLDAPWriterDN set", NONSENSITIVE); // We can't add users without an LDAP account capable of doing so. return false; } $this->email = $user->getEmail(); $this->realname = $user->getRealName(); $username = $user->getName(); if ($this->getConf('LowercaseUsernameScheme')) { $username = strtolower($username); } $pass = $this->getPasswordHash($password); if ($this->connect()) { $writeloc = $this->getConf('WriteLocation'); $this->userdn = $this->getSearchString($username); if ('' == $this->userdn) { $this->printDebug("userdn is blank, attempting to use wgLDAPWriteLocation", NONSENSITIVE); if ($writeloc) { $this->printDebug("wgLDAPWriteLocation is set, using that", NONSENSITIVE); $this->userdn = $this->getConf('SearchAttribute') . "=" . $username . "," . $writeloc; } else { $this->printDebug("wgLDAPWriteLocation is not set, failing", NONSENSITIVE); // getSearchString will bind, but will not unbind LdapAuthenticationPlugin::ldap_unbind($this->ldapconn); return false; } } $this->printDebug("Binding as the writerDN", NONSENSITIVE); $bind = $this->bindAs($writer, $this->getConf('WriterPassword')); if (!$bind) { $this->printDebug("Failed to bind as the writerDN; add failed", NONSENSITIVE); return false; } // Set up LDAP objectclasses and attributes // TODO: make objectclasses and attributes configurable $values["uid"] = $username; // sn is required for objectclass inetorgperson $values["sn"] = $username; if (is_string($this->email)) { $values["mail"] = $this->email; } if (is_string($this->realname)) { $values["cn"] = $this->realname; } else { $values["cn"] = $username; } $values["userpassword"] = $pass; $values["objectclass"] = array("inetorgperson"); $result = true; # Let other extensions modify the user object before creation wfRunHooks('LDAPSetCreationValues', array($this, $username, &$values, $writeloc, &$this->userdn, &$result)); if (!$result) { $this->printDebug("Failed to add user because LDAPSetCreationValues returned false", NONSENSITIVE); LdapAuthenticationPlugin::ldap_unbind($this->ldapconn); return false; } $this->printDebug("Adding user", NONSENSITIVE); if (LdapAuthenticationPlugin::ldap_add($this->ldapconn, $this->userdn, $values)) { $this->printDebug("Successfully added user", NONSENSITIVE); LdapAuthenticationPlugin::ldap_unbind($this->ldapconn); return true; } $this->printDebug("Failed to add user", NONSENSITIVE); LdapAuthenticationPlugin::ldap_unbind($this->ldapconn); } return false; }
/** * @static * @param $rolename * @param $project OpenStackNovaProject * @return bool */ static function createRole( $rolename, $project ) { global $wgAuth; OpenStackNovaLdapConnection::connect(); $role = array(); $role['objectclass'][] = 'groupofnames'; $role['cn'] = $rolename; $roledn = 'cn=' . $rolename . ',' . $project->projectDN; $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $roledn, $role ); # TODO: If role addition fails, find a way to fail gracefully # Though, if the project was added successfully, it is unlikely # that role addition will fail. if ( $success ) { $wgAuth->printDebug( "Successfully added role $rolename", NONSENSITIVE ); return true; } else { $wgAuth->printDebug( "Failed to add role $rolename", NONSENSITIVE ); return false; } }
/** * @static * @param $groupName * @param $project OpenStackNovaProject * @param $initialUser * @return null|OpenStackNovaServiceGroup */ static function createServiceGroup($inGroupName, $project, $initialUser) { global $wgAuth; global $wgOpenStackManagerLDAPUser; global $wgOpenStackManagerLDAPDefaultShell; global $wgOpenStackManagerLDAPServiceGroupBaseDN; global $wgMemc; OpenStackNovaLdapConnection::connect(); $projectPrefix = $project->getProjectName() . '.'; # We don't want naming collisions between service groups and actual groups # or users. So, prepend $projectPrefix to the requested group name. if (strpos($inGroupName, $projectPrefix, 0) === 0) { # The user was clever and already added the prefix. $groupName = $inGroupName; $simpleGroupName = substr($inGroupName, strlen($projectPrefix)); } else { $groupName = $projectPrefix . $inGroupName; $simpleGroupName = $inGroupName; } if ($initialUser) { $user = new OpenStackNovaUser($initialUser); if (!$user->userDN) { $wgAuth->printDebug("Unable to find initial user {$initialUser} for new group {$groupName}", NONSENSITIVE); return null; } $initialUserDN = $user->userDN; } $key = wfMemcKey('openstackmanager', 'servicegroup', $groupName); $wgMemc->delete($key); $group = array(); $group['objectclass'][] = 'posixgroup'; $group['objectclass'][] = 'groupofnames'; $group['cn'] = $groupName; $groupdn = 'cn=' . $groupName . ',' . $wgOpenStackManagerLDAPServiceGroupBaseDN; $group['gidnumber'] = OpenStackNovaUser::getNextIdNumber($wgAuth, 'gidnumber'); $group['member'] = array(); if ($initialUser) { $group['member'][] = $initialUserDN; } $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $groupdn, $group); if ($success) { $wgAuth->printDebug("Successfully added service group {$groupdn}", NONSENSITIVE); } else { $wgAuth->printDebug("Failed to add service group {$groupdn}", NONSENSITIVE); return null; } # stamp out regular expressions! $homeDir = $project->getServiceGroupHomedirPattern(); $homeDir = str_ireplace('%u', $simpleGroupName, $homeDir); $homeDir = str_ireplace('%p', $projectPrefix, $homeDir); # Now create the special SG member $newGroup = self::getServiceGroupByName($groupName, $project); $userdn = $newGroup->getSpecialUserDN(); $user = array(); $user['objectclass'][] = 'shadowaccount'; $user['objectclass'][] = 'posixaccount'; $user['objectclass'][] = 'person'; $user['objectclass'][] = 'top'; $user['loginshell'] = $wgOpenStackManagerLDAPDefaultShell; $user['homedirectory'] = $homeDir; $user['uidnumber'] = $group['gidnumber']; $user['gidnumber'] = $group['gidnumber']; $user['uid'] = $groupName; $user['sn'] = $groupName; $user['cn'] = $groupName; $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $userdn, $user); if ($success) { $wgAuth->printDebug("Successfully created service user {$userdn}", NONSENSITIVE); } else { $wgAuth->printDebug("Failed to create service user {$userdn}", NONSENSITIVE); return null; } # Create Sudo policy so that the service user can chown files in its homedir if (OpenStackNovaSudoer::createSudoer($groupName . '-chmod', $project->getProjectName(), array($groupName), array(), array('/bin/chown -R ' . $groupName . '\\:' . $groupName . ' ' . $homeDir), array('!authenticate'))) { $wgAuth->printDebug("Successfully created chmod sudo policy for {$groupName}", NONSENSITIVE); } else { $wgAuth->printDebug("Failed to creat chmod sudo policy for {$groupName}", NONSENSITIVE); } # Create Sudo policy so that members of the group can sudo as the service user if (OpenStackNovaSudoer::createSudoer('runas-' . $groupName, $project->getProjectName(), array("%" . $groupName), array($groupName), array('ALL'), array('!authenticate'))) { $wgAuth->printDebug("Successfully created run-as sudo policy for {$groupName}", NONSENSITIVE); } else { $wgAuth->printDebug("Failed to creat run-as sudo policy for {$groupName}", NONSENSITIVE); } return $newGroup; }
/** * Adds a host entry based on the hostname, IP addrss, and a domain. Returns null * if the entry already exists, or if the additional fails. This function should be used * for adding public DNS entries. * * @static * @param $hostname * @param $ip * @param $domain OpenStackNovaDomain * @return bool|null|OpenStackNovaHost */ static function addPublicHost($hostname, $ip, $domain) { global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; OpenStackNovaLdapConnection::connect(); $domainname = $domain->getFullyQualifiedDomainName(); $host = OpenStackNovaHost::getHostByPublicIP($ip); if ($host) { $wgAuth->printDebug("Failed to add public host {$hostname} as the DNS entry already exists", NONSENSITIVE); return null; } $hostEntry = array(); $hostEntry['objectclass'][] = 'dcobject'; $hostEntry['objectclass'][] = 'dnsdomain'; $hostEntry['objectclass'][] = 'domainrelatedobject'; $hostEntry['dc'] = $ip; $hostEntry['arecord'] = $ip; $hostEntry['associateddomain'][] = $hostname . '.' . $domainname; $dn = 'dc=' . $ip . ',' . $wgOpenStackManagerLDAPInstanceBaseDN; $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $dn, $hostEntry); if ($success) { $domain->updateSOA(); $wgAuth->printDebug("Successfully added public host {$hostname}", NONSENSITIVE); return new OpenStackNovaHost(false, null, $ip); } else { $wgAuth->printDebug("Failed to add public host {$hostname} with dn = {$dn}", NONSENSITIVE); return null; } }
/** * Create a new domain based on shortname, fully qualified domain name * and location. If location is an empty string, the domain created will * be a public domain, otherwise it will be a private domain for instance * creation. Returns null on domain creation failure. * * @static * @param $domainname * @param $fqdn * @param $location * @return null|OpenStackNovaDomain */ static function createDomain( $domainname, $fqdn, $location ) { global $wgAuth; global $wgOpenStackManagerLDAPInstanceBaseDN; global $wgOpenStackManagerDNSOptions; OpenStackNovaLdapConnection::connect(); $soa = OpenStackNovaDomain::generateSOA(); $domain = array(); $domain['objectclass'][] = 'dcobject'; $domain['objectclass'][] = 'dnsdomain'; $domain['objectclass'][] = 'domainrelatedobject'; $domain['dc'] = $domainname; $domain['soarecord'] = $wgOpenStackManagerDNSOptions['servers']['primary'] . ' ' . $soa; $domain['associateddomain'] = $fqdn; if ( $location ) { $domain['l'] = $location; } $dn = 'dc=' . $domainname . ',' . $wgOpenStackManagerLDAPInstanceBaseDN; $success = LdapAuthenticationPlugin::ldap_add( $wgAuth->ldapconn, $dn, $domain ); if ( $success ) { $wgAuth->printDebug( "Successfully added domain $domainname", NONSENSITIVE ); return new OpenStackNovaDomain( $domainname ); } else { $wgAuth->printDebug( "Failed to add domain $domainname", NONSENSITIVE ); return null; } }
/** * Add the top-level entry for Service Groups to this project. * This is in a separate function so we can call it for old entries * for reverse-compatibility * * @param $projectname String * @return bool */ static function createServiceGroupOUs($projectname) { global $wgAuth; global $wgOpenStackManagerLDAPProjectBaseDN; // Create ou for service groups $groups = array(); $groups['objectclass'][] = 'organizationalunit'; $groups['ou'] = 'groups'; $groupsdn = 'ou=' . $groups['ou'] . ',' . 'cn=' . $projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $groupsdn, $groups); if (!$success) { $wgAuth->printDebug("Failed to create service group ou for project {$projectname}", NONSENSITIVE); return false; } // Create ou for service users $users = array(); $users['objectclass'][] = 'organizationalunit'; $users['ou'] = 'people'; $usersdn = 'ou=' . $users['ou'] . ',' . 'cn=' . $projectname . ',' . $wgOpenStackManagerLDAPProjectBaseDN; $success = LdapAuthenticationPlugin::ldap_add($wgAuth->ldapconn, $usersdn, $users); if (!$success) { $wgAuth->printDebug("Failed to create service user ou for project {$projectname}", NONSENSITIVE); return false; } return true; }