Skip to content

Commit

Permalink
feat: login with microsoft (#46) (#50)
Browse files Browse the repository at this point in the history
* feat: login using microsoft account

* fix: do not show menu when empty

* style: formatting

* feat: migration to aad column

* fix: change Request Type

* fix: extra checks when login in with openid

* feat: translated message

* fix: more consistent naming

* feat: changed routes + set email verified to null

* feat: ajax call from login page

* fix: return value email notification

* feat: translate messages

* fix: message translation

* feat: block user if mail not send by you

* feat: added translations to verify email

* feat: create user now always has email

* style: formatting

* feat: added translations + removed unused view

* feat: dont use event

* style: formatting

---------

Co-authored-by: Xander Schuurman <[email protected]>
  • Loading branch information
64knl and keeama13 authored Jul 17, 2023
1 parent cfd3f5a commit 6ac66a8
Show file tree
Hide file tree
Showing 18 changed files with 311 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('cms_user', function (Blueprint $table) {
$table->timestamp('email_verified_at')->nullable()->default(null);
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::table('cms_user', function (Blueprint $table) {
$table->dropColumn('email_verified_at');
});
}
};
9 changes: 8 additions & 1 deletion lang/en/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,12 @@
'failed' => 'These credentials do not match our records.',
'password' => 'The provided password is incorrect.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',

'verify_email' => 'Please verify your email address.',
'verify_email_header' => 'Login to',
'verify_email_link' => 'Click the button to verify your email.',
'verify_email_button' => 'Verify email',
'verify_email_resend' => 'Resend verification email',
'verify_email_link_sent' => 'A fresh verification link has been sent to your email address.',
'verify_wrong_email' => 'Click here if this message was not send by you.',
'block_account_message' => 'The account has been blocked.',
];
9 changes: 8 additions & 1 deletion lang/nl/auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,12 @@
'failed' => 'Deze combinatie van e-mailadres en wachtwoord is niet geldig.',
'throttle' => 'Te veel mislukte loginpogingen. Probeer het over :seconds seconden nogmaals.',
'password' => 'Het opgegeven wachtwoord is onjuist.',

'verify_email' => 'Verifieer uw e-mailadres.',
'verify_email_header' => 'Inloggen bij',
'verify_email_button' => 'Bevestig e-mailadres',
'verify_email_link' => 'Klik op onderstaande link om je e-mailadres te bevestigen.',
'verify_email_resend' => 'Verificatiemail opnieuw verzenden',
'verify_email_link_sent' => 'Er is een nieuwe verificatielink naar jouw e-mailadres verzonden.',
'verify_wrong_email' => 'Klik hier als dit bericht niet van jou komt.',
'block_account_message' => 'Account succesvol geblokkeerd.',
];
15 changes: 15 additions & 0 deletions resources/views/emails/verify-email.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{-- blade-formatter-disable --}}
<x-mail::message>
# {{ __('siteboss::auth.verify_email_header') }} {{ config('app.name') }}

{{ __('siteboss::auth.verify_email_link') }}

<x-mail::button :url="$url">
{{ __('siteboss::auth.verify_email_button') }}
</x-mail::button>

Thanks,<br>
{{ config('app.name') }}

[<h4>{{__('siteboss::auth.verify_wrong_email')}}</h4>]({{$blockUrl}})
</x-mail::message>
7 changes: 7 additions & 0 deletions resources/views/mail/admin/account-blocked.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@component('mail::message')

<h4>De gebruiker met ID: {{ $user->id }} en e-mail: {{$user->email}} is geblokkeerd.</h4>
<p>Dit is gegaan doormiddel van de blokkeer link in de verificatie email.
</p>

@endcomponent
20 changes: 17 additions & 3 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

use Illuminate\Support\Facades\Route;
use NotFound\Framework\Http\Controllers\AboutController;
use NotFound\Framework\Http\Controllers\Auth\EmailVerificationNotificationController;
use NotFound\Framework\Http\Controllers\Auth\EmailVerificationPromptController;
use NotFound\Framework\Http\Controllers\Auth\VerifyEmailController;
use NotFound\Framework\Http\Controllers\ContentBlocks\ContentBlockController;
use NotFound\Framework\Http\Controllers\Forms\DataController;
use NotFound\Framework\Http\Controllers\Forms\DownloadController;
Expand All @@ -23,10 +26,17 @@
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::prefix(config('siteboss.api_prefix'))->group(function () {
// Unauthenticated routes
Route::prefix('api')->group(function () {
Route::get('email/verify', [EmailVerificationPromptController::class, '__invoke'])
->middleware('auth')
->name('verification.notice');

Route::get('email/verify/{id}/{hash}', [VerifyEmailController::class, '__invoke'])
->middleware(['signed', 'throttle:6,1'])
->name('verification.verify');

// Unauthenticated routes
Route::namespace('Forms')->group(function () {
Route::post('forms/{form:id}/{langurl}', [DataController::class, 'create'])->middleware(ProtectAgainstSpam::class)->name('formbuilder.post');
Route::get('fields/{id}', [FieldController::class, 'readOneJson']);
Expand All @@ -35,13 +45,17 @@
});
});

Route::post('{locale}/email/verification-notification', [EmailVerificationNotificationController::class, '__invoke'])
->middleware(['throttle:6,1', 'auth', 'set-forget-locale'])
->name('verification.send');

Route::get('{locale}/oidc', [InfoController::class, 'oidc'])->where('name', '[A-Za-z]{2}');

// Settings for the login page
Route::get('settings', [InfoController::class, 'settings']);

// Authenticated routes
Route::group(['middleware' => ['auth:openid', 'api']], function () {
Route::group(['middleware' => ['auth:openid', 'api', 'verified']], function () {
// Language for messages (not the language used for storing data)
Route::group(['prefix' => '/{locale}', 'middleware' => 'set-forget-locale'], function () {
Route::get('info', [InfoController::class, 'index']);
Expand Down
44 changes: 44 additions & 0 deletions src/Auth/Middleware/EnsureEmailIsVerified.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

namespace NotFound\Framework\Auth\Middleware;

use Closure;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Support\Facades\Redirect;

class EnsureEmailIsVerified
{
/**
* Specify the redirect route for the middleware.
*
* @param string $route
* @return string
*/
public static function redirectTo($route)
{
return static::class.':'.$route;
}

/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param string|null $redirectToRoute
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse|null
*/
public function handle($request, Closure $next, $redirectToRoute = null)
{
if (! $request->user() ||
($request->user() instanceof MustVerifyEmail &&
! $request->user()->hasVerifiedEmail())) {
return [
'result' => 'error',
'message' => __('siteboss::auth.verify_email'),
'buttonText' => __('siteboss::auth.verify_email_resend'),
'link' => route('verification.send', ['locale' => app()->getLocale()]),
];
}

return $next($request);
}
}
16 changes: 16 additions & 0 deletions src/FrameworkServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,12 @@

namespace NotFound\Framework;

use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Blade;
use Illuminate\Support\ServiceProvider;
use NotFound\Framework\Models\Lang;
use NotFound\Framework\View\Components\Forms\Form;

class FrameworkServiceProvider extends ServiceProvider
Expand All @@ -29,6 +33,18 @@ public function boot(): void
__DIR__.'/Providers/AuthServiceProvider.php' => app_path('Providers/AuthServiceProvider.php'),
__DIR__.'/../database/seeders/DatabaseSeeder.php' => database_path('seeders/DatabaseSeeder.php'),
], 'siteboss-framework');

VerifyEmail::toMailUsing(function (object $notifiable, string $url) {

// todo: get value from users current lang;
App::setLocale(Lang::current()->url);

$blockUrl = $url.'&block=1';

return (new MailMessage)
->subject(__('siteboss::auth.verify_email_button').' '.config('app.name'))
->markdown('siteboss::emails.verify-email', ['url' => $url, 'blockUrl' => $blockUrl]);
});
}

public function register(): void
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace NotFound\Framework\Http\Controllers\Auth;

use Illuminate\Http\Request;
use NotFound\Framework\Http\Controllers\Controller;

class EmailVerificationNotificationController extends Controller
{
public function __invoke(Request $request)
{
$request->user()->sendEmailVerificationNotification();

return ['status' => 'ok', 'message' => __('siteboss::auth.verify_email_link_sent')];
}
}
22 changes: 22 additions & 0 deletions src/Http/Controllers/Auth/EmailVerificationPromptController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace NotFound\Framework\Http\Controllers\Auth;

use Illuminate\Http\Request;
use NotFound\Framework\Http\Controllers\Controller;
use NotFound\Framework\Providers\RouteServiceProvider;

class EmailVerificationPromptController extends Controller
{
/**
* Display the email verification prompt.
*
* @return mixed
*/
public function __invoke(Request $request)
{
return $request->user()->hasVerifiedEmail()
? redirect()->intended(RouteServiceProvider::HOME)
: view('siteboss::auth.verify-email');
}
}
48 changes: 48 additions & 0 deletions src/Http/Controllers/Auth/VerifyEmailController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace NotFound\Framework\Http\Controllers\Auth;

use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Auth\Events\Verified;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use NotFound\Framework\Http\Controllers\Controller;
use NotFound\Framework\Mail\Admin\AccountBlocked;
use NotFound\Framework\Models\CmsUser;

class VerifyEmailController extends Controller
{
/**
* Mark the authenticated user's email address as verified.
*
* @return \Illuminate\Http\RedirectResponse
*/
public function __invoke(Request $request)
{
$user = CmsUser::find($request->route('id'));

if ($request->query('block')) {
$user->enabled = 0;
$user->email_verified_at = null;
$user->save();

Mail::to(env('SB_ADMIN_EMAIL'))->send(new AccountBlocked($user));

return ['status' => 'ok', 'message' => __('siteboss::auth.block_account_message')];
}

if (! $user) {
throw new AuthorizationException;
}

if (! hash_equals((string) $request->route('hash'), sha1($user->getEmailForVerification())) || ! $user->enabled) {
throw new AuthorizationException;
}

if ($user->markEmailAsVerified()) {
event(new Verified($user));
}

return redirect('/siteboss')->with('verified', true);
}
}
12 changes: 7 additions & 5 deletions src/Http/Controllers/InfoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,14 @@ private function menu()

if ($menuitem->level !== 0) {
$lastKey = array_key_last($orderedMenu);
if (! $orderedMenu[$lastKey]->submenu) {
$orderedMenu[$lastKey]->submenu = [];
}
if ($lastKey !== null) {
if (! $orderedMenu[$lastKey]->submenu) {
$orderedMenu[$lastKey]->submenu = [];
}

$orderedMenu[$lastKey]->path = '';
$orderedMenu[$lastKey]->submenu[] = $menuObj;
$orderedMenu[$lastKey]->path = '';
$orderedMenu[$lastKey]->submenu[] = $menuObj;
}
} else {
$orderedMenu[] = $menuObj;
}
Expand Down
33 changes: 33 additions & 0 deletions src/Mail/Admin/AccountBlocked.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace NotFound\Framework\Mail\Admin;

use Illuminate\Mail\Mailable;
use NotFound\Framework\Models\CmsUser;

class AccountBlocked extends Mailable
{
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(
private CmsUser $user,
) {
}

/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('siteboss::mail.admin.account-blocked')
->subject('CMS: Account geblokkeerd')
->with([
'user' => $this->user,
]);
}
}
9 changes: 8 additions & 1 deletion src/Models/CmsUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace NotFound\Framework\Models;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User;
Expand Down Expand Up @@ -58,7 +59,7 @@
*
* @mixin \Eloquent
*/
class CmsUser extends User
class CmsUser extends User implements MustVerifyEmail
{
use HasFactory, Notifiable, SoftDeletes;

Expand Down Expand Up @@ -90,6 +91,7 @@ class CmsUser extends User
protected $casts = [
'properties' => 'object',
'preferences' => 'object',
'email_verified_at' => 'datetime',
];

public function groups()
Expand Down Expand Up @@ -210,4 +212,9 @@ public function hasLocalRole(string $role): bool

return $roles->contains($role);
}

public function getEmailVerifiedAttribute(): bool
{
return $this->email_verified_at ? true : false;
}
}
Loading

0 comments on commit 6ac66a8

Please sign in to comment.