Commit fa0392b9 authored by Côme Bernigaud's avatar Côme Bernigaud Committed by Benoit Mortier
Browse files

Fixes #2919 Migrated stepMigrate to simplePlugin

Still to do:
add vars to the beginning of the class
check that migrations works
create admin role in top of admin user
add migration features for outsideUsers, outsideGroups and organizationalUnits
parent 9f04fbc6
......@@ -43,12 +43,6 @@ class Step_Checks extends setupStep
);
}
function __construct()
{
parent::__construct();
$this->update_strings();
}
function update_strings()
{
$this->s_title = _("Installation check");
......
......@@ -30,7 +30,7 @@ check_gosaAccounts - Check if there are users without the required obje
migrate_gosaAccounts - Migrate selected users to FusionDirectory user accounts.
check_organizationalUnits - Check if there are departments, that are not visible for FusionDirectory
migrate_organizationalUnits - Migrate selected departments
check_administrativeAccount - Check if there is at least one acl entry available
check_adminAccount - Check if there is at least one acl entry available
checkBase - Check if there is a root object available
get_user_list - Get list of available users
......@@ -44,79 +44,169 @@ array_to_ldif - Create ldif output of an ldap result array
****************/
class Step_Migrate extends setup_step
class CheckFailedException extends Exception
{
var $header_image = "geticon.php?context=applications&icon=utilities-system-monitor&size=48";
var $languages = array();
var $attributes = array('valid_admin');
var $checks = array();
private $error;
/* Department migration attributes */
var $dep_migration_dialog = FALSE;
var $deps_to_migrate = array();
var $show_details = FALSE;
public function __construct($msg, $error)
{
parent::__construct($msg);
$this->error = $error;
}
/* Department migration attributes */
var $users_migration_dialog = FALSE;
var $users_to_migrate = array();
public function getError()
{
return $this->error;
}
}
/* Create Acl attributes */
var $acl_create_dialog = FALSE;
var $acl_create_selected = ""; // Currently selected element, that should receive admin rights
var $acl_create_changes = ""; // Contains ldif information about changes
var $acl_create_confirmed = FALSE;
class StepMigrateDialog extends GenericDialog
{
protected $post_cancel = 'dialog_cancel';
protected $post_finish = 'dialog_confirm';
/* Checks initialised ? */
var $checks_initialised = FALSE;
private $infos;
private $tplfile;
private $check;
/* Users outside to people ou */
var $outside_users = array();
var $outside_users_dialog = FALSE;
public function __construct(&$check, $tpl, $infos)
{
$this->attribute = NULL;
$this->dialog = NULL;
$this->infos = $infos;
$this->tplfile = $tpl;
$this->check = $check;
}
/* Users outside to groups ou */
var $outside_groups = array();
var $outside_groups_dialog = FALSE;
public function dialog_execute()
{
if (
isset($_POST['dialog_showchanges']) ||
isset($_POST['dialog_hidechanges']) ||
isset($_POST['dialog_refresh'])) {
$this->infos = $this->check->dialog_refresh();
}
$smarty = get_smarty();
$smarty->assign('infos', $this->infos);
return $smarty->fetch(get_template_path($this->tplfile, TRUE, dirname(__FILE__)));
}
/* Device migration */
var $device_dialog = FALSE;
var $device = array();
function handle_finish ()
{
if ($this->check->migrate_confirm()) {
return FALSE;
} else {
return $this->dialog_execute();
}
}
/* Service migration */
var $service_dialog = FALSE;
var $service = array();
function handle_cancel ()
{
return FALSE;
}
}
/* Group menus */
var $menu_dialog = FALSE;
var $menu = array();
class StepMigrateCheck
{
public $name;
public $title;
public $status = FALSE;
public $msg = '';
public $error = '';
public $fnc;
private $step;
public function __construct($step, $name, $title)
{
$this->name = $name;
$this->title = $title;
$this->fnc = 'check_'.$name;
$this->step = $step;
}
/* check for multiple use of same uidNumber */
var $check_uidNumbers = array();
var $check_uidNumbers_dialog = FALSE;
public function run($fnc = NULL)
{
if ($fnc === NULL) {
$fnc = $this->fnc;
}
try {
$this->msg = _('Ok');
$this->error = $this->step->$fnc($this);
$this->status = TRUE;
} catch (CheckFailedException $e) {
$this->status = FALSE;
$this->msg = $e->getMessage();
$this->error = $e->getError();
}
}
/* check for multiple use of same gidNumber */
var $check_gidNumbers = array();
var $check_gidNumbers_dialog = FALSE;
public function save_object()
{
if (isset($_POST[$this->name.'_create'])) {
$fnc = $this->fnc.'_create';
$this->step->$fnc($this);
} elseif (isset($_POST[$this->name.'_migrate'])) {
$fnc = $this->fnc.'_migrate';
$this->step->$fnc($this);
}
}
var $group_list = array();
public function submit ($value = NULL, $id = 'migrate')
{
if ($value === NULL) {
$value = _('Migrate');
}
return '<input type="submit" name="'.$this->name.'_'.$id.'" value="'.$value.'"/>';
}
/* Migrable users */
var $migrate_users = array();
var $acl_migrate_dialog = FALSE;
var $migrate_acl_base_entry = "";
public function migrate_confirm()
{
$fnc = $this->fnc.'_migrate'.'_confirm';
$res = $this->step->$fnc($this);
if ($res) {
$this->run();
}
return $res;
/* TODO rerun depending tests? (done by hand for now) */
}
public function dialog_refresh()
{
$fnc = $this->fnc.'_migrate'.'_refresh';
return $this->step->$fnc($this);
}
}
class Step_Migrate extends setupStep
{
var $header_image = "geticon.php?context=applications&icon=utilities-system-monitor&size=48";
/* Root object classes */
var $rootOC_migrate_dialog = FALSE;
var $rootOC_details = array();
/* One valid admin dn */
var $valid_admin = FALSE;
/* Invisible users */
var $users_to_migrate = array();
/* Defaults ACL roles */
var $defaultRoles;
static function getAttributesInfo()
{
return array(
'checks' => array(
'class' => array('fullwidth'),
'name' => _('PHP module and extension checks'),
'template' => get_template_path("setup_migrate.tpl", TRUE, dirname(__FILE__)),
'attrs' => array(
new FakeAttribute('checks')
)
),
);
}
function __construct()
{
$this->update_strings();
parent::__construct();
$this->fill_defaultRoles();
}
......@@ -153,339 +243,266 @@ class Step_Migrate extends setup_step
function initialize_checks()
{
$this->checks = array();
$this->checks['root']['TITLE'] = _("Checking for root object");
$this->checks['root']['STATUS'] = FALSE;
$this->checks['root']['STATUS_MSG'] = "";
$this->checks['root']['ERROR_MSG'] = "";
$this->checkBase();
$this->checks['rootOC']['TITLE'] = _("Inspecting object classes in root object");
$this->checks['rootOC']['STATUS'] = FALSE;
$this->checks['rootOC']['STATUS_MSG'] = "";
$this->checks['rootOC']['ERROR_MSG'] = "";
$this->checkBaseOC();
$this->checks['permissions']['TITLE'] = _("Checking permission for LDAP database");
$this->checks['permissions']['STATUS'] = FALSE;
$this->checks['permissions']['STATUS_MSG'] = "";
$this->checks['permissions']['ERROR_MSG'] = "";
$this->check_ldap_permissions();
$this->checks['deps_visible']['TITLE'] = _("Checking for invisible departments");
$this->checks['deps_visible']['STATUS'] = FALSE;
$this->checks['deps_visible']['STATUS_MSG'] = "";
$this->checks['deps_visible']['ERROR_MSG'] = "";
$this->checks['users_visible']['TITLE'] = _("Checking for invisible users");
$this->checks['users_visible']['STATUS'] = FALSE;
$this->checks['users_visible']['STATUS_MSG'] = "";
$this->checks['users_visible']['ERROR_MSG'] = "";
$this->check_gosaAccounts();
$this->migrate_users = array();
$this->checks['acls']['TITLE'] = _("Checking for super administrator");
$this->checks['acls']['STATUS'] = FALSE;
$this->checks['acls']['STATUS_MSG'] = "";
$this->checks['acls']['ERROR_MSG'] = "";
$this->check_administrativeAccount();
$this->checks['default_acls']['TITLE'] = _("Checking for default ACL roles and groupes");
$this->checks['default_acls']['STATUS'] = FALSE;
$this->checks['default_acls']['STATUS_MSG'] = "";
$this->checks['default_acls']['ERROR_MSG'] = "";
$this->check_defaultACLs();
$this->checks['outside_users']['TITLE'] = _("Checking for users outside the people tree");
$this->checks['outside_users']['STATUS'] = FALSE;
$this->checks['outside_users']['STATUS_MSG'] = "";
$this->checks['outside_users']['ERROR_MSG'] = "";
$this->search_outside_users();
$this->checks['outside_groups']['TITLE'] = _("Checking for groups outside the groups tree");
$this->checks['outside_groups']['STATUS'] = FALSE;
$this->checks['outside_groups']['STATUS_MSG'] = "";
$this->checks['outside_groups']['ERROR_MSG'] = "";
$this->search_outside_groups();
$this->check_organizationalUnits();
$this->checks['uidNumber_usage']['TITLE'] = _("Checking for duplicated UID numbers");
$this->checks['uidNumber_usage']['STATUS'] = FALSE;
$this->checks['uidNumber_usage']['STATUS_MSG'] = "";
$this->checks['uidNumber_usage']['ERROR_MSG'] = "";
$this->check_uidNumber();
$this->checks['gidNumber_usage']['TITLE'] = _("Checking for duplicate GID numbers");
$this->checks['gidNumber_usage']['STATUS'] = FALSE;
$this->checks['gidNumber_usage']['STATUS_MSG'] = "";
$this->checks['gidNumber_usage']['ERROR_MSG'] = "";
$this->check_gidNumber();
$this->checks['old_style_devices']['TITLE'] = _("Checking for old style USB devices");
$this->checks['old_style_devices']['STATUS'] = FALSE;
$this->checks['old_style_devices']['STATUS_MSG'] = "";
$this->checks['old_style_devices']['ERROR_MSG'] = "";
$this->check_usb_devices();
$this->checks['old_style_services']['TITLE'] = _("Checking for old services that have to be migrated");
$this->checks['old_style_services']['STATUS'] = FALSE;
$this->checks['old_style_services']['STATUS_MSG'] = "";
$this->checks['old_style_services']['ERROR_MSG'] = "";
$this->check_services();
$this->checks['old_style_menus']['TITLE'] = _("Checking for old style application menus");
$this->checks['old_style_menus']['STATUS'] = FALSE;
$this->checks['old_style_menus']['STATUS_MSG'] = "";
$this->checks['old_style_menus']['ERROR_MSG'] = "";
$this->check_menus();
$checks = array(
'base' => new StepMigrateCheck($this, 'base', _('Checking for root object')),
'baseOC' => new StepMigrateCheck($this, 'baseOC', _('Inspecting object classes in root object')),
'permissions' => new StepMigrateCheck($this, 'permissions', _('Checking permission for LDAP database')),
'gosaAccounts' => new StepMigrateCheck($this, 'gosaAccounts', _('Checking for invisible users')),
'adminAccount' => new StepMigrateCheck($this, 'adminAccount', _('Checking for super administrator')),
'defaultACLs' => new StepMigrateCheck($this, 'defaultACLs', _('Checking for default ACL roles and groups')),
'outsideUsers' => new StepMigrateCheck($this, 'outsideUsers', _('Checking for users outside the people tree')),
'outsideGroups' => new StepMigrateCheck($this, 'outsideGroups', _('Checking for groups outside the groups tree')),
'organizationalUnits' => new StepMigrateCheck($this, 'organizationalUnits', _('Checking for invisible departments')),
'uidNumber' => new StepMigrateCheck($this, 'uidNumber', _('Checking for duplicated UID numbers')),
'gidNumber' => new StepMigrateCheck($this, 'gidNumber', _('Checking for duplicate GID numbers')),
);
$this->checks = $checks;
}
function execute()
{
if (empty($this->checks) || isset($_POST['reload'])) {
$this->initialize_checks();
foreach ($this->checks as &$check) {
$check->run();
}
unset($check);
}
return parent::execute();
}
/* Check if there are uidNumbers which are used more than once */
function check_uidNumber()
function save_object()
{
parent::save_object();
foreach ($this->checks as &$check) {
$check->save_object();
}
unset($check);
}
/* Check if the root object exists.
* If the parameter just_check is TRUE, then just check if the
* root object is missing and update the info messages.
* If the Parameter is FALSE, try to create a new root object.
*/
function check_base(&$checkobj)
{
global $config;
$ldap = $config->get_ldap_link();
/* Check if root object exists */
$ldap->cd($config->current['BASE']);
$res = $ldap->search("(&(objectClass=posixAccount)(uidNumber=*))", array("dn","uidNumber"));
if (!$res) {
$this->checks['uidNumber_usage']['STATUS'] = FALSE;
$this->checks['uidNumber_usage']['STATUS_MSG'] = _("LDAP query failed");
$this->checks['uidNumber_usage']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
return FALSE;
}
$ldap->set_size_limit(1);
$res = $ldap->search("(objectClass=*)");
$ldap->set_size_limit(0);
$err = ldap_errno($ldap->cid);
$this->check_uidNumbers = array();
$tmp = array();
while ($attrs = $ldap->fetch()) {
$tmp[$attrs['uidNumber'][0]][] = $attrs;
}
if ( !$res ||
$err == 0x20 || // LDAP_NO_SUCH_OBJECT
$err == 0x40) { // LDAP_NAMING_VIOLATION
foreach ($tmp as $entries) {
if (count($entries) > 1) {
foreach ($entries as $entry) {
$this->check_uidNumbers[base64_encode($entry['dn'])] = $entry;
}
}
/* Root object doesn't exists */
throw new CheckFailedException(
_('Failed'),
_('The LDAP root object is missing. It is required to use your LDAP service.').'&nbsp;'.
$checkobj->submit(_('Try to create root object'), 'create')
);
}
if ($this->check_uidNumbers) {
$this->checks['uidNumber_usage']['STATUS'] = FALSE;
$this->checks['uidNumber_usage']['STATUS_MSG'] = "<div style='color:#F0A500'>"._("Warning")."</div>";
$this->checks['uidNumber_usage']['ERROR_MSG'] =
sprintf(_("Found %s duplicate values for attribute 'uidNumber'."), count($this->check_uidNumbers));
return FALSE;
} else {
$this->checks['uidNumber_usage']['STATUS'] = TRUE;
$this->checks['uidNumber_usage']['STATUS_MSG'] = _("Ok");
$this->checks['uidNumber_usage']['ERROR_MSG'] = "";
return TRUE;
}
/* Root object exists */
return '';
}
function check_base_create (&$check)
{
global $config;
$ldap = $config->get_ldap_link();
/* Check if there are duplicated gidNumbers present in ldap */
function check_gidNumber()
/* Add root object */
$ldap->cd($config->current['BASE']);
$ldap->create_missing_trees($config->current['BASE']);
/* Re-run test */
$checkobj->run();
}
/* Check if the root object includes the required object classes, e.g. gosaDepartment is required for ACLs.
* If the parameter just_check is TRUE, then just check for the OCs.
* If the Parameter is FALSE, try to add the required object classes.
*/
function check_baseOC(&$checkobj)
{
global $config;
$ldap = $config->get_ldap_link();
/* Check if root object exists */
$ldap->cd($config->current['BASE']);
$res = $ldap->search("(&(objectClass=posixGroup)(gidNumber=*))", array("dn","gidNumber"));
if (!$res) {
$this->checks['gidNumber_usage']['STATUS'] = FALSE;
$this->checks['gidNumber_usage']['STATUS_MSG'] = _("LDAP query failed");
$this->checks['gidNumber_usage']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
return FALSE;
$ldap->cat($config->current['BASE']);
if (!$ldap->count()) {
throw new CheckFailedException(
_('LDAP query failed'),
_('Possibly the "root object" is missing.')
);
}
$this->check_gidNumbers = array();
$tmp = array();
while ($attrs = $ldap->fetch()) {
$tmp[$attrs['gidNumber'][0]][] = $attrs;
}
$attrs = $ldap->fetch();
foreach ($tmp as $entries) {
if (count($entries) > 1) {
foreach ($entries as $entry) {
$this->check_gidNumbers[base64_encode($entry['dn'])] = $entry;
/* Root object doesn't exists */
if (!in_array("gosaDepartment", $attrs['objectClass'])) {
$this->rootOC_details = array();
$mods = array();
/* Get list of possible container objects, to be able to detect naming
* attributes and missing attribute types.
*/
if (!class_available("departmentManagement")) {
throw new CheckFailedException(
_("Failed"),
sprintf(_("Missing FusionDirectory object class '%s'!"), "departmentManagement").
"&nbsp;"._("Please check your installation.")
);
}
/* Try to detect base class type, e.g. is it a dcObject */
$dep_types = departmentManagement::getDepartmentTypes();
$dep_type = "";
$attrs['objectClass'][] = 'gosaDepartment'; // This allow us to filter it as if it was already migrated
foreach ($dep_types as $type) {
if (objects::isOfType($attrs, $type)) {
$dep_type = $type;
break;
}
}
}
$key = array_search('gosaDepartment', $attrs['objectClass']);
unset($attrs['objectClass'][$key]);
if ($this->check_gidNumbers) {
$this->checks['gidNumber_usage']['STATUS'] = FALSE;
$this->checks['gidNumber_usage']['STATUS_MSG'] = "<div style='color:#F0A500'>"._("Warning")."</div>";
$this->checks['gidNumber_usage']['ERROR_MSG'] =
sprintf(_("Found %s duplicate values for attribute 'gidNumber'."), count($this->check_gidNumbers));
return FALSE;
} else {
$this->checks['gidNumber_usage']['STATUS'] = TRUE;
$this->checks['gidNumber_usage']['STATUS_MSG'] = _("Ok");
$this->checks['gidNumber_usage']['ERROR_MSG'] = "";
return TRUE;
}
}
/* If no known base class was detect, abort with message */
if (empty($dep_type)) {
throw new CheckFailedException(
_("Failed"),
sprintf(_("Cannot handle the structural object type of your root object. Please try to add the object class '%s' manually."), "gosaDepartment")
);
}
$dep_infos = objects::infos($dep_type);
/* Search for groups outside the group ou */
function search_outside_groups()
{
global $config;
$ldap = $config->get_ldap_link();
/* Create 'current' and 'target' object properties, to be able to display
* a set of modifications required to create a valid FusionDirectory department.
*/
$str = "dn: ".$config->current['BASE']."\n";
for ($i = 0; $i < $attrs['objectClass']['count']; $i++) {
$str .= "objectClass: ".$attrs['objectClass'][$i]."\n";
}
$this->rootOC_details['current'] = $str;
$group_ou = get_ou('groupRDN');
$ldap->cd($config->current['BASE']);
/* Create target infos */
$str = "dn: ".$config->current['BASE']."\n";
for ($i = 0; $i < $attrs['objectClass']['count']; $i++) {
$str .= "objectClass: ".$attrs['objectClass'][$i]."\n";
$mods['objectClass'][] = $attrs['objectClass'][$i];
}
$mods['objectClass'][] = "gosaDepartment";
/***********
* Get all gosaDepartments to be able to
* validate correct ldap tree position of every single user
***********/
$valid_deps = array();
$valid_deps['/'] = $config->current['BASE'];
$ldap->search("(&(objectClass=gosaDepartment)(ou=*))", array("dn","ou"));
while ($attrs = $ldap->fetch()) {
$valid_deps[] = $attrs['dn'];
}
$str .= "<b>objectClass: gosaDepartment</b>\n";
/***********
* Get all groups
***********/
$res = $ldap->search("(objectClass=posixGroup)", array("dn"));
if (!$res) {
$this->checks['outside_groups']['STATUS'] = FALSE;
$this->checks['outside_groups']['STATUS_MSG'] = _("LDAP query failed");
$this->checks['outside_groups']['ERROR_MSG'] = _("Possibly the 'root object' is missing.");
return FALSE;
}
/* Append attribute 'ou', it is required by gosaDepartment */
if (!isset($attrs['ou'])) {
$val = "GOsa";
if (isset($attrs[$dep_infos['mainAttr']][0])) {
$val = $attrs[$dep_infos['mainAttr']][0];
}
$str .= "<b>ou: ".$val."</b>\n";
$this->outside_groups = array();
$this->groups_list = array();;
while ($attrs = $ldap->fetch()) {
$group_db_base = preg_replace("/^[^,]+,".preg_quote($group_ou, '/')."/i", "", $attrs['dn']);
$mods['ou'] = $val;
}