]> BookStack Code Mirror - bookstack/blob - app/Auth/Access/ExternalAuthService.php
Default OpenID display name set to standard value
[bookstack] / app / Auth / Access / ExternalAuthService.php
1 <?php namespace BookStack\Auth\Access;
2
3 use BookStack\Auth\Role;
4 use BookStack\Auth\User;
5 use Illuminate\Database\Eloquent\Builder;
6 use Illuminate\Support\Str;
7
8 class ExternalAuthService
9 {
10     protected $registrationService;
11     protected $user;
12
13     /**
14      * ExternalAuthService base constructor.
15      */
16     public function __construct(RegistrationService $registrationService, User $user)
17     {
18         $this->registrationService = $registrationService;
19         $this->user = $user;
20     }
21     
22     /**
23      * Get the user from the database for the specified details.
24      * @throws UserRegistrationException
25      */
26     protected function getOrRegisterUser(array $userDetails): ?User
27     {
28         $user = $this->user->newQuery()
29           ->where('external_auth_id', '=', $userDetails['external_id'])
30           ->first();
31
32         if (is_null($user)) {
33             $userData = [
34                 'name' => $userDetails['name'],
35                 'email' => $userDetails['email'],
36                 'password' => Str::random(32),
37                 'external_auth_id' => $userDetails['external_id'],
38             ];
39
40             $user = $this->registrationService->registerUser($userData, null, false);
41         }
42
43         return $user;
44     }
45
46     /**
47      * Check a role against an array of group names to see if it matches.
48      * Checked against role 'external_auth_id' if set otherwise the name of the role.
49      */
50     protected function roleMatchesGroupNames(Role $role, array $groupNames): bool
51     {
52         if ($role->external_auth_id) {
53             return $this->externalIdMatchesGroupNames($role->external_auth_id, $groupNames);
54         }
55
56         $roleName = str_replace(' ', '-', trim(strtolower($role->display_name)));
57         return in_array($roleName, $groupNames);
58     }
59
60     /**
61      * Check if the given external auth ID string matches one of the given group names.
62      */
63     protected function externalIdMatchesGroupNames(string $externalId, array $groupNames): bool
64     {
65         $externalAuthIds = explode(',', strtolower($externalId));
66
67         foreach ($externalAuthIds as $externalAuthId) {
68             if (in_array(trim($externalAuthId), $groupNames)) {
69                 return true;
70             }
71         }
72
73         return false;
74     }
75
76     /**
77      * Match an array of group names to BookStack system roles.
78      * Formats group names to be lower-case and hyphenated.
79      * @param array $groupNames
80      * @return \Illuminate\Support\Collection
81      */
82     protected function matchGroupsToSystemsRoles(array $groupNames)
83     {
84         foreach ($groupNames as $i => $groupName) {
85             $groupNames[$i] = str_replace(' ', '-', trim(strtolower($groupName)));
86         }
87
88         $roles = Role::query()->where(function (Builder $query) use ($groupNames) {
89             $query->whereIn('name', $groupNames);
90             foreach ($groupNames as $groupName) {
91                 $query->orWhere('external_auth_id', 'LIKE', '%' . $groupName . '%');
92             }
93         })->get();
94
95         $matchedRoles = $roles->filter(function (Role $role) use ($groupNames) {
96             return $this->roleMatchesGroupNames($role, $groupNames);
97         });
98
99         return $matchedRoles->pluck('id');
100     }
101
102     /**
103      * Sync the groups to the user roles for the current user
104      */
105     public function syncWithGroups(User $user, array $userGroups): void
106     {
107         // Get the ids for the roles from the names
108         $groupsAsRoles = $this->matchGroupsToSystemsRoles($userGroups);
109
110         // Sync groups
111         if ($this->config['remove_from_groups']) {
112             $user->roles()->sync($groupsAsRoles);
113             $user->attachDefaultRole();
114         } else {
115             $user->roles()->syncWithoutDetaching($groupsAsRoles);
116         }
117     }
118 }