diff --git a/app/Http/Controllers/GoogleAuthController.php b/app/Http/Controllers/GoogleAuthController.php new file mode 100644 index 0000000000..fea45f5b61 --- /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('home'); + } + + return redirect()->route('login') + ->withErrors( + [ + 'email' => [ + trans('admin/users/message.user_not_found'), + ], + ] + ); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index c626203cfc..fbb7f4e4ce 100755 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -1039,6 +1039,48 @@ class SettingsController extends Controller return $pdf_branding; } + + /** + * Show Google login settings form + * + * @author [A. Gianotto] [] + * @since [v6.1.1] + * @return View + */ + public function getGoogleLoginSettings() + { + $setting = Setting::getSettings(); + return view('settings.google', compact('setting')); + } + + /** + * ShSaveow Google login settings form + * + * @author [A. Gianotto] [] + * @since [v6.1.1] + * @return View + */ + public function postGoogleLoginSettings(Request $request) + { + if (!config('app.lock_passwords')) { + $setting = Setting::getSettings(); + + $setting->google_login = $request->input('google_login', 0); + $setting->google_client_id = $request->input('google_client_id'); + $setting->google_client_secret = $request->input('google_client_secret'); + + if ($setting->save()) { + return redirect()->route('settings.index') + ->with('success', trans('admin/settings/message.update.success')); + } + + return redirect()->back()->withInput()->withErrors($setting->getErrors()); + } + + return redirect()->back()->with('error', trans('general.feature_disabled')); + } + + /** * Show the listing of backups. * diff --git a/app/Models/Setting.php b/app/Models/Setting.php index 61be790e00..807f6a962f 100755 --- a/app/Models/Setting.php +++ b/app/Models/Setting.php @@ -86,6 +86,9 @@ class Setting extends Model 'webhook_endpoint', 'webhook_channel', 'webhook_botname', + 'google_login', + 'google_client_id', + 'google_client_secret', ]; /** 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..2559b8012c 100755 --- a/config/app.php +++ b/config/app.php @@ -216,7 +216,8 @@ return [ */ 'require_saml' => env('REQUIRE_SAML', false), - + + /* |-------------------------------------------------------------------------- | Demo Mode Lockdown @@ -294,6 +295,7 @@ return [ Laravel\Tinker\TinkerServiceProvider::class, Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class, Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class, + Laravel\Socialite\SocialiteServiceProvider::class, /* * Application Service Providers... @@ -366,6 +368,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/database/migrations/2023_05_10_001836_add_google_auth_to_settings.php b/database/migrations/2023_05_10_001836_add_google_auth_to_settings.php new file mode 100644 index 0000000000..7f15e0d6e1 --- /dev/null +++ b/database/migrations/2023_05_10_001836_add_google_auth_to_settings.php @@ -0,0 +1,37 @@ +boolean('google_login')->nullable()->default(0); + $table->string('google_client_id')->nullable()->default(null); + $table->string('google_client_secret')->nullable()->default(null); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('settings', function (Blueprint $table) { + $table->dropColumn('google_login'); + $table->dropColumn('google_client_id'); + $table->dropColumn('google_client_secret'); + + }); + } +} 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..9d1f371cf4 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) -
+
diff --git a/resources/views/settings/google.blade.php b/resources/views/settings/google.blade.php new file mode 100644 index 0000000000..aaae6aa619 --- /dev/null +++ b/resources/views/settings/google.blade.php @@ -0,0 +1,111 @@ +@extends('layouts/default') + +{{-- Page title --}} +@section('title') + Google + @parent +@stop + +@section('header_right') + {{ trans('general.back') }} +@stop + + +{{-- Page content --}} +@section('content') + + + + {{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form' ]) }} + + {{csrf_field()}} + +
+
+ + +
+
+

+ Google +

+
+
+ + +
+ + +
+
+ {{ Form::label('google_login', 'Google Login') }} +
+
+ +
+
+ + + +
+
+ {{ Form::label('google_client_id', 'Client ID') }} +
+
+ {{ Form::text('google_client_id', old('google_client_id', $setting->google_client_id), ['class' => 'form-control','placeholder' => trans('general.example') .'000000000000-XXXXXXXXXXX.apps.googleusercontent.com', (config('app.lock_passwords')===true) ? 'disabled': '']) }} + {!! $errors->first('google_client_id', '') !!} + @if (config('app.lock_passwords')===true) +

{{ trans('general.feature_disabled') }}

+ @endif +
+
+ + +
+
+ {{ Form::label('google_client_secret', 'Client Secret') }} +
+
+ {{ Form::text('google_client_secret', old('google_client_secret', $setting->google_client_secret), ['class' => 'form-control','placeholder' => trans('general.example') .'XXXXXXXXXXXX', (config('app.lock_passwords')===true) ? 'disabled': '']) }} + {!! $errors->first('google_client_secret', '') !!} + @if (config('app.lock_passwords')===true) +

{{ trans('general.feature_disabled') }}

+ @endif +
+
+ + +
+
+ Redirect URL +
+
+

{{ config('app.url') }}/google/callback

+

This should be entered as your calback URL in your Google OAuth app settings in your Google admin console.

+
+
+ +
+ + +
+ +
+
+
+ + {{Form::close()}} + +@stop diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index 678233c933..83642da669 100755 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -235,6 +235,21 @@
+
+
+
+
+ + +

+ Google Auth +
+
+

Set up Google Login

+
+
+
+
diff --git a/routes/web.php b/routes/web.php index 39c66d35d8..49998f43fc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -192,6 +192,9 @@ Route::group(['prefix' => 'admin', 'middleware' => ['auth', 'authorize:superuser Route::get('oauth', [SettingsController::class, 'api'])->name('settings.oauth.index'); + Route::get('google', [SettingsController::class, 'getGoogleLoginSettings'])->name('settings.google.index'); + Route::post('google', [SettingsController::class, 'postGoogleLoginSettings'])->name('settings.google.save'); + Route::get('purge', [SettingsController::class, 'getPurge'])->name('settings.purge.index'); Route::post('purge', [SettingsController::class, 'postPurge'])->name('settings.purge.save'); @@ -453,8 +456,6 @@ Route::group(['middleware' => 'web'], function () { [LoginController::class, 'postTwoFactorAuth'] ); - - Route::post( 'password/email', [ForgotPasswordController::class, 'sendResetLinkEmail'] @@ -483,7 +484,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(