Skip to content

Commit

Permalink
WIP work on LSLogin flow
Browse files Browse the repository at this point in the history
  • Loading branch information
mzur committed Apr 25, 2023
1 parent 65eac6e commit 9825ad5
Show file tree
Hide file tree
Showing 10 changed files with 322 additions and 2 deletions.
3 changes: 3 additions & 0 deletions composer.json
Expand Up @@ -14,6 +14,9 @@
"email": "martin@cebitec.uni-bielefeld.de"
}
],
"require": {
"socialiteproviders/lifesciencelogin": "^1.0"
},
"autoload": {
"psr-4": {
"Biigle\\Modules\\AuthLSLogin\\": "src"
Expand Down
30 changes: 30 additions & 0 deletions src/Database/Factories/LsloginIdFactory.php
@@ -0,0 +1,30 @@
<?php

namespace Biigle\Modules\AuthLSLogin\Database\Factories;

use Biigle\Modules\AuthLSLogin\LsloginId;
use Biigle\User;
use Illuminate\Database\Eloquent\Factories\Factory;

class LsloginIdFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* @var string
*/
protected $model = LsloginId::class;

/**
* Define the model's default state.
*
* @return array
*/
public function definition()
{
return [
'id' => $this->faker->uuid(),
'user_id' => User::factory(),
];
}
}
@@ -0,0 +1,38 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('lslogin_ids', function (Blueprint $table) {
// The ID can be anything, really, but we hope that it's not longer than
// 128 characters.
$table->string('id', 128)->primary();

$table->timestamps();

$table->foreignId('user_id')
->constrained()
->cascadeOnDelete();
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('lslogin_ids');
}
};
24 changes: 22 additions & 2 deletions src/Http/Controllers/LSLoginController.php
Expand Up @@ -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
Expand All @@ -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');
}
}
13 changes: 13 additions & 0 deletions src/Http/Controllers/RegisterController.php
@@ -0,0 +1,13 @@
<?php

namespace Biigle\Modules\AuthLSLogin\Http\Controllers;

use Biigle\Http\Controllers\Auth\RegisterController as BaseController;
use Laravel\Socialite\Facades\Socialite;

class RegisterController extends BaseController
{
// Handle disabled user registration (show error message)
//
// Reuse parent class code as much as possible (with optional required terms etc)
}
5 changes: 5 additions & 0 deletions src/Http/routes.php
Expand Up @@ -9,3 +9,8 @@
'as' => 'lslogin-callback',
'uses' => 'LSLoginController@callback',
]);

$router->get('auth/lslogin/register', [
'as' => 'lslogin-register-form',
'uses' => 'RegisterController@showRegistrationForm',
]);
9 changes: 9 additions & 0 deletions src/LSLoginServiceProvider.php
Expand Up @@ -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
{
Expand All @@ -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',
Expand All @@ -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']
);
}

/**
Expand Down
55 changes: 55 additions & 0 deletions src/LsloginId.php
@@ -0,0 +1,55 @@
<?php

namespace Biigle\Modules\AuthLSLogin;

use Biigle\Modules\AuthLSLogin\Database\Factories\LsloginIdFactory;
use Biigle\User;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class LsloginId extends Model
{
use HasFactory;

/**
* Indicates if the model's ID is auto-incrementing.
*
* @var bool
*/
public $incrementing = false;

/**
* The data type of the auto-incrementing ID.
*
* @var string
*/
protected $keyType = 'string';

/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'id',
'user_id',
];

/**
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function user()
{
return $this->belongsTo(User::class);
}

/**
* Create a new factory instance for the model.
*
* @return \Illuminate\Database\Eloquent\Factories\Factory
*/
protected static function newFactory()
{
return LsloginIdFactory::new();
}
}
79 changes: 79 additions & 0 deletions tests/Http/Controllers/LSLoginControllerTest.php
@@ -0,0 +1,79 @@
<?php

namespace Biigle\Tests\Modules\AuthLSLogin\Http\Controllers;

use Biigle\Modules\AuthLSLogin\LsloginId;
use Biigle\User;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\User as SocialiteUser;
use Session;
use TestCase;


class LSLoginControllerTest extends TestCase
{
public function testRedirect()
{
$this->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();
}
}
68 changes: 68 additions & 0 deletions tests/Http/Controllers/RegisterControllerTest.php
@@ -0,0 +1,68 @@
<?php

namespace Biigle\Tests\Modules\AuthLSLogin\Http\Controllers;

use Biigle\User;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\User as SocialiteUser;
use Session;
use TestCase;


class RegisterControllerTest extends TestCase
{
public function testShowRegistrationForm()
{
// user should enter affiliation and check terms/privacy
}

public function testShowRegistrationFormWithoutToken()
{
//
}

public function testShowRegistrationFormAuthenticated()
{
//
}

public function testShowRegistrationFormDisabledRegistration()
{
//
}

public function testRegister()
{
// should not require honeypot if the token is in the session
}

public function testRegisterEmailTaken()
{
// case insensitive
}

public function testRegisterWithoutToken()
{
//
}

public function testRegisterDisabledRegistration()
{
//
}

public function testRegisterAuthenticated()
{
//
}

public function testRegisterAdminConfirmationDisabled()
{
//
}

public function testRegisterAdminConfirmationEnabled()
{
//
}
}

0 comments on commit 9825ad5

Please sign in to comment.