Merge pull request #7136 from open-sausages/pulls/4.0/fix-installer-create-admin

BUG Ensure that installer can create an initial admin account
This commit is contained in:
Chris Joe 2017-07-07 09:15:41 +12:00 committed by GitHub
commit 0b09a510f4
3 changed files with 93 additions and 24 deletions

View File

@ -4,11 +4,10 @@ namespace SilverStripe\Dev\Install;
use Exception; use Exception;
use SilverStripe\Control\Cookie; use SilverStripe\Control\Cookie;
use SilverStripe\Control\HTTPApplication;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPRequestBuilder; use SilverStripe\Control\HTTPRequestBuilder;
use SilverStripe\Control\Session;
use SilverStripe\Core\CoreKernel; use SilverStripe\Core\CoreKernel;
use SilverStripe\Control\HTTPApplication;
use SilverStripe\Core\Kernel; use SilverStripe\Core\Kernel;
use SilverStripe\Core\Startup\ParameterConfirmationToken; use SilverStripe\Core\Startup\ParameterConfirmationToken;
use SilverStripe\ORM\DatabaseAdmin; use SilverStripe\ORM\DatabaseAdmin;
@ -229,9 +228,15 @@ PHP
// Create default administrator user and group in database // Create default administrator user and group in database
// (not using Security::setDefaultAdmin()) // (not using Security::setDefaultAdmin())
$adminMember = DefaultAdminService::singleton()->findOrCreateDefaultAdmin(); $username = $config['admin']['username'];
$adminMember->Email = $config['admin']['username']; $password = $config['admin']['password'];
$adminMember->Password = $config['admin']['password']; $adminMember = DefaultAdminService::singleton()
->findOrCreateAdmin(
$username,
_t(DefaultAdminService::class . '.DefaultAdminFirstname', 'Default Admin')
);
$adminMember->Email = $username;
$adminMember->Password = $password;
$adminMember->PasswordEncryption = Security::config()->get('encryption_algorithm'); $adminMember->PasswordEncryption = Security::config()->get('encryption_algorithm');
try { try {
@ -243,8 +248,8 @@ PHP
); );
} }
$request->getSession()->set('username', $config['admin']['username']); $request->getSession()->set('username', $username);
$request->getSession()->set('password', $config['admin']['password']); $request->getSession()->set('password', $password);
$request->getSession()->save($request); $request->getSession()->save($request);
}, true); }, true);

View File

@ -129,33 +129,53 @@ class DefaultAdminService
return null; return null;
} }
// Find or create ADMIN group // Create admin with default admin username
Group::singleton()->requireDefaultRecords(); $admin = $this->findOrCreateAdmin(
$adminGroup = Permission::get_groups_by_permission('ADMIN')->first(); static::getDefaultAdminUsername(),
_t(__CLASS__ . '.DefaultAdminFirstname', 'Default Admin')
);
if (!$adminGroup) { $this->extend('afterFindOrCreateDefaultAdmin', $admin);
Group::singleton()->requireDefaultRecords();
$adminGroup = Permission::get_groups_by_permission('ADMIN')->first(); return $admin;
} }
/**
* Find or create a Member with admin permissions
*
* @skipUpgrade
* @param string $email
* @param string $name
* @return Member
*/
public function findOrCreateAdmin($email, $name = null)
{
$this->extend('beforeFindOrCreateAdmin', $email, $name);
// Find member // Find member
/** @skipUpgrade */ /** @var Member $admin */
$admin = Member::get() $admin = Member::get()
->filter('Email', static::getDefaultAdminUsername()) ->filter('Email', $email)
->first(); ->first();
// Find or create admin group
$adminGroup = $this->findOrCreateAdminGroup();
// If no admin is found, create one // If no admin is found, create one
if (!$admin) { if ($admin) {
// 'Password' is not set to avoid creating $inGroup = $admin->inGroup($adminGroup);
// persistent logins in the database. See Security::setDefaultAdmin(). } else {
// Note: This user won't be able to login until a password is set
// Set 'Email' to identify this as the default admin // Set 'Email' to identify this as the default admin
$inGroup = false;
$admin = Member::create(); $admin = Member::create();
$admin->FirstName = _t(__CLASS__ . '.DefaultAdminFirstname', 'Default Admin'); $admin->FirstName = $name ?: $email;
$admin->Email = static::getDefaultAdminUsername(); $admin->Email = $email;
$admin->write(); $admin->write();
} }
// Ensure this user is in the admin group // Ensure this user is in an admin group
if (!$admin->inGroup($adminGroup)) { if (!$inGroup) {
// Add member to group instead of adding group to member // Add member to group instead of adding group to member
// This bypasses the privilege escallation code in Member_GroupSet // This bypasses the privilege escallation code in Member_GroupSet
$adminGroup $adminGroup
@ -163,11 +183,41 @@ class DefaultAdminService
->add($admin); ->add($admin);
} }
$this->extend('afterFindOrCreateDefaultAdmin', $admin); $this->extend('afterFindOrCreateAdmin', $admin);
return $admin; return $admin;
} }
/**
* Ensure a Group exists with admin permission
*
* @return Group
*/
protected function findOrCreateAdminGroup()
{
// Check pre-existing group
$adminGroup = Permission::get_groups_by_permission('ADMIN')->first();
if ($adminGroup) {
return $adminGroup;
}
// Check if default records create the group
Group::singleton()->requireDefaultRecords();
$adminGroup = Permission::get_groups_by_permission('ADMIN')->first();
if ($adminGroup) {
return $adminGroup;
}
// Create new admin group directly
$adminGroup = Group::create();
$adminGroup->Code = 'administrators';
$adminGroup->Title = _t('SilverStripe\\Security\\Group.DefaultGroupTitleAdministrators', 'Administrators');
$adminGroup->Sort = 0;
$adminGroup->write();
Permission::grant($adminGroup->ID, 'ADMIN');
return $adminGroup;
}
/** /**
* Check if the user is a default admin. * Check if the user is a default admin.
* Returns false if there is no default admin. * Returns false if there is no default admin.

View File

@ -79,6 +79,20 @@ class SecurityDefaultAdminTest extends SapphireTest
$this->assertNull($admin->Password); $this->assertNull($admin->Password);
} }
public function testFindOrCreateAdmin()
{
$adminMembers = Permission::get_members_by_permission('ADMIN');
$this->assertEquals(0, $adminMembers->count());
$admin = DefaultAdminService::singleton()->findOrCreateAdmin('newadmin@example.com', 'Admin Name');
$this->assertInstanceOf(Member::class, $admin);
$this->assertTrue(Permission::checkMember($admin, 'ADMIN'));
$this->assertEquals('newadmin@example.com', $admin->Email);
$this->assertEquals('Admin Name', $admin->FirstName);
$this->assertNull($admin->Password);
}
public function testFindAnAdministratorWithoutDefaultAdmin() public function testFindAnAdministratorWithoutDefaultAdmin()
{ {
// Clear default admin // Clear default admin