diff --git a/src/Http/Controllers/OAuthController.php b/src/Http/Controllers/OAuthController.php index dbc25bec9a6..2759da95b39 100644 --- a/src/Http/Controllers/OAuthController.php +++ b/src/Http/Controllers/OAuthController.php @@ -13,6 +13,7 @@ use Statamic\Facades\OAuth; use Statamic\Facades\TwoFactor; use Statamic\Facades\URL; +use Statamic\Facades\User; use Statamic\Support\Str; use function Statamic\trans as __; @@ -83,7 +84,7 @@ public function handleProviderCallback(Request $request, string $provider) } if (Auth::guard($guard)->check()) { - return $this->connectProvider($oauth, $providerUser, Auth::guard($guard)->user()); + return $this->connectProvider($oauth, $providerUser, User::fromUser(Auth::guard($guard)->user())); } if ($user = $oauth->findUser($providerUser)) { @@ -127,7 +128,7 @@ public function disconnect(Request $request, string $provider) throw new NotFoundHttpException(); } - $oauth->forgetUser($request->user()); + $oauth->forgetUser(User::fromUser($request->user())); if ($request->wantsJson()) { return new JsonResponse([], 204); @@ -148,7 +149,7 @@ protected function connectProvider($oauth, $providerUser, $user) $existingUserId = $oauth->getUserId($providerUser->getId()); - if ($existingUserId === $user->id()) { + if ($existingUserId === (string) $user->id()) { return redirect() ->to($this->successRedirectUrl()) ->with('success', __('statamic::messages.oauth_already_connected', ['provider' => $oauth->label()])); diff --git a/tests/OAuth/EloquentOAuthTest.php b/tests/OAuth/EloquentOAuthTest.php new file mode 100644 index 00000000000..71df8080cd5 --- /dev/null +++ b/tests/OAuth/EloquentOAuthTest.php @@ -0,0 +1,114 @@ +set('auth.providers.users', [ + 'driver' => 'eloquent', + 'model' => EloquentUser::class, + ]); + $app['config']->set('statamic.oauth.enabled', true); + $app['config']->set('statamic.oauth.providers', ['test' => 'Test']); + $app['config']->set('statamic.users.repository', 'eloquent'); + } + + protected function defineDatabaseMigrations() + { + $this->loadMigrationsFrom(__DIR__.'/../Auth/Eloquent/__migrations__'); + } + + public function tearDown(): void + { + app('files')->deleteDirectory(storage_path('statamic/oauth')); + + parent::tearDown(); + } + + #[Test] + public function an_authenticated_eloquent_user_can_connect_a_provider() + { + $user = $this->makeUser(); + + $this->assertFalse(method_exists($user, 'id')); + + $this->fakeProvider('sub-1'); + + $response = $this + ->actingAs($user) + ->withElevatedSession() + ->withSession(['statamic.oauth.guard' => 'web']) + ->get(route('statamic.oauth.callback', 'test')); + + $this->assertSame((string) $user->getKey(), $this->provider()->getUserId('sub-1')); + $this->assertAuthenticatedAs($user); + $response->assertSessionHas('success', __('statamic::messages.oauth_connected', ['provider' => 'Test'])); + } + + #[Test] + public function reconnecting_a_provider_to_the_same_eloquent_user_is_idempotent() + { + $user = $this->makeUser(); + $this->provider()->setUserProviderId(UserFacade::fromUser($user), 'sub-1'); + + $this->fakeProvider('sub-1'); + + $response = $this + ->actingAs($user) + ->withElevatedSession() + ->withSession(['statamic.oauth.guard' => 'web']) + ->get(route('statamic.oauth.callback', 'test')); + + $this->assertSame((string) $user->getKey(), $this->provider()->getUserId('sub-1')); + $response->assertSessionHas('success', __('statamic::messages.oauth_already_connected', ['provider' => 'Test'])); + } + + #[Test] + public function an_authenticated_eloquent_user_can_disconnect_a_provider() + { + $user = $this->makeUser(); + $this->provider()->setUserProviderId(UserFacade::fromUser($user), 'sub-1'); + + $response = $this + ->actingAs($user) + ->withElevatedSession() + ->delete(route('statamic.oauth.disconnect', 'test')); + + $this->assertNull($this->provider()->getUserId('sub-1')); + $response->assertSessionHas('success', __('statamic::messages.oauth_disconnected', ['provider' => 'Test'])); + } + + private function makeUser(): EloquentUser + { + return EloquentUser::create(['name' => 'Test User', 'email' => 'test@example.com']); + } + + private function fakeProvider(string $id): void + { + Socialite::fake('test', SocialiteUser::fake([ + 'id' => $id, + 'email' => 'test@example.com', + 'name' => 'Test User', + ])); + } + + private function provider(): Provider + { + return new Provider('test'); + } +}