Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
7db3df7
[WIP] Add google2fa depend and views
asbiin Dec 22, 2017
b8f3803
[WIP] Add check for code when enabling 2FA, improve views
asbiin Dec 26, 2017
280498a
Update composer
asbiin Dec 26, 2017
f5ef3f9
Add a Command to deactivate 2FA for a user
asbiin Dec 26, 2017
9c956a5
Add a new conf in the .env file to enable/disable 2FA
asbiin Dec 26, 2017
70cb16b
Use the login function from Authenticator
asbiin Dec 26, 2017
a6cbd94
Add some tests
asbiin Dec 27, 2017
b0ef8cc
Updating composer
asbiin Dec 27, 2017
df3b0a4
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Dec 27, 2017
a1c1468
Commit StyleCI analysis
asbiin Dec 27, 2017
e49f927
Add a Security item in the sidebar, and fix other stuffs (translation…
asbiin Jan 1, 2018
63bc2f3
Update lang file (en) that was missed on the last commit
asbiin Jan 1, 2018
6f44483
Add a comment to the env example file
asbiin Jan 1, 2018
0d37211
Renaming controller, add good return message
asbiin Jan 2, 2018
c8c8266
StyleCI recommandations
asbiin Jan 2, 2018
db98f2c
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Jan 2, 2018
b81a417
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Jan 2, 2018
6006cf6
Update messages
asbiin Jan 4, 2018
663db7c
Use app laravel function
asbiin Jan 4, 2018
42260cf
Change route for 2fa validation
asbiin Jan 4, 2018
2c5b1db
Fix layout and some messages
asbiin Jan 6, 2018
a740b68
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Jan 6, 2018
b37c399
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Jan 6, 2018
28380f2
Fix styleci
asbiin Jan 6, 2018
fbe4586
Merge branch '164-2FA-two-factor-auth' of github.com:asbiin/monica in…
asbiin Jan 6, 2018
efe87c5
Add texts to every lang files
asbiin Jan 6, 2018
8d0e1bf
Fix stylceci
asbiin Jan 6, 2018
151535b
Add some infos
asbiin Jan 6, 2018
a7c0cfa
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Jan 6, 2018
0b0f393
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Jan 6, 2018
d2159bb
Merge branch 'master' into 164-2FA-two-factor-auth
asbiin Jan 7, 2018
06612eb
Review AddGoogle2faSecretToUsers
asbiin Jan 7, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,6 @@ AWS_SECRET=
AWS_REGION=us-east-1
AWS_BUCKET=
AWS_SERVER=

# Enable Two Factor Authentication
2FA_ENABLED=false
2 changes: 2 additions & 0 deletions .env.travis
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ DB_TEST_PASSWORD=
CACHE_DRIVER=array
SESSION_DRIVER=array
QUEUE_DRIVER=sync

2FA_ENABLED=false
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ monica.sublime-workspace
/storage/oauth-private.key
/storage/oauth-public.key
.DS_Store
npm-debug.log.*
1 change: 1 addition & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ UNRELEASED CHANGES:
* Display missing page when loading a contact that does not exist
* Add ability to filter contacts by more than one tag
* Change the structure of the dashboard
* Add two factor authentication ability

RELEASED VERSIONS:

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ Scott Williams @scott-joe
Craig Davison @davisonio <[email protected]>
Michael Heap @mheap <[email protected]>
Matthew Du Pont @mattdp <[email protected]>
Alexis Saettler @asbiin
Alexis Saettler @asbiin <[email protected]>
83 changes: 83 additions & 0 deletions app/Console/Commands/Deactivate2FA.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace App\Console\Commands;

use App\User;
use Illuminate\Console\Command;

class Deactivate2FA extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = '2fa:deactivate {--email= : The email of the user to deactivate 2FA} {--force : run without asking for confirmation}';

/**
* The console command description.
*
* @var string
*/
protected $description = 'Deactivate 2FA for this user';

/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}

/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
// retrieve the email from the option
$email = $this->option('email');

// if no email was passed to the option, prompt the user to enter the email
if (! $email) {
$email = $this->ask('what is the user\'s email?');
}

// retrieve the user with the specified email
$user = User::where('email', $email)->first();

if (! $user) {
// show an error and exist if the user does not exist
$this->error('No user with that email.');

return;
}
if (is_null($user->google2fa_secret)) {
// show an error and exist if the user does not exist
$this->error('2FA is currently not activated for this user.');

return;
}

// Print a warning
$this->info('2FA will be deactivated for '.$user->email);
$this->info('This action can\'t be cancelled.');

// ask for confirmation if not forced
if (! $this->option('force') && ! $this->confirm('Do you wish to continue?')) {
return;
}

// remove google2fa_secret key
$user->google2fa_secret = null;

// save the user
$user->save();

// show the new secret key
$this->info('2FA has been deactivated for '.$user->email);
}
}
1 change: 1 addition & 0 deletions app/Console/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Kernel extends ConsoleKernel
'App\Console\Commands\ImportVCards',
'App\Console\Commands\PingVersionServer',
'App\Console\Commands\SetupTest',
'App\Console\Commands\Deactivate2FA',
'App\Console\Commands\GetVersion',
];

Expand Down
2 changes: 1 addition & 1 deletion app/Http/Controllers/Auth/PasswordChangeController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class PasswordChangeController extends Controller
{
use RedirectsUsers;

protected $redirectTo = '/settings';
protected $redirectTo = '/settings/security';

/**
* Get usefull parameters from request.
Expand Down
144 changes: 144 additions & 0 deletions app/Http/Controllers/Settings/MultiFAController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

namespace App\Http\Controllers\Settings;

use Google2FA;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\RedirectsUsers;
use PragmaRX\Google2FALaravel\Support\Authenticator;

class MultiFAController extends Controller
{
use RedirectsUsers;

protected $redirectTo = '/settings/security';

/**
* Session var name to store secret code.
*/
private const SESSION_TFA_SECRET = '2FA_secret';

/**
* Create a new authentication controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('web');
}

/**
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function enableTwoFactor(Request $request)
{
//generate new secret
$secret = $this->generateSecret();

$user = $request->user();

//generate image for QR barcode
$imageDataUri = Google2FA::getQRCodeInline(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it's an issue, but static analysis says that this is an instance method, called statically

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, we should use app('pragmarx.google2fa')->getQRCodeInline instead.
Thanks !
Do you want to open an issue ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or just add it to the (great) PR #878

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have added

$request->getHttpHost(),
$user->email,
$secret,
200
);

$request->session()->put(self::SESSION_TFA_SECRET, $secret);

return view('settings.security.2fa-enable', ['image' => $imageDataUri, 'secret' => $secret]);
}

/**
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function validateTwoFactor(Request $request)
{
$this->validate($request, [
'one_time_password' => 'required',
]);

//retrieve secret
$secret = $request->session()->pull(self::SESSION_TFA_SECRET);

$authenticator = app(Authenticator::class)->boot($request);

if ($authenticator->verifyGoogle2FA($secret, $request['one_time_password'])) {
//get user
$user = $request->user();

//encrypt and then save secret
$user->google2fa_secret = $secret;
$user->save();

$authenticator->login();

return redirect($this->redirectPath())
->with('status', trans('settings.2fa_enable_success'));
}

$authenticator->logout();

return redirect($this->redirectPath())
->withErrors(trans('settings.2fa_enable_error'));
}

/**
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function disableTwoFactor(Request $request)
{
return view('settings.security.2fa-disable');
}

/**
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function deactivateTwoFactor(Request $request)
{
$this->validate($request, [
'one_time_password' => 'required',
]);

$user = $request->user();

//retrieve secret
$secret = $user->google2fa_secret;

$authenticator = app(Authenticator::class)->boot($request);

if ($authenticator->verifyGoogle2FA($secret, $request['one_time_password'])) {

//make secret column blank
$user->google2fa_secret = null;
$user->save();

$authenticator->logout();

return redirect($this->redirectPath())
->with('status', trans('settings.2fa_disable_success'));
}

return redirect($this->redirectPath())
->withErrors(trans('settings.2fa_disable_error'));
}

/**
* Generate a secret key in Base32 format.
*
* @return string
*/
private function generateSecret()
{
$google2fa = app('pragmarx.google2fa');

return $google2fa->generateSecretKey(32);
}
}
6 changes: 6 additions & 0 deletions app/Http/Controllers/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use App\Http\Requests\SettingsRequest;
use Illuminate\Support\Facades\Storage;
use App\Http\Requests\InvitationRequest;
use PragmaRX\Google2FALaravel\Support\Authenticator;

class SettingsController extends Controller
{
Expand Down Expand Up @@ -430,4 +431,9 @@ public function api()
{
return view('settings.api.index');
}

public function security(Request $request)
{
return view('settings.security.index', ['is2FAActivated' => (new Authenticator($request))->isActivated()]);
}
}
1 change: 1 addition & 0 deletions app/Http/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,6 @@ class Kernel extends HttpKernel
//'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'throttle' => \App\Http\Middleware\ThrottleRequestsMiddleware::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'2fa' => \PragmaRX\Google2FALaravel\Middleware::class,
];
}
30 changes: 28 additions & 2 deletions app/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class User extends Authenticatable
* @var array
*/
protected $fillable = [
'first_name', 'last_name', 'email', 'password', 'timezone', 'locale', 'currency_id', 'fluid_container', 'name_order',
'first_name', 'last_name', 'email', 'password', 'timezone', 'locale', 'currency_id', 'fluid_container', 'name_order', 'google2fa_secret',
];

/**
Expand All @@ -32,7 +32,7 @@ class User extends Authenticatable
* @var array
*/
protected $hidden = [
'password', 'remember_token',
'password', 'remember_token', 'google2fa_secret',
];

/**
Expand Down Expand Up @@ -145,4 +145,30 @@ public function hasAlreadyRatedToday()

return true;
}

/**
* Ecrypt the user's google_2fa secret.
*
* @param string $value
* @return string
*/
public function setGoogle2faSecretAttribute($value)
{
$this->attributes['google2fa_secret'] = encrypt($value);
}

/**
* Decrypt the user's google_2fa secret.
*
* @param string $value
* @return string
*/
public function getGoogle2faSecretAttribute($value)
{
if (is_null($value)) {
return $value;
}

return decrypt($value);
}
}
Loading