diff --git a/.env b/.env index 2275a9d..ca9cade 100644 --- a/.env +++ b/.env @@ -43,8 +43,11 @@ REDIS_HOST=redis://redis MAILER_DSN=null://null ###< symfony/mailer ### +AUTH_METHOD=form_login + ###> drenso/symfony-oidc-bundle ### -OIDC_WELL_KNOWN_URL="Enter the .well-known url for the OIDC provider" +OIDC_WELL_KNOWN_URL="https://oidc/.well-known" OIDC_CLIENT_ID="Enter your OIDC client id" OIDC_CLIENT_SECRET="Enter your OIDC client secret" +OIDC_BYPASS_FORM_LOGIN=false ###< drenso/symfony-oidc-bundle ### diff --git a/config/packages/security.yaml b/config/packages/security.yaml index e1a28c6..348e902 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -24,9 +24,14 @@ security: logout: path: /logout provider: app_oidc + form_login: + login_path: app_login + check_path: app_login + enable_csrf: true oidc: login_path: '/login/oidc' check_path: '/login/oidc/auth' + entry_point: form_login # activate different ways to authenticate # https://symfony.com/doc/current/security.html#the-firewall diff --git a/config/services.yaml b/config/services.yaml index f44dc32..b8885fa 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -6,6 +6,7 @@ parameters: # App app.url: '%env(APP_URL)%' + app.version: '%env(default:app.default.version:APP_VERSION)%' # Debrid Services app.debrid.real_debrid.key: '%env(REAL_DEBRID_KEY)%' @@ -34,7 +35,14 @@ parameters: app.default.version: '0.dev' app.default.timezone: 'America/Chicago' - app.version: '%env(default:app.default.version:APP_VERSION)%' + # Auth + auth.default.method: 'form_login' + auth.method: '%env(default:auth.default.method:AUTH_METHOD)%' + + auth.oidc.well_known_url: '%env(OIDC_WELL_KNOWN_URL)%' + auth.oidc.client_id: '%env(OIDC_CLIENT_ID)%' + auth.oidc.client_secret: '%env(OIDC_CLIENT_SECRET)%' + auth.oidc.bypass_form_login: '%env(bool:OIDC_BYPASS_FORM_LOGIN)%' services: # default configuration for services in *this* file diff --git a/src/Base/ConfigResolver.php b/src/Base/ConfigResolver.php index 28ccc8f..520dc49 100644 --- a/src/Base/ConfigResolver.php +++ b/src/Base/ConfigResolver.php @@ -23,6 +23,21 @@ final class ConfigResolver #[Autowire(param: 'media.tvshows.path')] private readonly ?string $tvshowsPath = null, + + #[Autowire(param: 'auth.method')] + private readonly ?string $authMethod = null, + + #[Autowire(param: 'auth.oidc.well_known_url')] + private readonly ?string $authOidcWellKnownUrl = null, + + #[Autowire(param: 'auth.oidc.client_id')] + private readonly ?string $authOidcClientId = null, + + #[Autowire(param: 'auth.oidc.client_secret')] + private readonly ?string $authOidcClientSecret = null, + + #[Autowire(param: 'auth.oidc.bypass_form_login')] + private ?bool $authOidcBypassFormLogin = null, ) {} public function validate(): bool @@ -46,4 +61,35 @@ final class ConfigResolver { return $this->messages; } + + public function authIs(string $method): bool + { + if (strtolower($method) === strtolower($this->getAuthMethod())) { + return true; + } + return false; + } + + public function getAuthMethod(): string + { + return strtolower($this->authMethod); + } + + public function bypassFormLogin(): bool + { + return $this->authOidcBypassFormLogin; + } + + public function getAuthConfig(): array + { + return [ + 'method' => $this->authMethod, + 'oidc' => [ + 'well_known_url' => $this->authOidcWellKnownUrl, + 'client_id' => $this->authOidcClientId, + 'client_secret' => $this->authOidcClientSecret, + 'bypass_form_login' => $this->authOidcBypassFormLogin, + ] + ]; + } } diff --git a/src/User/Framework/Controller/Web/LoginController.php b/src/User/Framework/Controller/Web/LoginController.php index 0f0dbf6..b96b731 100644 --- a/src/User/Framework/Controller/Web/LoginController.php +++ b/src/User/Framework/Controller/Web/LoginController.php @@ -2,29 +2,30 @@ namespace App\User\Framework\Controller\Web; +use App\Base\ConfigResolver; use App\User\Framework\Repository\UserRepository; -use App\User\Framework\Security\OidcUserProvider; use Doctrine\Common\Collections\ArrayCollection; -use Drenso\OidcBundle\Exception\OidcException; -use Drenso\OidcBundle\OidcClientInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\SecurityBundle\Security; -use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Routing\Attribute\Route; -use Symfony\Component\Security\Http\Attribute\IsGranted; + use Symfony\Component\Security\Http\Authentication\AuthenticationUtils; class LoginController extends AbstractController { #[Route(path: '/login', name: 'app_login')] - public function login(AuthenticationUtils $authenticationUtils, UserRepository $userRepository): Response + public function login(ConfigResolver $config, AuthenticationUtils $authenticationUtils, UserRepository $userRepository): Response { if ((new ArrayCollection($userRepository->findAll()))->count() === 0) { return $this->redirectToRoute('app_getting_started'); } + if ($config->authIs('oidc') && $config->bypassFormLogin()) { + return $this->redirectToRoute('app_login_oidc'); + } + // get the login error if there is one $error = $authenticationUtils->getLastAuthenticationError(); @@ -32,6 +33,7 @@ class LoginController extends AbstractController $lastUsername = $authenticationUtils->getLastUsername(); return $this->render('user/login.html.twig', [ + 'show_oidc_button' => $config->authIs('oidc'), 'last_username' => $lastUsername, 'error' => $error, ]); diff --git a/src/User/Framework/Controller/Web/LoginOidcController.php b/src/User/Framework/Controller/Web/LoginOidcController.php index 51e447b..fa58a82 100644 --- a/src/User/Framework/Controller/Web/LoginOidcController.php +++ b/src/User/Framework/Controller/Web/LoginOidcController.php @@ -2,6 +2,7 @@ namespace App\User\Framework\Controller\Web; +use App\Base\ConfigResolver; use Drenso\OidcBundle\OidcClientInterface; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Bundle\SecurityBundle\Security; @@ -11,9 +12,18 @@ use Symfony\Component\Routing\Attribute\Route; class LoginOidcController extends AbstractController { + + public function __construct( + private ConfigResolver $configResolver, + ) {} + #[Route('/login/oidc', name: 'app_login_oidc')] public function oidcStart(OidcClientInterface $oidcClient): RedirectResponse { + if (false === $this->configResolver->authIs('oidc')) { + throw new \Exception('You must configure the OIDC environment variables before logging in at this route.'); + } + // Redirect to authorization @ OIDC provider return $oidcClient->generateAuthorizationRedirect(); } @@ -21,6 +31,10 @@ class LoginOidcController extends AbstractController #[Route('/login/oidc/auth', name: 'app_login_oidc_auth')] public function oidcAuthenticate(): RedirectResponse { + if (false === $this->configResolver->authIs('oidc')) { + throw new \Exception('You must configure the OIDC environment variables before logging in at this route.'); + } + throw new \LogicException('This method can be blank - it will be intercepted by the "oidc" key on your firewall.'); } diff --git a/templates/user/login.html.twig b/templates/user/login.html.twig index 1c09573..ed98cfa 100644 --- a/templates/user/login.html.twig +++ b/templates/user/login.html.twig @@ -52,10 +52,16 @@ - -