Merge pull request #12994 from snipe/features/google_socialite

Google OAuth login
This commit is contained in:
snipe 2023-05-10 01:23:37 -07:00 committed by GitHub
commit a90fc1ab59
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 440 additions and 10 deletions

View file

@ -0,0 +1,57 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
use Laravel\Socialite\Two\InvalidStateException;
class GoogleAuthController extends Controller
{
public function redirectToGoogle()
{
return Socialite::driver('google')->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'),
],
]
);
}
}

View file

@ -1039,6 +1039,48 @@ class SettingsController extends Controller
return $pdf_branding;
}
/**
* Show Google login settings form
*
* @author [A. Gianotto] [<snipe@snipe.net>]
* @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] [<snipe@snipe.net>]
* @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.
*

View file

@ -86,6 +86,9 @@ class Setting extends Model
'webhook_endpoint',
'webhook_channel',
'webhook_botname',
'google_login',
'google_client_id',
'google_client_secret',
];
/**

View file

@ -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",

149
composer.lock generated
View file

@ -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"
}

View file

@ -217,6 +217,7 @@ 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,
],

View file

@ -0,0 +1,37 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddGoogleAuthToSettings extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('settings', function (Blueprint $table) {
$table->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');
});
}
}

View file

@ -12,5 +12,7 @@ return [
'remember_me' => 'Remember Me',
'username_help_top' => 'Enter your <strong>username</strong> to be emailed a password reset link.',
'username_help_bottom' => 'Your username and email address <em>may</em> be the same, but may not be, depending on your configuration. If you cannot remember your username, contact your administrator. <br><br><strong>Usernames without an associated email address will not be emailed a password reset link.</strong> ',
'google_login' => 'Login via Google',
];

View file

@ -77,6 +77,17 @@
@else
<button class="btn btn-lg btn-primary btn-block">{{ trans('auth/general.login') }}</button>
@endif
@if (($snipeSettings->google_login=='1') && ($snipeSettings->google_client_id!='') && ($snipeSettings->google_client_secret!=''))
<br>
<center>Or</center>
<br>
<a class="btn btn-lg btn-primary btn-block" href="{{ route('google.redirect') }}">
<i class="fa-brands fa-google"></i>
{{ trans('auth/general.google_login') }}
</a>
@endif
</div>
<div class="text-right col-md-12 col-sm-12 col-xs-12" style="padding-top: 10px;">
@if ($snipeSettings->custom_forgot_pass_url)

View file

@ -0,0 +1,111 @@
@extends('layouts/default')
{{-- Page title --}}
@section('title')
Google
@parent
@stop
@section('header_right')
<a href="{{ route('settings.index') }}" class="btn btn-primary"> {{ trans('general.back') }}</a>
@stop
{{-- Page content --}}
@section('content')
{{ Form::open(['method' => 'POST', 'files' => false, 'autocomplete' => 'off', 'class' => 'form-horizontal', 'role' => 'form' ]) }}
<!-- CSRF Token -->
{{csrf_field()}}
<div class="row">
<div class="col-sm-10 col-sm-offset-1 col-md-8 col-md-offset-2">
<div class="panel box box-default">
<div class="box-header with-border">
<h2 class="box-title">
<i class="fa-brands fa-google"></i> Google
</h2>
</div>
<div class="box-body">
<div class="col-md-12">
<!-- Google login -->
<div class="form-group {{ $errors->has('google') ? 'error' : '' }}">
<div class="col-md-3 text-right">
{{ Form::label('google_login', 'Google Login') }}
</div>
<div class="col-md-8">
<label class="form-control{{ (config('app.lock_passwords')===true) ? ' form-control--disabled': '' }}">
<span class="sr-only">{{ trans('admin/settings/general.pwd_secure_uncommon') }}</span>
{{ Form::checkbox('google_login', '1', old('google_login', $setting->google_login),array('aria-label'=>'google_login', (config('app.lock_passwords')===true) ? 'disabled': '')) }}
Enable google login
</label>
</div>
</div>
<!-- Google Client ID -->
<div class="form-group {{ $errors->has('google_client_id') ? 'error' : '' }}">
<div class="col-md-3 text-right">
{{ Form::label('google_client_id', 'Client ID') }}
</div>
<div class="col-md-8">
{{ 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', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
@endif
</div>
</div>
<!-- Google Client Secret -->
<div class="form-group {{ $errors->has('google_client_secret') ? 'error' : '' }}">
<div class="col-md-3 text-right">
{{ Form::label('google_client_secret', 'Client Secret') }}
</div>
<div class="col-md-8">
{{ 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', '<span class="alert-msg" aria-hidden="true">:message</span>') !!}
@if (config('app.lock_passwords')===true)
<p class="text-warning"><i class="fas fa-lock" aria-hidden="true"></i> {{ trans('general.feature_disabled') }}</p>
@endif
</div>
</div>
<!-- Google Client Secret -->
<div class="form-group">
<div class="col-md-3 text-right">
<strong>Redirect URL</strong>
</div>
<div class="col-md-8">
<p class="form-control-static">{{ config('app.url') }}/google/callback</p>
<p class="help-block">This should be entered as your calback URL in your Google OAuth app settings in your Google admin console.</p>
</div>
</div>
</div>
</div> <!--/.box-body-->
<div class="box-footer">
<div class="text-left col-md-6">
<a class="btn btn-link text-left" href="{{ route('settings.index') }}">{{ trans('button.cancel') }}</a>
</div>
<div class="text-right col-md-6">
<button type="submit" class="btn btn-success"{{ (config('app.lock_passwords')===true) ? ' disabled': '' }}><i class="fas fa-check icon-white" aria-hidden="true"></i> {{ trans('general.save') }}</button>
</div>
</div>
</div> <!-- /box -->
</div> <!-- /.col-md-8-->
</div> <!-- /.row-->
{{Form::close()}}
@stop

View file

@ -235,6 +235,21 @@
</div>
</div>
<div class="col-md-4 col-lg-3 col-sm-6 col-xl-1">
<div class="box box-default">
<div class="box-body text-center">
<h5>
<a href="{{ route('settings.google.index') }}" class="settings_button">
<i class="fa-brands fa-google fa-4x" aria-hidden="true"></i>
<br><br>
<span class="name">Google Auth</span>
</a>
</h5>
<p class="help-block">Set up Google Login</p>
</div>
</div>
</div>
<div class="col-md-4 col-lg-3 col-sm-6 col-xl-1">
<div class="box box-default">
<div class="box-body text-center">

View file

@ -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(