Skip to content

Commit 0b18886

Browse files
committed
Add OIDC Connect
1 parent 106f7f2 commit 0b18886

15 files changed

Lines changed: 280 additions & 7 deletions

File tree

.rnd

1 KB
Binary file not shown.

app/Filament/Pages/ManageGeneralSettings.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Filament\Pages;
44

5+
use App\Models\Role;
56
use App\Settings\GeneralSettings;
67
use Filament\Forms\Components\Card;
78
use Filament\Forms\Components\Checkbox;
@@ -77,6 +78,12 @@ protected function getFormSchema(): array
7778
->helperText(__('The language used by the platform.'))
7879
->searchable()
7980
->options($this->getLanguages()),
81+
82+
Select::make('default_role')
83+
->label(__('Default role'))
84+
->helperText(__('The platform default role (used mainly in OIDC Connect).'))
85+
->searchable()
86+
->options(Role::all()->pluck('name', 'id')->toArray()),
8087
]),
8188
]),
8289
]),
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
namespace App\Http\Controllers\Auth;
4+
5+
use App\Http\Controllers\Controller;
6+
use App\Models\Role;
7+
use App\Models\User;
8+
use App\Settings\GeneralSettings;
9+
use Illuminate\Http\Request;
10+
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
11+
use League\OAuth2\Client\Provider\GenericProvider;
12+
13+
class OidcAuthController extends Controller
14+
{
15+
private $client;
16+
17+
public function __construct()
18+
{
19+
$this->client = new GenericProvider([
20+
'clientId' => config('services.oidc.client_id'),
21+
'clientSecret' => config('services.oidc.client_secret'),
22+
'redirectUri' => config('services.oidc.redirect_uri'),
23+
'urlAuthorize' => config('services.oidc.url_authorize'),
24+
'urlAccessToken' => config('services.oidc.url_access_token'),
25+
'urlResourceOwnerDetails' => config('services.oidc.url_resource_owner_details'),
26+
'scopes' => config('services.oidc.scope')
27+
]);
28+
}
29+
30+
public function redirect()
31+
{
32+
$authUrl = $this->client->getAuthorizationUrl();
33+
return redirect($authUrl);
34+
}
35+
36+
public function callback(Request $request)
37+
{
38+
try {
39+
$accessToken = $this->client->getAccessToken('authorization_code', [
40+
'code' => $request->input('code')
41+
]);
42+
$user = $this->client->getResourceOwner($accessToken);
43+
44+
// Perform any additional validation or user creation here
45+
if ($user) {
46+
$data = $user->toArray();
47+
$user = User::where('email', $data['email'])->first();
48+
if (!$user) {
49+
$user = User::create([
50+
'name' => $data['given_name'] . ' ' . $data['family_name'],
51+
'email' => $data['email'],
52+
'oidc_username' => $data['preferred_username'],
53+
'email_verified_at' => $data['email_verified'] ? now() : null,
54+
'type' => 'oidc',
55+
'oidc_sub' => $data['sub'],
56+
'password' => null
57+
]);
58+
$defaultRoleSettings = app(GeneralSettings::class)->default_role;
59+
if ($defaultRoleSettings && $defaultRole = Role::where('id', $defaultRoleSettings)->first()) {
60+
$user->syncRoles([$defaultRole]);
61+
}
62+
} else {
63+
$user->update([
64+
'name' => $data['given_name'] . ' ' . $data['family_name'],
65+
'email' => $data['email'],
66+
'oidc_username' => $data['preferred_username'],
67+
'type' => 'oidc',
68+
'oidc_sub' => $data['sub'],
69+
'password' => null
70+
]);
71+
$user->refresh();
72+
}
73+
74+
// Log the user in
75+
auth()->login($user);
76+
77+
return redirect()->intended();
78+
}
79+
session()->flash('oidc_error');
80+
return redirect()->route('login');
81+
} catch (IdentityProviderException $e) {
82+
session()->flash('oidc_error');
83+
return redirect()->route('login');
84+
}
85+
}
86+
}

app/Models/User.php

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,10 @@ class User extends Authenticatable implements MustVerifyEmail, FilamentUser
3434
'name',
3535
'email',
3636
'password',
37-
'creation_token'
37+
'creation_token',
38+
'type',
39+
'oidc_username',
40+
'email_verified_at',
3841
];
3942

4043
/**
@@ -61,12 +64,16 @@ public static function boot()
6164
parent::boot();
6265

6366
static::creating(function (User $item) {
64-
$item->password = bcrypt(uniqid());
65-
$item->creation_token = Uuid::uuid4()->toString();
67+
if ($item->type == 'db') {
68+
$item->password = bcrypt(uniqid());
69+
$item->creation_token = Uuid::uuid4()->toString();
70+
}
6671
});
6772

6873
static::created(function (User $item) {
69-
$item->notify(new UserCreatedNotification($item));
74+
if ($item->type == 'db') {
75+
$item->notify(new UserCreatedNotification($item));
76+
}
7077
});
7178
}
7279

app/Settings/GeneralSettings.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ class GeneralSettings extends Settings
1212
public string|null $site_logo;
1313
public string|null $enable_social_login;
1414
public string|null $site_language;
15+
public string|null $default_role;
1516

1617
public static function group(): string
1718
{

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"laravel/framework": "^9.19",
2020
"laravel/sanctum": "^3.0",
2121
"laravel/tinker": "^2.7",
22+
"league/oauth2-client": "^2.6",
2223
"maatwebsite/excel": "^3.1",
2324
"owenvoke/blade-fontawesome": "^2.1",
2425
"protonemedia/laravel-verify-new-email": "^1.6",

composer.lock

Lines changed: 71 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/services.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,16 @@
5555
'redirect' => env('TWITTER_CLIENT_CALLBACK')
5656
],
5757

58+
'oidc' => [
59+
'is_enabled' => env('OIDC_IS_ENABLED'),
60+
'client_id' => env('OIDC_CLIENT_ID'),
61+
'client_secret' => env('OIDC_CLIENT_SECRET'),
62+
'discovery_endpoint' => env('OIDC_DISCOVERY_ENDPOINT'),
63+
'redirect_uri' => env('OIDC_REDIRECT_URI'),
64+
'url_authorize' => env('OIDC_URL_AUTHORIZE'),
65+
'url_access_token' => env('OIDC_URL_ACCESS_TOKEN'),
66+
'url_resource_owner_details' => env('OIDC_URL_RESOURCE_OWNER_DETAILS'),
67+
'scope' => explode(",", env('OIDC_SCOPE')),
68+
],
69+
5870
];
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
use Illuminate\Database\Migrations\Migration;
4+
use Illuminate\Database\Schema\Blueprint;
5+
use Illuminate\Support\Facades\Schema;
6+
7+
return new class extends Migration
8+
{
9+
/**
10+
* Run the migrations.
11+
*
12+
* @return void
13+
*/
14+
public function up()
15+
{
16+
Schema::table('users', function (Blueprint $table) {
17+
$table->string('password')->nullable(true)->change();
18+
$table->string('type')->default('db');
19+
$table->string('oidc_username')->nullable();
20+
$table->string('oidc_sub')->nullable();
21+
});
22+
}
23+
24+
/**
25+
* Reverse the migrations.
26+
*
27+
* @return void
28+
*/
29+
public function down()
30+
{
31+
Schema::table('users', function (Blueprint $table) {
32+
$table->string('password')->nullable(false)->change();
33+
$table->dropColumn('type');
34+
$table->dropColumn('oidc_username');
35+
$table->dropColumn('oidc_sub');
36+
});
37+
}
38+
};

database/seeders/DefaultUserSeeder.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ class DefaultUserSeeder extends Seeder
1616
public function run()
1717
{
1818
if (User::where('email', 'john.doe@helper.app')->count() == 0) {
19-
User::create([
19+
$user = User::create([
2020
'name' => 'John DOE',
2121
'email' => 'john.doe@helper.app',
2222
'password' => bcrypt('Passw@rd'),
2323
'email_verified_at' => now()
2424
]);
25+
$user->creation_token = null;
26+
$user->save();
2527
}
2628
}
2729
}

0 commit comments

Comments
 (0)