Feat: Add OIDC config resolver and enhanced logging for app creation
- Introduced `OidcConfigResolver` to streamline client secret checks based on app type. - Enhanced logging in `OidcService` to provide detailed insights during app creation and error handling. - Updated UI to conditionally display client secret based on app type. - Added placeholder image support for app logos.
This commit is contained in:
parent
0b77f69818
commit
28f6da1a9a
24
app/Services/Applications/OIDC/OidcConfigResolver.php
Normal file
24
app/Services/Applications/OIDC/OidcConfigResolver.php
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Services\Applications\OIDC;
|
||||||
|
|
||||||
|
use App\Enums\ApplicationTypeEnum;
|
||||||
|
|
||||||
|
class OidcConfigResolver
|
||||||
|
{
|
||||||
|
private ?ApplicationTypeEnum $applicationType = null;
|
||||||
|
|
||||||
|
public function for(ApplicationTypeEnum $applicationType): OidcConfigResolver
|
||||||
|
{
|
||||||
|
$this->applicationType = $applicationType;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function hasClientSecret(): bool
|
||||||
|
{
|
||||||
|
return ApplicationTypeEnum::SPA !== $this->applicationType;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@
|
|||||||
use App\Services\{ApplicationLogoUploader, ConnectedAppService};
|
use App\Services\{ApplicationLogoUploader, ConnectedAppService};
|
||||||
use App\Services\Applications\OIDC\Factory\ClientCreationFactory;
|
use App\Services\Applications\OIDC\Factory\ClientCreationFactory;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Throwable;
|
use Throwable;
|
||||||
|
|
||||||
@ -27,6 +28,10 @@ public function __construct(
|
|||||||
*/
|
*/
|
||||||
public function createApp(StoreOIDCAppData $data): CreatedApplicationData
|
public function createApp(StoreOIDCAppData $data): CreatedApplicationData
|
||||||
{
|
{
|
||||||
|
Log::info('Creating OIDC app', [
|
||||||
|
'name' => $data->name,
|
||||||
|
'type' => $data->type,
|
||||||
|
]);
|
||||||
try {
|
try {
|
||||||
DB::beginTransaction();
|
DB::beginTransaction();
|
||||||
$logo = $this->logoUploader->store($data->logo);
|
$logo = $this->logoUploader->store($data->logo);
|
||||||
@ -47,12 +52,23 @@ public function createApp(StoreOIDCAppData $data): CreatedApplicationData
|
|||||||
// remove sensitive data
|
// remove sensitive data
|
||||||
$appData->settings = null;
|
$appData->settings = null;
|
||||||
|
|
||||||
|
Log::info('OIDC app created', [
|
||||||
|
'name' => $data->name,
|
||||||
|
'type' => $data->type,
|
||||||
|
'clientId' => isset($clientData->clientId),
|
||||||
|
'clientSecret' => isset($clientData->clientSecret),
|
||||||
|
]);
|
||||||
|
|
||||||
return new CreatedApplicationData(
|
return new CreatedApplicationData(
|
||||||
application: $appData,
|
application: $appData,
|
||||||
clientCredentials: $clientData,
|
clientCredentials: $clientData,
|
||||||
);
|
);
|
||||||
} catch (Throwable $e) {
|
} catch (Throwable $e) {
|
||||||
DB::rollBack();
|
DB::rollBack();
|
||||||
|
Log::error('Failed to create OIDC app', [
|
||||||
|
'name' => $data->name,
|
||||||
|
'type' => $data->type,
|
||||||
|
]);
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,6 +34,7 @@ function () use ($data): ConnectedAppData {
|
|||||||
$data->toArray()
|
$data->toArray()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Create a permission for this app
|
||||||
$this->permissionService->add(ConnectedAppData::from($connectedApp), ConnectedAppPermissonEnum::Use);
|
$this->permissionService->add(ConnectedAppData::from($connectedApp), ConnectedAppPermissonEnum::Use);
|
||||||
|
|
||||||
return ConnectedAppData::from($connectedApp);
|
return ConnectedAppData::from($connectedApp);
|
||||||
|
|||||||
BIN
public/images/app-icon-placeholder.png
Normal file
BIN
public/images/app-icon-placeholder.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.0 KiB |
@ -7,8 +7,8 @@
|
|||||||
use App\Livewire\Concerns\Choices\{ChoiceField, WithSearchableChoices};
|
use App\Livewire\Concerns\Choices\{ChoiceField, WithSearchableChoices};
|
||||||
use App\Livewire\Concerns\WithRepeaterFields;
|
use App\Livewire\Concerns\WithRepeaterFields;
|
||||||
use App\Livewire\Forms\StoreOIDCAppForm;
|
use App\Livewire\Forms\StoreOIDCAppForm;
|
||||||
use App\Services\{Applications\OIDC\OidcService, RoleService};
|
use App\Services\{Applications\OIDC\OidcConfigResolver, Applications\OIDC\OidcService, RoleService};
|
||||||
use Livewire\Attributes\{Url};
|
use Livewire\Attributes\{Computed, Url};
|
||||||
use Livewire\Component;
|
use Livewire\Component;
|
||||||
use Livewire\WithFileUploads;
|
use Livewire\WithFileUploads;
|
||||||
|
|
||||||
@ -34,12 +34,14 @@ class extends Component {
|
|||||||
public ApplicationTypeEnum $applicationType;
|
public ApplicationTypeEnum $applicationType;
|
||||||
private RoleService $roleService;
|
private RoleService $roleService;
|
||||||
private OidcService $oidcService;
|
private OidcService $oidcService;
|
||||||
|
private OidcConfigResolver $configResolver;
|
||||||
|
|
||||||
|
|
||||||
public function boot(RoleService $roleService, OidcService $oidcService): void
|
public function boot(RoleService $roleService, OidcService $oidcService, OidcConfigResolver $configResolver): void
|
||||||
{
|
{
|
||||||
$this->roleService = $roleService;
|
$this->roleService = $roleService;
|
||||||
$this->oidcService = $oidcService;
|
$this->oidcService = $oidcService;
|
||||||
|
$this->configResolver = $configResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
@ -60,6 +62,8 @@ public function save(bool $goBack = true): void
|
|||||||
function () {
|
function () {
|
||||||
$data = StoreOIDCAppData::fromArray($this->applicationType, $this->form->pull());
|
$data = StoreOIDCAppData::fromArray($this->applicationType, $this->form->pull());
|
||||||
$appdata = $this->oidcService->createApp($data);
|
$appdata = $this->oidcService->createApp($data);
|
||||||
|
|
||||||
|
// Show the credentials
|
||||||
$this->created = true;
|
$this->created = true;
|
||||||
$this->clientId = $appdata->clientCredentials->clientId;
|
$this->clientId = $appdata->clientCredentials->clientId;
|
||||||
$this->clientSecret = $appdata->clientCredentials->clientSecret;
|
$this->clientSecret = $appdata->clientCredentials->clientSecret;
|
||||||
@ -111,40 +115,43 @@ protected function choiceFields(): array
|
|||||||
),
|
),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Computed]
|
||||||
|
public function hasClientSecret(): bool
|
||||||
|
{
|
||||||
|
return $this->configResolver->for($this->applicationType)->hasClientSecret();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
@if($created && $clientId && $clientSecret)
|
@if($created)
|
||||||
<x-shared.card
|
<x-shared.card
|
||||||
title="Application Created"
|
title="Application Created"
|
||||||
icon="lucide-check-circle"
|
icon="lucide-check-circle"
|
||||||
>
|
>
|
||||||
<div class="flex w-full justify-center items-center pt-6">
|
<div class="flex w-full justify-center items-center pt-6">
|
||||||
<article class="mx-auto flex items-center gap-4">
|
<article class="mx-auto flex items-center gap-4">
|
||||||
<x-mary-avatar :image="$app->logo" alt="App logo" class="w-14! rounded-lg! p-2"/>
|
<x-mary-avatar :image="$app->logo ? asset($app->logo) : asset('images/app-icon-placeholder.png')"
|
||||||
|
alt="App logo"
|
||||||
|
class="w-14! rounded-lg! p-2"/>
|
||||||
<h1 class="text-2xl font-medium">{{$app->name}}</h1>
|
<h1 class="text-2xl font-medium">{{$app->name}}</h1>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
<div class="space-y-6 p-6">
|
<div class="space-y-6 p-6">
|
||||||
|
|
||||||
<x-mary-alert
|
|
||||||
title="Save these credentials"
|
|
||||||
description="The client secret will only be displayed once."
|
|
||||||
class="alert-warning alert-soft text-yellow-700"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<x-mary-input
|
<x-mary-input
|
||||||
label="Client ID"
|
label="Client ID"
|
||||||
:value="$clientId"
|
:value="$clientId"
|
||||||
readonly
|
readonly
|
||||||
/>
|
/>
|
||||||
|
@if($this->hasClientSecret)
|
||||||
<x-mary-input
|
<x-mary-alert
|
||||||
label="Client Secret"
|
title="Save these credentials"
|
||||||
:value="$clientSecret"
|
description="The client secret will only be displayed once."
|
||||||
readonly
|
class="alert-warning alert-soft text-yellow-700"
|
||||||
/>
|
/>
|
||||||
|
<x-mary-password label="Client Secret" :value="$clientSecret" readonly right/>
|
||||||
|
@endif
|
||||||
|
|
||||||
<div class="flex justify-end gap-4">
|
<div class="flex justify-end gap-4">
|
||||||
<x-mary-button
|
<x-mary-button
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user