diff --git a/composer.json b/composer.json index 74015e4..ce260b2 100644 --- a/composer.json +++ b/composer.json @@ -14,6 +14,9 @@ "email": "martin@cebitec.uni-bielefeld.de" } ], + "require": { + "socialiteproviders/lifesciencelogin": "^1.0" + }, "autoload": { "psr-4": { "Biigle\\Modules\\AuthLSLogin\\": "src" diff --git a/src/Database/Factories/LsloginIdFactory.php b/src/Database/Factories/LsloginIdFactory.php new file mode 100644 index 0000000..d0fca2a --- /dev/null +++ b/src/Database/Factories/LsloginIdFactory.php @@ -0,0 +1,30 @@ + $this->faker->uuid(), + 'user_id' => User::factory(), + ]; + } +} diff --git a/src/Database/migrations/2023_04_25_122133_create_lslogin_ids_table.php b/src/Database/migrations/2023_04_25_122133_create_lslogin_ids_table.php new file mode 100644 index 0000000..ddea408 --- /dev/null +++ b/src/Database/migrations/2023_04_25_122133_create_lslogin_ids_table.php @@ -0,0 +1,38 @@ +string('id', 128)->primary(); + + $table->timestamps(); + + $table->foreignId('user_id') + ->constrained() + ->cascadeOnDelete(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('lslogin_ids'); + } +}; diff --git a/src/Http/Controllers/LSLoginController.php b/src/Http/Controllers/LSLoginController.php index f2940fc..0726ca0 100644 --- a/src/Http/Controllers/LSLoginController.php +++ b/src/Http/Controllers/LSLoginController.php @@ -3,6 +3,9 @@ namespace Biigle\Modules\AuthLSLogin\Http\Controllers; use Biigle\Http\Controllers\Controller; +use Biigle\Modules\AuthLSLogin\LsloginId; +use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; use Laravel\Socialite\Facades\Socialite; class LSLoginController extends Controller @@ -20,12 +23,29 @@ public function redirect() /** * Handle the authentication response * + * @param Request $request * @return mixed */ - public function callback() + public function callback(Request $request) { $user = Socialite::driver('lifesciencelogin')->user(); - //... + $lslId = LsloginId::with('user')->find($user->id); + if ($lslId) { + Auth::login($lslId->user); + + return redirect()->route('home'); + } elseif ($request->user()) { + LsloginId::create([ + 'id' => $user->id, + 'user_id' => $request->user()->id, + ]); + + return redirect()->route('home'); + } + + $request->session()->put('lslogin-token', $user->token); + + return redirect()->route('lslogin-register-form'); } } diff --git a/src/Http/Controllers/RegisterController.php b/src/Http/Controllers/RegisterController.php new file mode 100644 index 0000000..55e079b --- /dev/null +++ b/src/Http/Controllers/RegisterController.php @@ -0,0 +1,13 @@ + 'lslogin-callback', 'uses' => 'LSLoginController@callback', ]); + +$router->get('auth/lslogin/register', [ + 'as' => 'lslogin-register-form', + 'uses' => 'RegisterController@showRegistrationForm', +]); diff --git a/src/LSLoginServiceProvider.php b/src/LSLoginServiceProvider.php index da9607d..22e43bf 100644 --- a/src/LSLoginServiceProvider.php +++ b/src/LSLoginServiceProvider.php @@ -4,7 +4,10 @@ use Biigle\Services\Modules; use Illuminate\Routing\Router; +use Illuminate\Support\Facades\Event; use Illuminate\Support\ServiceProvider; +use SocialiteProviders\Manager\SocialiteWasCalled; +use SocialiteProviders\LifeScienceLogin\LifeScienceLoginExtendSocialite; class LSLoginServiceProvider extends ServiceProvider { @@ -19,6 +22,7 @@ class LSLoginServiceProvider extends ServiceProvider public function boot(Modules $modules, Router $router) { $this->loadViewsFrom(__DIR__.'/resources/views', 'auth-lslogin'); + $this->loadMigrationsFrom(__DIR__.'/Database/migrations'); $router->group([ 'namespace' => 'Biigle\Modules\AuthLSLogin\Http\Controllers', @@ -37,6 +41,11 @@ public function boot(Modules $modules, Router $router) $this->publishes([ __DIR__.'/public/assets' => public_path('vendor/auth-lslogin'), ], 'public'); + + Event::listen( + SocialiteWasCalled::class, + [LifeScienceLoginExtendSocialite::class, 'handle'] + ); } /** diff --git a/src/LsloginId.php b/src/LsloginId.php new file mode 100644 index 0000000..bac76c1 --- /dev/null +++ b/src/LsloginId.php @@ -0,0 +1,55 @@ +belongsTo(User::class); + } + + /** + * Create a new factory instance for the model. + * + * @return \Illuminate\Database\Eloquent\Factories\Factory + */ + protected static function newFactory() + { + return LsloginIdFactory::new(); + } +} diff --git a/tests/Http/Controllers/LSLoginControllerTest.php b/tests/Http/Controllers/LSLoginControllerTest.php new file mode 100644 index 0000000..719a224 --- /dev/null +++ b/tests/Http/Controllers/LSLoginControllerTest.php @@ -0,0 +1,79 @@ +get('auth/lslogin/redirect') + ->assertRedirectContains('https://proxy.aai.lifescience-ri.eu'); + } + + public function testCallbackNewUser() + { + $user = new SocialiteUser; + $user->setToken('mytoken'); + Socialite::shouldReceive('driver->user')->andReturn($user); + + $this->get('auth/lslogin/callback') + ->assertSessionHas('lslogin-token', 'mytoken') + ->assertRedirectToRoute('lslogin-register-form'); + } + + public function testCallbackConflictingNewEmail() + { + // The LSLogin ID does not exist yet but a user with the email address exists. + // Show an error message and suggest to connect the existing account + // (i.e. log in to the account and then connect via settings). + $this->markTestIncomplete(); + } + + public function testCallbackExistingUser() + { + $id = LsloginId::factory()->create(); + $user = new SocialiteUser; + $user->map(['id' => $id->id]); + Socialite::shouldReceive('driver->user')->andReturn($user); + + $this->get('auth/lslogin/callback')->assertRedirectToRoute('home'); + $this->assertAuthenticatedAs($id->user); + } + + public function testCallbackConnectWithUser() + { + + $user = new SocialiteUser; + $user->map(['id' => 'myspecialid']); + Socialite::shouldReceive('driver->user')->andReturn($user); + + $user = User::factory()->create(); + $this->be($user); + $this->get('auth/lslogin/callback')->assertRedirectToRoute('home'); + $this->assertAuthenticatedAs($user); + $this->assertTrue(LsloginId::where('user_id', $user->id)->where('id', 'myspecialid')->exists()); + $this->markTestIncomplete('redirect to the third party auth settings view'); + } + + public function testCallbackConnectConflictingIDExists() + { + // A user is already authenticated but the LSLogin ID is already connected to a + // different user. Show an error message. + $this->markTestIncomplete(); + } + + public function testCallbackConnectAlreadyConnected() + { + // A user is authenticated and the LSLogin ID is already connected to the user. + // Redirect to the dashboard and do nothing. + $this->markTestIncomplete(); + } +} diff --git a/tests/Http/Controllers/RegisterControllerTest.php b/tests/Http/Controllers/RegisterControllerTest.php new file mode 100644 index 0000000..ef41526 --- /dev/null +++ b/tests/Http/Controllers/RegisterControllerTest.php @@ -0,0 +1,68 @@ +