Issues (2882)

src/Security/DefaultAdminService.php (2 issues)

Severity
1
<?php
2
3
namespace SilverStripe\Security;
4
5
use BadMethodCallException;
6
use InvalidArgumentException;
7
use SilverStripe\Core\Config\Configurable;
8
use SilverStripe\Core\Environment;
9
use SilverStripe\Core\Extensible;
10
use SilverStripe\Core\Injector\Injectable;
11
12
/**
13
 * Provides access to the default admin
14
 */
15
class DefaultAdminService
16
{
17
    use Extensible;
18
    use Configurable;
19
    use Injectable;
20
21
    /**
22
     * Can be set to explicitly true or false, or left null.
23
     * If null, hasDefaultAdmin() will be inferred from environment.
24
     *
25
     * @var bool|null
26
     */
27
    protected static $has_default_admin = null;
28
29
    /**
30
     * @var string
31
     */
32
    protected static $default_username = null;
33
34
    /**
35
     * @var string
36
     */
37
    protected static $default_password = null;
38
39
    public function __construct()
40
    {
41
    }
42
43
    /**
44
     * Set the default admin credentials
45
     *
46
     * @param string $username
47
     * @param string $password
48
     */
49
    public static function setDefaultAdmin($username, $password)
50
    {
51
        // don't overwrite if already set
52
        if (static::hasDefaultAdmin()) {
53
            throw new BadMethodCallException(
54
                "Default admin already exists. Use clearDefaultAdmin() first."
55
            );
56
        }
57
58
        if (empty($username) || empty($password)) {
59
            throw new InvalidArgumentException("Default admin username / password cannot be empty");
60
        }
61
62
        static::$default_username = $username;
63
        static::$default_password = $password;
64
        static::$has_default_admin = true;
65
    }
66
67
    /**
68
     * @return string The default admin username
69
     * @throws BadMethodCallException Throws exception if there is no default admin
70
     */
71
    public static function getDefaultAdminUsername()
72
    {
73
        if (!static::hasDefaultAdmin()) {
74
            throw new BadMethodCallException(
75
                "No default admin configured. Please call hasDefaultAdmin() before getting default admin username"
76
            );
77
        }
78
        return static::$default_username ?: Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME');
79
    }
80
81
    /**
82
     * @return string The default admin password
83
     * @throws BadMethodCallException Throws exception if there is no default admin
84
     */
85
    public static function getDefaultAdminPassword()
86
    {
87
        if (!static::hasDefaultAdmin()) {
88
            throw new BadMethodCallException(
89
                "No default admin configured. Please call hasDefaultAdmin() before getting default admin password"
90
            );
91
        }
92
        return static::$default_password ?: Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD');
93
    }
94
95
    /**
96
     * Check if there is a default admin
97
     *
98
     * @return bool
99
     */
100
    public static function hasDefaultAdmin()
101
    {
102
        // Check environment if not explicitly set
103
        if (!isset(static::$has_default_admin)) {
104
            return !empty(Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME'))
105
                && !empty(Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD'));
106
        }
107
        return static::$has_default_admin;
108
    }
109
110
    /**
111
     * Flush the default admin credentials.
112
     */
113
    public static function clearDefaultAdmin()
114
    {
115
        static::$has_default_admin = false;
116
        static::$default_username = null;
117
        static::$default_password = null;
118
    }
119
120
    /**
121
     * @return Member|null
122
     */
123
    public function findOrCreateDefaultAdmin()
124
    {
125
        $this->extend('beforeFindOrCreateDefaultAdmin');
126
127
        // Check if we have default admins
128
        if (!static::hasDefaultAdmin()) {
129
            return null;
130
        }
131
132
        // Create admin with default admin username
133
        $admin = $this->findOrCreateAdmin(
134
            static::getDefaultAdminUsername(),
135
            _t(__CLASS__ . '.DefaultAdminFirstname', 'Default Admin')
136
        );
137
138
        $this->extend('afterFindOrCreateDefaultAdmin', $admin);
139
140
        return $admin;
141
    }
142
143
    /**
144
     * Find or create a Member with admin permissions
145
     *
146
     * @skipUpgrade
147
     * @param string $email
148
     * @param string $name
149
     * @return Member
150
     */
151
    public function findOrCreateAdmin($email, $name = null)
152
    {
153
        $this->extend('beforeFindOrCreateAdmin', $email, $name);
154
155
        // Find member
156
        /** @var Member $admin */
157
        $admin = Member::get()
158
            ->filter('Email', $email)
159
            ->first();
160
161
        // Find or create admin group
162
        $adminGroup = $this->findOrCreateAdminGroup();
163
164
        // If no admin is found, create one
165
        if ($admin) {
0 ignored issues
show
$admin is of type SilverStripe\Security\Member, thus it always evaluated to true.
Loading history...
166
            $inGroup = $admin->inGroup($adminGroup);
167
        } else {
168
            // Note: This user won't be able to login until a password is set
169
            // Set 'Email' to identify this as the default admin
170
            $inGroup = false;
171
            $admin = Member::create();
172
            $admin->FirstName = $name ?: $email;
173
            $admin->Email = $email;
174
            $admin->PasswordEncryption = 'none';
175
            $admin->write();
176
        }
177
178
        // Ensure this user is in an admin group
179
        if (!$inGroup) {
180
            // Add member to group instead of adding group to member
181
            // This bypasses the privilege escallation code in Member_GroupSet
182
            $adminGroup
183
                ->DirectMembers()
184
                ->add($admin);
185
        }
186
187
        $this->extend('afterFindOrCreateAdmin', $admin);
188
189
        return $admin;
190
    }
191
192
    /**
193
     * Ensure a Group exists with admin permission
194
     *
195
     * @return Group
196
     */
197
    protected function findOrCreateAdminGroup()
198
    {
199
        // Check pre-existing group
200
        $adminGroup = Permission::get_groups_by_permission('ADMIN')->first();
201
        if ($adminGroup) {
0 ignored issues
show
$adminGroup is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
202
            return $adminGroup;
203
        }
204
205
        // Check if default records create the group
206
        Group::singleton()->requireDefaultRecords();
207
        $adminGroup = Permission::get_groups_by_permission('ADMIN')->first();
208
        if ($adminGroup) {
209
            return $adminGroup;
210
        }
211
212
        // Create new admin group directly
213
        $adminGroup = Group::create();
214
        $adminGroup->Code = 'administrators';
215
        $adminGroup->Title = _t('SilverStripe\\Security\\Group.DefaultGroupTitleAdministrators', 'Administrators');
216
        $adminGroup->Sort = 0;
217
        $adminGroup->write();
218
        Permission::grant($adminGroup->ID, 'ADMIN');
219
        return $adminGroup;
220
    }
221
222
    /**
223
     * Check if the user is a default admin.
224
     * Returns false if there is no default admin.
225
     *
226
     * @param string $username
227
     * @return bool
228
     */
229
    public static function isDefaultAdmin($username)
230
    {
231
        return static::hasDefaultAdmin()
232
            && $username
233
            && $username === static::getDefaultAdminUsername();
234
    }
235
236
    /**
237
     * Check if the user credentials match the default admin.
238
     * Returns false if there is no default admin.
239
     *
240
     * @param string $username
241
     * @param string $password
242
     * @return bool
243
     */
244
    public static function isDefaultAdminCredentials($username, $password)
245
    {
246
        return static::isDefaultAdmin($username)
247
            && $password
248
            && $password === static::getDefaultAdminPassword();
249
    }
250
}
251