| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  | <?php namespace BookStack\Auth\Access; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use BookStack\Auth\Role; | 
					
						
							|  |  |  | use BookStack\Auth\User; | 
					
						
							| 
									
										
										
										
											2019-08-07 21:31:10 +08:00
										 |  |  | use Illuminate\Database\Eloquent\Builder; | 
					
						
							| 
									
										
										
										
											2020-07-07 00:14:43 +08:00
										 |  |  | use Illuminate\Support\Str; | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ExternalAuthService | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-07 00:14:43 +08:00
										 |  |  |     protected $registrationService; | 
					
						
							|  |  |  |     protected $user; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * ExternalAuthService base constructor. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function __construct(RegistrationService $registrationService, User $user) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $this->registrationService = $registrationService; | 
					
						
							|  |  |  |         $this->user = $user; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Get the user from the database for the specified details. | 
					
						
							|  |  |  |      * @throws UserRegistrationException | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function getOrRegisterUser(array $userDetails): ?User | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $user = $this->user->newQuery() | 
					
						
							|  |  |  |           ->where('external_auth_id', '=', $userDetails['external_id']) | 
					
						
							|  |  |  |           ->first(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (is_null($user)) { | 
					
						
							|  |  |  |             $userData = [ | 
					
						
							|  |  |  |                 'name' => $userDetails['name'], | 
					
						
							|  |  |  |                 'email' => $userDetails['email'], | 
					
						
							|  |  |  |                 'password' => Str::random(32), | 
					
						
							|  |  |  |                 'external_auth_id' => $userDetails['external_id'], | 
					
						
							|  |  |  |             ]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $user = $this->registrationService->registerUser($userData, null, false); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $user; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Check a role against an array of group names to see if it matches. | 
					
						
							|  |  |  |      * Checked against role 'external_auth_id' if set otherwise the name of the role. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2019-11-16 23:24:09 +08:00
										 |  |  |     protected function roleMatchesGroupNames(Role $role, array $groupNames): bool | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         if ($role->external_auth_id) { | 
					
						
							| 
									
										
										
										
											2019-11-16 23:24:09 +08:00
										 |  |  |             return $this->externalIdMatchesGroupNames($role->external_auth_id, $groupNames); | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $roleName = str_replace(' ', '-', trim(strtolower($role->display_name))); | 
					
						
							|  |  |  |         return in_array($roleName, $groupNames); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-16 23:24:09 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Check if the given external auth ID string matches one of the given group names. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function externalIdMatchesGroupNames(string $externalId, array $groupNames): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $externalAuthIds = explode(',', strtolower($externalId)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($externalAuthIds as $externalAuthId) { | 
					
						
							|  |  |  |             if (in_array(trim($externalAuthId), $groupNames)) { | 
					
						
							|  |  |  |                 return true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Match an array of group names to BookStack system roles. | 
					
						
							|  |  |  |      * Formats group names to be lower-case and hyphenated. | 
					
						
							|  |  |  |      * @param array $groupNames | 
					
						
							|  |  |  |      * @return \Illuminate\Support\Collection | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     protected function matchGroupsToSystemsRoles(array $groupNames) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         foreach ($groupNames as $i => $groupName) { | 
					
						
							|  |  |  |             $groupNames[$i] = str_replace(' ', '-', trim(strtolower($groupName))); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $roles = Role::query()->where(function (Builder $query) use ($groupNames) { | 
					
						
							|  |  |  |             $query->whereIn('name', $groupNames); | 
					
						
							|  |  |  |             foreach ($groupNames as $groupName) { | 
					
						
							|  |  |  |                 $query->orWhere('external_auth_id', 'LIKE', '%' . $groupName . '%'); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         })->get(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $matchedRoles = $roles->filter(function (Role $role) use ($groupNames) { | 
					
						
							|  |  |  |             return $this->roleMatchesGroupNames($role, $groupNames); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $matchedRoles->pluck('id'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Sync the groups to the user roles for the current user | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |     public function syncWithGroups(User $user, array $userGroups): void | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         // Get the ids for the roles from the names
 | 
					
						
							| 
									
										
										
										
											2019-08-07 21:31:10 +08:00
										 |  |  |         $groupsAsRoles = $this->matchGroupsToSystemsRoles($userGroups); | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         // Sync groups
 | 
					
						
							|  |  |  |         if ($this->config['remove_from_groups']) { | 
					
						
							| 
									
										
										
										
											2019-08-07 21:31:10 +08:00
										 |  |  |             $user->roles()->sync($groupsAsRoles); | 
					
						
							| 
									
										
										
										
											2020-02-03 01:31:00 +08:00
										 |  |  |             $user->attachDefaultRole(); | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  |         } else { | 
					
						
							| 
									
										
										
										
											2019-08-07 21:31:10 +08:00
										 |  |  |             $user->roles()->syncWithoutDetaching($groupsAsRoles); | 
					
						
							| 
									
										
										
										
											2019-08-07 18:07:21 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |