363 lines
14 KiB
PHP
363 lines
14 KiB
PHP
<?php
|
|
|
|
namespace Paymenter\Extensions\Others\Authentik;
|
|
|
|
use App\Attributes\ExtensionMeta;
|
|
use App\Classes\Extension\Extension;
|
|
use App\Events\SocialiteWasCalled;
|
|
use App\Helpers\ExtensionHelper;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Illuminate\Support\Facades\View;
|
|
use Illuminate\Support\Facades\Lang;
|
|
use Paymenter\Extensions\Others\Authentik\Providers\AuthentikProvider;
|
|
use Paymenter\Extensions\Others\Authentik\Http\Controllers\AuthentikController;
|
|
use Paymenter\Extensions\Others\Authentik\Middleware\ForceAuthentikOnly;
|
|
use Paymenter\Extensions\Others\Authentik\Livewire\AuthentikLoginOverride;
|
|
use Livewire\Livewire;
|
|
|
|
#[ExtensionMeta(
|
|
name: 'Authentik SSO - Forclus.NET',
|
|
description: 'Integración completa con Authentik para autenticación SSO - Desarrollado por ForclusNET',
|
|
version: '1.0.0',
|
|
author: 'ForclusNET',
|
|
url: 'https://forclus.net'
|
|
)]
|
|
class Authentik extends Extension
|
|
{
|
|
public function __construct(public $config = []) {}
|
|
|
|
/**
|
|
* Get all the configuration for the extension
|
|
*
|
|
* @param array $values
|
|
* @return array
|
|
*/
|
|
public function getConfig($values = [])
|
|
{
|
|
return [
|
|
[
|
|
'name' => 'enabled',
|
|
'label' => __('authentik::messages.authentik_enabled'),
|
|
'description' => __('authentik::messages.authentik_enabled'),
|
|
'type' => 'checkbox',
|
|
'database_type' => 'boolean',
|
|
'default' => false,
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'client_id',
|
|
'label' => __('authentik::messages.authentik_client_id'),
|
|
'type' => 'text',
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'client_secret',
|
|
'label' => __('authentik::messages.authentik_client_secret'),
|
|
'type' => 'text',
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'base_url',
|
|
'label' => __('authentik::messages.authentik_base_url'),
|
|
'type' => 'text',
|
|
'required' => false,
|
|
'description' => __('authentik::messages.authentik_base_url_description'),
|
|
],
|
|
[
|
|
'name' => 'auto_create_users',
|
|
'label' => __('authentik::messages.authentik_auto_create_users'),
|
|
'description' => __('authentik::messages.authentik_auto_create_users_description'),
|
|
'type' => 'checkbox',
|
|
'database_type' => 'boolean',
|
|
'default' => true,
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'require_existing_user',
|
|
'label' => __('authentik::messages.authentik_require_existing_user'),
|
|
'description' => __('authentik::messages.authentik_require_existing_user_description'),
|
|
'type' => 'checkbox',
|
|
'database_type' => 'boolean',
|
|
'default' => false,
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'force_authentik_only',
|
|
'label' => __('authentik::messages.authentik_force_authentik_only'),
|
|
'description' => __('authentik::messages.authentik_force_authentik_only_description'),
|
|
'type' => 'checkbox',
|
|
'database_type' => 'boolean',
|
|
'default' => false,
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'button_text',
|
|
'label' => __('authentik::messages.authentik_button_text'),
|
|
'description' => __('authentik::messages.authentik_button_text_description'),
|
|
'type' => 'text',
|
|
'default' => __('authentik::messages.authentik_login_button'),
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'button_image',
|
|
'label' => __('authentik::messages.authentik_button_image'),
|
|
'description' => __('authentik::messages.authentik_button_image_description'),
|
|
'type' => 'text',
|
|
'default' => '',
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'button_image_alt',
|
|
'label' => __('authentik::messages.authentik_button_image_alt'),
|
|
'description' => __('authentik::messages.authentik_button_image_alt_description'),
|
|
'type' => 'text',
|
|
'default' => 'Authentik',
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'button_bg_color',
|
|
'label' => __('authentik::messages.authentik_button_bg_color'),
|
|
'description' => __('authentik::messages.authentik_button_bg_color_description'),
|
|
'type' => 'text',
|
|
'default' => '#3B82F6',
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'button_text_color',
|
|
'label' => __('authentik::messages.authentik_button_text_color'),
|
|
'description' => __('authentik::messages.authentik_button_text_color_description'),
|
|
'type' => 'text',
|
|
'default' => '#FFFFFF',
|
|
'required' => false,
|
|
],
|
|
[
|
|
'name' => 'callback_url',
|
|
'label' => __('authentik::messages.authentik_callback_url'),
|
|
'description' => __('authentik::messages.authentik_callback_url_description'),
|
|
'type' => 'text',
|
|
'default' => url('/oauth/authentik/callback'),
|
|
'required' => false,
|
|
'disabled' => true,
|
|
],
|
|
];
|
|
}
|
|
|
|
public function enabled()
|
|
{
|
|
// La extensión está activada
|
|
// Modificar automáticamente la vista de login
|
|
try {
|
|
$this->modifyLoginView();
|
|
\Log::info('Extensión Authentik activada - Vista de login modificada automáticamente');
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error al modificar la vista de login al activar la extensión: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function disabled()
|
|
{
|
|
// La extensión está desactivada
|
|
// Restaurar la vista de login original
|
|
try {
|
|
$this->restoreLoginView();
|
|
\Log::info('Extensión Authentik desactivada - Vista de login restaurada automáticamente');
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error al restaurar la vista de login al desactivar la extensión: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
public function boot()
|
|
{
|
|
// Registrar las rutas
|
|
$this->registerRoutes();
|
|
|
|
// Registrar las vistas y idiomas
|
|
View::addNamespace('authentik', __DIR__ . '/resources/views');
|
|
Lang::addNamespace('authentik', __DIR__ . '/resources/lang');
|
|
|
|
// Registrar el provider Authentik con Socialite
|
|
Event::listen(SocialiteWasCalled::class, function (SocialiteWasCalled $event) {
|
|
$event->extendSocialite('authentik', AuthentikProvider::class);
|
|
});
|
|
|
|
// Registrar los permisos
|
|
Event::listen('permissions', function () {
|
|
return [
|
|
'admin.authentik.view' => 'Ver configuración de Authentik',
|
|
'admin.authentik.update' => 'Actualizar configuración de Authentik',
|
|
];
|
|
});
|
|
|
|
// Registrar los permisos API
|
|
Event::listen('api.permissions', function () {
|
|
return [
|
|
'admin.authentik.view' => 'Ver configuración de Authentik',
|
|
'admin.authentik.update' => 'Actualizar configuración de Authentik',
|
|
];
|
|
});
|
|
|
|
// El middleware está desactivado para evitar bucles de redirección
|
|
// La lógica de "force_authentik_only" se maneja directamente en la vista de login
|
|
// ExtensionHelper::registerMiddleware(ForceAuthentikOnly::class);
|
|
|
|
// Registrar el componente Livewire para el override del login
|
|
Livewire::component('authentik-login-override', AuthentikLoginOverride::class);
|
|
|
|
// Hook para modificar la página de login
|
|
Event::listen('view.login', function ($view) {
|
|
$extension = Extension::where('extension', 'Authentik')->first();
|
|
|
|
if ($extension && $extension->enabled) {
|
|
$settings = $extension->settings->pluck('value', 'key')->toArray();
|
|
|
|
if (!empty($settings['force_authentik_only'])) {
|
|
// Reemplazar el contenido de la vista de login
|
|
$view->with('forceAuthentikOnly', true);
|
|
$view->with('authentikEnabled', true);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Registrar las rutas de la extensión
|
|
*/
|
|
private function registerRoutes()
|
|
{
|
|
require __DIR__ . '/routes/web.php';
|
|
}
|
|
|
|
/**
|
|
* Prueba de la configuración Authentik
|
|
*/
|
|
public function testConfig()
|
|
{
|
|
$baseUrl = $this->config['base_url'] ?? '';
|
|
$clientId = $this->config['client_id'] ?? '';
|
|
$clientSecret = $this->config['client_secret'] ?? '';
|
|
|
|
if (empty($baseUrl) || empty($clientId) || empty($clientSecret)) {
|
|
return 'Configuración incompleta. Por favor, complete todos los campos requeridos.';
|
|
}
|
|
|
|
try {
|
|
// Prueba de conexión a la API Authentik
|
|
$response = \Http::timeout(10)
|
|
->get($baseUrl . '/api/v3/core/users/me/');
|
|
|
|
if ($response->successful()) {
|
|
return 'Configuración válida. Conexión a Authentik exitosa.';
|
|
} else {
|
|
return 'Error de conexión a Authentik: ' . $response->status();
|
|
}
|
|
} catch (\Exception $e) {
|
|
return 'Error de prueba: ' . $e->getMessage();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Modificar automáticamente la vista de login
|
|
*/
|
|
private function modifyLoginView()
|
|
{
|
|
$loginViewPath = base_path('themes/default/views/auth/login.blade.php');
|
|
|
|
if (!file_exists($loginViewPath)) {
|
|
\Log::warning('Vista de login no encontrada en: ' . $loginViewPath);
|
|
return false;
|
|
}
|
|
|
|
// Leer el contenido actual
|
|
$content = file_get_contents($loginViewPath);
|
|
|
|
// Verificar si ya está modificada
|
|
if (strpos($content, 'force_authentik_only') !== false) {
|
|
\Log::info('La vista de login ya está modificada.');
|
|
return true;
|
|
}
|
|
|
|
// Crear el contenido modificado
|
|
$newContent = '@php
|
|
// Verificar si el modo "force_authentik_only" está activado
|
|
$extension = \App\Models\Extension::where(\'extension\', \'Authentik\')->first();
|
|
$forceAuthentikOnly = false;
|
|
$authentikEnabled = false;
|
|
|
|
if ($extension && $extension->enabled) {
|
|
$settings = $extension->settings->pluck(\'value\', \'key\')->toArray();
|
|
$forceAuthentikOnly = !empty($settings[\'force_authentik_only\']);
|
|
$authentikEnabled = !empty($settings[\'client_id\']) && !empty($settings[\'client_secret\']) && !empty($settings[\'base_url\']);
|
|
}
|
|
@endphp
|
|
|
|
@if($forceAuthentikOnly && $authentikEnabled)
|
|
{{-- Mode Authentik uniquement --}}
|
|
<div class="mx-auto flex flex-col gap-2 mt-4 shadow-sm px-6 sm:px-14 pb-10 bg-primary-800 rounded-md xl:max-w-[40%] w-full">
|
|
<div class="flex flex-col items-center mt-4 mb-10">
|
|
<x-logo />
|
|
<h1 class="text-2xl text-center mt-2">{{ __(\'auth.sign_in_title\') }}</h1>
|
|
<p class="text-sm text-center mt-2 text-gray-300">
|
|
{{ __(\'authentik::messages.authentik_force_only_description\') }}
|
|
</p>
|
|
</div>
|
|
|
|
<a href="{{ route(\'oauth.authentik.redirect\') }}"
|
|
class="w-full flex items-center justify-center px-4 py-3 bg-blue-600 border border-transparent rounded-md font-semibold text-sm text-white uppercase tracking-widest hover:bg-blue-700 focus:bg-blue-700 active:bg-blue-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2 transition ease-in-out duration-150">
|
|
<svg class="w-5 h-5 mr-2" fill="currentColor" viewBox="0 0 20 20">
|
|
<path fill-rule="evenodd" d="M3 3a1 1 0 000 2v8a2 2 0 002 2h2.586l-1.293 1.293a1 1 0 101.414 1.414L10 15.414l2.293 2.293a1 1 0 001.414-1.414L12.414 15H15a2 2 0 002-2V5a1 1 0 100-2H3zm11.707 4.707a1 1 0 00-1.414-1.414L10 9.586 8.707 8.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z" clip-rule="evenodd"></path>
|
|
</svg>
|
|
{{ __(\'authentik::messages.authentik_login_button\') }}
|
|
</a>
|
|
</div>
|
|
@else
|
|
{{-- Mode normal --}}
|
|
' . $content . '
|
|
@endif';
|
|
|
|
// Crear backup
|
|
$backupPath = $loginViewPath . '.backup.' . date('Y-m-d-H-i-s');
|
|
file_put_contents($backupPath, $content);
|
|
\Log::info('Backup creado en: ' . $backupPath);
|
|
|
|
// Escribir el nuevo contenido
|
|
if (file_put_contents($loginViewPath, $newContent)) {
|
|
\Log::info('Vista de login modificada exitosamente.');
|
|
return true;
|
|
} else {
|
|
\Log::error('Error al modificar la vista de login.');
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Restaurar la vista de login original
|
|
*/
|
|
private function restoreLoginView()
|
|
{
|
|
$loginViewPath = base_path('themes/default/views/auth/login.blade.php');
|
|
|
|
// Buscar el backup más reciente
|
|
$backupFiles = glob($loginViewPath . '.backup.*');
|
|
if (empty($backupFiles)) {
|
|
\Log::warning('No se encontraron archivos de backup.');
|
|
return false;
|
|
}
|
|
|
|
// Ordenar por fecha de modificación (más reciente primero)
|
|
usort($backupFiles, function($a, $b) {
|
|
return filemtime($b) - filemtime($a);
|
|
});
|
|
|
|
$latestBackup = $backupFiles[0];
|
|
$originalContent = file_get_contents($latestBackup);
|
|
|
|
if (file_put_contents($loginViewPath, $originalContent)) {
|
|
\Log::info('Vista de login restaurada desde: ' . $latestBackup);
|
|
return true;
|
|
} else {
|
|
\Log::error('Error al restaurar la vista de login.');
|
|
return false;
|
|
}
|
|
}
|
|
}
|