diff --git a/database/migrations/authkit2_token.php b/database/migrations/authkit2_token.php new file mode 100644 index 0000000..a537ee6 --- /dev/null +++ b/database/migrations/authkit2_token.php @@ -0,0 +1,35 @@ +text('id')->unique(); + $table->foreignId('user_id')->constrained('users'); + $table->text('access_token'); + $table->text('refresh_token'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::drop('authkit2_token'); + } +} diff --git a/database/migrations/existing/authkit2_users_update_minimal.php b/database/migrations/existing/authkit2_users_update_minimal.php index 11c3325..210b189 100644 --- a/database/migrations/existing/authkit2_users_update_minimal.php +++ b/database/migrations/existing/authkit2_users_update_minimal.php @@ -6,7 +6,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class Authkit2UsersUpdateMinimal extends Migration +class Authkit2ExistingProject extends Migration { /** * Run the migrations. @@ -15,16 +15,9 @@ class Authkit2UsersUpdateMinimal extends Migration */ public function up() { - // These are split up like this as to not cause issues when running - // against sqlite. Schema::table('users', static function(Blueprint $table) { $table->string('password')->nullable()->change(); }); - Schema::table('users', static function(BluePrint $table) { - $table->string('authkit_id')->unique()->nullable(); - $table->text('authkit_access_token')->nullable(); - $table->text('authkit_refresh_token')->nullable(); - }); } /** @@ -35,7 +28,6 @@ class Authkit2UsersUpdateMinimal extends Migration public function down() { Schema::table('users', static function(Blueprint $table) { - $table->dropColumn(['authkit_id', 'authkit_access_token', 'authkit_refresh_token']); $table->string('password')->nullable(false)->default(null)->change(); }); } diff --git a/database/migrations/new/authkit2_users_update.php b/database/migrations/new/authkit2_users_update.php index 80322c0..0c3c8d4 100644 --- a/database/migrations/new/authkit2_users_update.php +++ b/database/migrations/new/authkit2_users_update.php @@ -6,7 +6,7 @@ use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; -class Authkit2UsersUpdate extends Migration +class Authkit2FreshProject extends Migration { /** * Run the migrations. @@ -15,16 +15,9 @@ class Authkit2UsersUpdate extends Migration */ public function up() { - // These are split up like this as to not cause issues when running - // against sqlite. Schema::table('users', static function(Blueprint $table) { $table->dropColumn(['email_verified_at', 'password']); }); - Schema::table('users', static function(Blueprint $table) { - $table->string('authkit_id')->unique(); - $table->text('authkit_access_token'); - $table->text('authkit_refresh_token'); - }); } /** @@ -35,7 +28,6 @@ class Authkit2UsersUpdate extends Migration public function down() { Schema::table('users', static function(Blueprint $table) { - $table->dropColumn(['authkit_id', 'authkit_access_token', 'authkit_refresh_token']); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); }); diff --git a/src/Events/UserLogin.php b/src/Events/UserLogin.php index fce9eb6..b6c8f65 100644 --- a/src/Events/UserLogin.php +++ b/src/Events/UserLogin.php @@ -9,4 +9,22 @@ namespace authkit2\Events; */ class UserLogin extends UserEvent { + /** + * Additional fields returned during login + * + * @var mixed + */ + public $user_info; + + /** + * Initialize new event + * + * @param mixed $user + * @param array $user_info + */ + public function __construct($user, array $user_info) + { + parent::__construct($user); + $this->user_info = $user_info; + } } diff --git a/src/Http/Controllers/AuthenticationController.php b/src/Http/Controllers/AuthenticationController.php index 60ec396..9e63125 100644 --- a/src/Http/Controllers/AuthenticationController.php +++ b/src/Http/Controllers/AuthenticationController.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace authkit2\Http\Controllers; use Illuminate\Http\Request; +use authkit2\Models\Token; /** * Methods for handling user authentication operations @@ -43,75 +44,49 @@ class AuthenticationController extends Controller */ public function callback(Request $request) { - // Get the user class from the Laravel auth config - $user_class = config('auth.providers.users.model'); - // Verify the passed in state value $this->user_flow->validateState($request->state); // TODO: Check for error response // Exchange the code for a token - $token = $this->user_flow->exchangeCodeForToken($request->code, config('authkit.authn.openid.redirect_uri')); - $user_info = $token->getUserInfo(); + $oidc_token = $this->user_flow->exchangeCodeForToken($request->code, config('authkit.authn.openid.redirect_uri')); + $user_info = $oidc_token->getUserInfo(); - // Try and use the token to find the local user - $user = \Auth::loginUsingId($token->getUserId()); + // Try and find a token for that user id + $token = Token::where('id', $oidc_token->getUserId())->first(); // If that failed - if ($user === false) + if (!isset($token)) { - // User doesn't exist, create them. - $user = new $user_class(); - $id_field = $user->getAuthIdentifierName(); - $user->{$id_field} = $token->getUserId(); - $user->name = $user_info['name']; - $user->email = $user_info['email']; - if ($user instanceof \authkit2\Models\IAuthkitUser) - { - $user->{$user->getAccessTokenName()} = $token->getAccessToken(); - $user->{$user->getRefreshTokenName()} = $token->getRefreshToken(); - } - else + // No token for that user, either create them or migrate + $register_event_result = event(new \authkit2\Events\UserRegistration($user_info)); + $user = null; + foreach ($register_event_result as $result) { - $user->authkit_access_token = $token->getAccessToken(); - $user->authkit_refresh_token = $token->getRefreshToken(); - } - $register_event_result = event(new \authkit2\Events\UserRegistration($user)); - if (sizeof($register_event_result)) - { - foreach ($register_event_result as $result) + if (is_object($result)) { - if ($result instanceof $user_class) - { - $user = $result; - } + $user = $result; } } - if (!$user->exists) - { - $user->save(); - } - \Auth::login($user); - } - else - { - $user->name = $user_info['name']; - $user->email = $user_info['email']; - if ($user instanceof \authkit2\Models\IAuthkitUser) - { - $user->{$user->getAccessTokenName()} = $token->getAccessToken(); - $user->{$user->getRefreshTokenName()} = $token->getRefreshToken(); - } - else + + if (!isset($user)) { - $user->authkit_access_token = $token->getAccessToken(); - $user->authkit_refresh_token = $token->getRefreshToken(); + // TODO: Log a useful error + abort(500); } - $user->save(); + + $token = new Token(); + $token->id = $oidc_token->getUserId(); + $token->access_token = $oidc_token->getAccessToken(); + $token->refresh_token = $oidc_token->getRefreshToken(); + $token->user_id = $user->{$user->getAuthIdentifierName()}; + $token->save(); + } - event(new \authkit2\Events\UserLogin($user)); + \Auth::login($user); + event(new \authkit2\Events\UserLogin($user, $user_info)); return redirect(url(config('authkit.authn.urls.post_login'))); } diff --git a/src/Models/IAuthkitUser.php b/src/Models/IAuthkitUser.php deleted file mode 100644 index 5d4462f..0000000 --- a/src/Models/IAuthkitUser.php +++ /dev/null @@ -1,9 +0,0 @@ -{$user->getAccessTokenName()}; - $refresh = $user->{$user->getRefreshTokenName()}; - } - else - { - $token = $user->authkit_access_token; - $refresh = $user->authkit_refresh_token; - } + // Find the token + refresh token for the user + $token = Token::where('user_id', $user->{$user->getAuthIdentifierName()})->first(); // Create a token object - $user->authkit = Authkit2::get_token($token, $refresh); + $user->authkit = Authkit2::get_token($token->access_token, $token->refresh_token); + // Set a refresh callback on the token -- when it's been refreshed, - // then set the new tokens on the user and save it - $user->authkit->setRefreshCallback(function($token) use ($user) { - if ($user instanceof \authkit2\Models\IAuthkitUser) - { - $user->{$user->getAccessTokenName()} = $token->getAccessToken(); - $user->{$user->getRefreshTokenName()} = $token->getRefreshToken(); - } - else - { - $user->authkit_access_token = $token->getAccessToken(); - $user->authkit_refresh_token = $token->getRefreshToken(); - } - $user->save(); + // save the new tokens. + $user->authkit->setRefreshCallback(function($oidc_token) use ($token) { + $token->access_token = $oidc_token->getAccessToken(); + $token->refresh_token = $oidc_token->getRefreshToken(); + $token->save(); }); } public function saving($user) { if (isset($user->authkit)) - static::$token_cache[$user->authkit->getAccessToken()] = $user->authkit; + static::$token_cache[$user->{$user->getAuthIdentifierName()}] = $user->authkit; unset($user->authkit); } public function saved($user) { - $access_token = ($user instanceof \authkit2\Models\IAuthkitUser) ? $user->{$user->getAccessTokenName()} : $user->authkit_access_token; - if (isset(static::$token_cache[$access_token])) - $user->authkit = static::$token_cache[$access_token]; + $user_id = $user->{$user->getAuthIdentifierName()}; + if (isset(static::$token_cache[$user_id])) + $user->authkit = static::$token_cache[$user_id]; } } diff --git a/src/Providers/Authkit2ServiceProvider.php b/src/Providers/Authkit2ServiceProvider.php index 82a4017..b2b8289 100644 --- a/src/Providers/Authkit2ServiceProvider.php +++ b/src/Providers/Authkit2ServiceProvider.php @@ -39,14 +39,16 @@ class Authkit2ServiceProvider extends ServiceProvider { $this->publishes([ __DIR__.'/../../config/authkit.php' => config_path('authkit.php') - ], 'config'); + ], 'authkit2_config'); $this->publishes([ - __DIR__.'/../../database/migrations/new/authkit2_users_update.php' => database_path('migrations/'.date('Y_m_d_His').'_authkit2_users_update.php') - ], 'migrations_new'); + __DIR__.'/../../database/migrations/authkit2_token.php' => database_path('migrations/'.date('Y_m_d_His').'_authkit2_token.php'), + __DIR__.'/../../database/migrations/new/authkit2_users_update.php' => database_path('migrations/'.date('Y_m_d_His').'_authkit2_fresh_project.php') + ], 'authkit2_migrate_fresh_project'); $this->publishes([ - __DIR__.'/../../database/migrations/existing/authkit2_users_update_minimal.php' => database_path('migrations/'.date('Y_m_d_His').'_authkit2_users_update_minimal.php') - ], 'migrations_existing'); + __DIR__.'/../../database/migrations/authkit2_token.php' => database_path('migrations/'.date('Y_m_d_His').'_authkit2_token.php'), + __DIR__.'/../../database/migrations/existing/authkit2_users_update_minimal.php' => database_path('migrations/'.date('Y_m_d_His').'_authkit2_existing_project.php') + ], 'authkit2_migrate_existing_project'); } } } diff --git a/src/Providers/AuthnServiceProvider.php b/src/Providers/AuthnServiceProvider.php index 46b340f..45ee712 100644 --- a/src/Providers/AuthnServiceProvider.php +++ b/src/Providers/AuthnServiceProvider.php @@ -120,8 +120,13 @@ class AuthnServiceProvider extends ServiceProvider ]); } - $this->app->booted(function($app) { - Authkit2::configure(config('authkit.authn.openid.client_id'), config('authkit.authn.openid.client_secret'), config('authkit.authn.openid.endpoint')); - }); + // Don't even try and init authkit unless configuration is present, prevents erroring out when + // running a composer require/composer install without credentials present. + if (config('authkit.authn.openid.client_id') != null && config('authkit.authn.openid.client_secret') != null && config('authkit.authn.openid.endpoint') != null) + { + $this->app->booted(function($app) { + Authkit2::configure(config('authkit.authn.openid.client_id'), config('authkit.authn.openid.client_secret'), config('authkit.authn.openid.endpoint')); + }); + } } }