diff --git a/.env.example b/.env.example index fbf5c4cfff..08baf822f5 100644 --- a/.env.example +++ b/.env.example @@ -175,6 +175,15 @@ REQUIRE_SAML=false API_THROTTLE_PER_MINUTE=120 CSV_ESCAPE_FORMULAS=true + +# -------------------------------------------- +# OPTIONAL: GOOGLE LOGIN +# -------------------------------------------- +ENABLE_GOOGLE_LOGIN=false +GOOGLE_CLIENT_ID=null +GOOGLE_CLIENT_SECRET=null +GOOGLE_REDIRECT_URL=null + # -------------------------------------------- # OPTIONAL: HASHING # -------------------------------------------- diff --git a/app/Http/Controllers/GoogleAuthController.php b/app/Http/Controllers/GoogleAuthController.php new file mode 100644 index 0000000000..b24a3a5b25 --- /dev/null +++ b/app/Http/Controllers/GoogleAuthController.php @@ -0,0 +1,57 @@ +redirect(); + } + + public function handleGoogleCallback() + { + try { + $socialUser = Socialite::driver('google')->user(); + } catch (InvalidStateException $exception) { + + return redirect()->route('login') + ->withErrors( + [ + 'email' => [ + __('Google Login failed, please try again.'), + ], + ] + ); + } + + + $user = User::where('email', $socialUser->getEmail())->first(); + + + if ($user) { + $user->update([ + 'avatar' => $socialUser->avatar, + ]); + + Auth::login($user, true); + return redirect()->route('setup.done'); + } + + return redirect()->route('login') + ->withErrors( + [ + 'email' => [ + trans('admin/users/message.user_not_found'), + ], + ] + ); + } +} \ No newline at end of file diff --git a/composer.json b/composer.json index a66aa22df0..165a4a08f6 100644 --- a/composer.json +++ b/composer.json @@ -46,6 +46,7 @@ "laravel/helpers": "^1.4", "laravel/passport": "^10.1", "laravel/slack-notification-channel": "^2.3", + "laravel/socialite": "^5.6", "laravel/tinker": "^2.6", "laravel/ui": "^3.3", "laravelcollective/html": "^6.2", diff --git a/composer.lock b/composer.lock index 620c7c6855..1ef75690aa 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c0444af6de1d16a70c7e5520db745170", + "content-hash": "4c82b2e171fb02a3ef024906db5d74c9", "packages": [ { "name": "alek13/slack", @@ -3605,6 +3605,75 @@ }, "time": "2022-01-12T18:07:54+00:00" }, + { + "name": "laravel/socialite", + "version": "v5.6.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/socialite.git", + "reference": "a14a177f2cc71d8add71e2b19e00800e83bdda09" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/socialite/zipball/a14a177f2cc71d8add71e2b19e00800e83bdda09", + "reference": "a14a177f2cc71d8add71e2b19e00800e83bdda09", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0", + "illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0", + "league/oauth1-client": "^1.10.1", + "php": "^7.2|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0", + "phpunit/phpunit": "^8.0|^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + }, + "laravel": { + "providers": [ + "Laravel\\Socialite\\SocialiteServiceProvider" + ], + "aliases": { + "Socialite": "Laravel\\Socialite\\Facades\\Socialite" + } + } + }, + "autoload": { + "psr-4": { + "Laravel\\Socialite\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel wrapper around OAuth 1 & OAuth 2 libraries.", + "homepage": "https://laravel.com", + "keywords": [ + "laravel", + "oauth" + ], + "support": { + "issues": "https://github.com/laravel/socialite/issues", + "source": "https://github.com/laravel/socialite" + }, + "time": "2023-01-20T15:42:35+00:00" + }, { "name": "laravel/tinker", "version": "v2.7.2", @@ -4534,6 +4603,82 @@ ], "time": "2022-04-17T13:12:02+00:00" }, + { + "name": "league/oauth1-client", + "version": "v1.10.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth1-client.git", + "reference": "d6365b901b5c287dd41f143033315e2f777e1167" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth1-client/zipball/d6365b901b5c287dd41f143033315e2f777e1167", + "reference": "d6365b901b5c287dd41f143033315e2f777e1167", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-openssl": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "guzzlehttp/psr7": "^1.7|^2.0", + "php": ">=7.1||>=8.0" + }, + "require-dev": { + "ext-simplexml": "*", + "friendsofphp/php-cs-fixer": "^2.17", + "mockery/mockery": "^1.3.3", + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5||9.5" + }, + "suggest": { + "ext-simplexml": "For decoding XML-based responses." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev", + "dev-develop": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "League\\OAuth1\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Corlett", + "email": "bencorlett@me.com", + "homepage": "http://www.webcomm.com.au", + "role": "Developer" + } + ], + "description": "OAuth 1.0 Client Library", + "keywords": [ + "Authentication", + "SSO", + "authorization", + "bitbucket", + "identity", + "idp", + "oauth", + "oauth1", + "single sign on", + "trello", + "tumblr", + "twitter" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth1-client/issues", + "source": "https://github.com/thephpleague/oauth1-client/tree/v1.10.1" + }, + "time": "2022-04-15T14:02:14+00:00" + }, { "name": "league/oauth2-server", "version": "8.3.5", @@ -16425,5 +16570,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.0.0" } diff --git a/config/app.php b/config/app.php index 8833ea2ae7..2913bdc273 100755 --- a/config/app.php +++ b/config/app.php @@ -216,7 +216,17 @@ return [ */ 'require_saml' => env('REQUIRE_SAML', false), - + + + /* + |-------------------------------------------------------------------------- + | Enable Google Login + |-------------------------------------------------------------------------- + */ + + 'google_login' => env('ENABLE_GOOGLE_LOGIN', false), + + /* |-------------------------------------------------------------------------- | Demo Mode Lockdown @@ -294,6 +304,7 @@ return [ Laravel\Tinker\TinkerServiceProvider::class, Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class, Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class, + Laravel\Socialite\SocialiteServiceProvider::class, /* * Application Service Providers... @@ -366,6 +377,7 @@ return [ 'Image' => Intervention\Image\ImageServiceProvider::class, 'Carbon' => Carbon\Carbon::class, 'Helper' => App\Helpers\Helper::class, // makes it much easier to use 'Helper::blah' in blades (which is where we usually use this) + 'Socialite' => Laravel\Socialite\Facades\Socialite::class, ], diff --git a/config/services.php b/config/services.php index de8c4ed71a..a0f25664f6 100644 --- a/config/services.php +++ b/config/services.php @@ -51,6 +51,9 @@ return [ 'google' => [ 'maps_api_key' => env('GOOGLE_MAPS_API'), + 'client_id' => env('GOOGLE_CLIENT_ID'), + 'client_secret' => env('GOOGLE_CLIENT_SECRET'), + 'redirect' => env('GOOGLE_REDIRECT_URL'), ], ]; diff --git a/resources/lang/en/auth/general.php b/resources/lang/en/auth/general.php index 78b6780927..a0914b6334 100644 --- a/resources/lang/en/auth/general.php +++ b/resources/lang/en/auth/general.php @@ -12,5 +12,7 @@ return [ 'remember_me' => 'Remember Me', 'username_help_top' => 'Enter your username to be emailed a password reset link.', 'username_help_bottom' => 'Your username and email address may be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator.

Usernames without an associated email address will not be emailed a password reset link. ', - ]; + 'google_login' => 'Login via Google', + +]; diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 330d7bf503..730afae833 100755 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -64,7 +64,7 @@ @if (!config('app.require_saml') && $snipeSettings->saml_enabled) -
+
@@ -73,9 +73,17 @@
diff --git a/routes/web.php b/routes/web.php index 39c66d35d8..f809f5a3e3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -453,8 +453,6 @@ Route::group(['middleware' => 'web'], function () { [LoginController::class, 'postTwoFactorAuth'] ); - - Route::post( 'password/email', [ForgotPasswordController::class, 'sendResetLinkEmail'] @@ -483,7 +481,9 @@ Route::group(['middleware' => 'web'], function () { )->name('password.email')->middleware('throttle:forgotten_password'); - + // Socialite Google login + Route::get('google', 'App\Http\Controllers\GoogleAuthController@redirectToGoogle')->name('google.redirect'); + Route::get('google/callback', 'App\Http\Controllers\GoogleAuthController@handleGoogleCallback')->name('google.callback'); Route::get(