mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
251 lines
7.0 KiB
PHP
251 lines
7.0 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Security;
|
|
|
|
use BadMethodCallException;
|
|
use InvalidArgumentException;
|
|
use SilverStripe\Core\Config\Configurable;
|
|
use SilverStripe\Core\Environment;
|
|
use SilverStripe\Core\Extensible;
|
|
use SilverStripe\Core\Injector\Injectable;
|
|
|
|
/**
|
|
* Provides access to the default admin
|
|
*/
|
|
class DefaultAdminService
|
|
{
|
|
use Extensible;
|
|
use Configurable;
|
|
use Injectable;
|
|
|
|
/**
|
|
* Can be set to explicitly true or false, or left null.
|
|
* If null, hasDefaultAdmin() will be inferred from environment.
|
|
*
|
|
* @var bool|null
|
|
*/
|
|
protected static $has_default_admin = null;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected static $default_username = null;
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected static $default_password = null;
|
|
|
|
public function __construct()
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Set the default admin credentials
|
|
*
|
|
* @param string $username
|
|
* @param string $password
|
|
*/
|
|
public static function setDefaultAdmin($username, $password)
|
|
{
|
|
// don't overwrite if already set
|
|
if (static::hasDefaultAdmin()) {
|
|
throw new BadMethodCallException(
|
|
"Default admin already exists. Use clearDefaultAdmin() first."
|
|
);
|
|
}
|
|
|
|
if (empty($username) || empty($password)) {
|
|
throw new InvalidArgumentException("Default admin username / password cannot be empty");
|
|
}
|
|
|
|
static::$default_username = $username;
|
|
static::$default_password = $password;
|
|
static::$has_default_admin = true;
|
|
}
|
|
|
|
/**
|
|
* @return string The default admin username
|
|
* @throws BadMethodCallException Throws exception if there is no default admin
|
|
*/
|
|
public static function getDefaultAdminUsername()
|
|
{
|
|
if (!static::hasDefaultAdmin()) {
|
|
throw new BadMethodCallException(
|
|
"No default admin configured. Please call hasDefaultAdmin() before getting default admin username"
|
|
);
|
|
}
|
|
return static::$default_username ?: Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME');
|
|
}
|
|
|
|
/**
|
|
* @return string The default admin password
|
|
* @throws BadMethodCallException Throws exception if there is no default admin
|
|
*/
|
|
public static function getDefaultAdminPassword()
|
|
{
|
|
if (!static::hasDefaultAdmin()) {
|
|
throw new BadMethodCallException(
|
|
"No default admin configured. Please call hasDefaultAdmin() before getting default admin password"
|
|
);
|
|
}
|
|
return static::$default_password ?: Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD');
|
|
}
|
|
|
|
/**
|
|
* Check if there is a default admin
|
|
*
|
|
* @return bool
|
|
*/
|
|
public static function hasDefaultAdmin()
|
|
{
|
|
// Check environment if not explicitly set
|
|
if (!isset(static::$has_default_admin)) {
|
|
return !empty(Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME'))
|
|
&& !empty(Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD'));
|
|
}
|
|
return static::$has_default_admin;
|
|
}
|
|
|
|
/**
|
|
* Flush the default admin credentials.
|
|
*/
|
|
public static function clearDefaultAdmin()
|
|
{
|
|
static::$has_default_admin = false;
|
|
static::$default_username = null;
|
|
static::$default_password = null;
|
|
}
|
|
|
|
/**
|
|
* @return Member|null
|
|
*/
|
|
public function findOrCreateDefaultAdmin()
|
|
{
|
|
$this->extend('beforeFindOrCreateDefaultAdmin');
|
|
|
|
// Check if we have default admins
|
|
if (!static::hasDefaultAdmin()) {
|
|
return null;
|
|
}
|
|
|
|
// Create admin with default admin username
|
|
$admin = $this->findOrCreateAdmin(
|
|
static::getDefaultAdminUsername(),
|
|
_t(__CLASS__ . '.DefaultAdminFirstname', 'Default Admin')
|
|
);
|
|
|
|
$this->extend('afterFindOrCreateDefaultAdmin', $admin);
|
|
|
|
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
|
|
/** @var Member $admin */
|
|
$admin = Member::get()
|
|
->filter('Email', $email)
|
|
->first();
|
|
|
|
// Find or create admin group
|
|
$adminGroup = $this->findOrCreateAdminGroup();
|
|
|
|
// If no admin is found, create one
|
|
if ($admin) {
|
|
$inGroup = $admin->inGroup($adminGroup);
|
|
} else {
|
|
// Note: This user won't be able to login until a password is set
|
|
// Set 'Email' to identify this as the default admin
|
|
$inGroup = false;
|
|
$admin = Member::create();
|
|
$admin->FirstName = $name ?: $email;
|
|
$admin->Email = $email;
|
|
$admin->PasswordEncryption = 'none';
|
|
$admin->write();
|
|
}
|
|
|
|
// Ensure this user is in an admin group
|
|
if (!$inGroup) {
|
|
// Add member to group instead of adding group to member
|
|
// This bypasses the privilege escallation code in Member_GroupSet
|
|
$adminGroup
|
|
->DirectMembers()
|
|
->add($admin);
|
|
}
|
|
|
|
$this->extend('afterFindOrCreateAdmin', $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.
|
|
* Returns false if there is no default admin.
|
|
*
|
|
* @param string $username
|
|
* @return bool
|
|
*/
|
|
public static function isDefaultAdmin($username)
|
|
{
|
|
return static::hasDefaultAdmin()
|
|
&& $username
|
|
&& $username === static::getDefaultAdminUsername();
|
|
}
|
|
|
|
/**
|
|
* Check if the user credentials match the default admin.
|
|
* Returns false if there is no default admin.
|
|
*
|
|
* @param string $username
|
|
* @param string $password
|
|
* @return bool
|
|
*/
|
|
public static function isDefaultAdminCredentials($username, $password)
|
|
{
|
|
return static::isDefaultAdmin($username)
|
|
&& $password
|
|
&& $password === static::getDefaultAdminPassword();
|
|
}
|
|
}
|