mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-07-28 17:02:04 +03:00
OIDC RP Logout: Added autodiscovery support and test cases
This commit is contained in:
@ -10,27 +10,19 @@ use BookStack\Facades\Activity;
|
||||
use BookStack\Http\Controller;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class LoginController extends Controller
|
||||
{
|
||||
use ThrottlesLogins;
|
||||
|
||||
protected SocialDriverManager $socialDriverManager;
|
||||
protected LoginService $loginService;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*/
|
||||
public function __construct(SocialDriverManager $driverManager, LoginService $loginService)
|
||||
{
|
||||
public function __construct(
|
||||
protected SocialDriverManager $socialDriverManager,
|
||||
protected LoginService $loginService,
|
||||
) {
|
||||
$this->middleware('guest', ['only' => ['getLogin', 'login']]);
|
||||
$this->middleware('guard:standard,ldap', ['only' => ['login']]);
|
||||
$this->middleware('guard:standard,ldap,oidc', ['only' => ['logout']]);
|
||||
|
||||
$this->socialDriverManager = $driverManager;
|
||||
$this->loginService = $loginService;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -52,7 +44,7 @@ class LoginController extends Controller
|
||||
// Store the previous location for redirect after login
|
||||
$this->updateIntendedFromPrevious();
|
||||
|
||||
if (!$preventInitiation && $this->shouldAutoInitiate()) {
|
||||
if (!$preventInitiation && $this->loginService->shouldAutoInitiate()) {
|
||||
return view('auth.login-initiate', [
|
||||
'authMethod' => $authMethod,
|
||||
]);
|
||||
@ -194,7 +186,7 @@ class LoginController extends Controller
|
||||
{
|
||||
// Store the previous location for redirect after login
|
||||
$previous = url()->previous('');
|
||||
$isPreviousFromInstance = (strpos($previous, url('/')) === 0);
|
||||
$isPreviousFromInstance = str_starts_with($previous, url('/'));
|
||||
if (!$previous || !setting('app-public') || !$isPreviousFromInstance) {
|
||||
return;
|
||||
}
|
||||
@ -205,7 +197,7 @@ class LoginController extends Controller
|
||||
];
|
||||
|
||||
foreach ($ignorePrefixList as $ignorePrefix) {
|
||||
if (strpos($previous, url($ignorePrefix)) === 0) {
|
||||
if (str_starts_with($previous, url($ignorePrefix))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -176,14 +176,18 @@ class LoginService
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if login auto-initiate should be valid based upon authentication config.
|
||||
* Check if login auto-initiate should be active based upon authentication config.
|
||||
*/
|
||||
protected function shouldAutoInitiate(): bool
|
||||
public function shouldAutoInitiate(): bool
|
||||
{
|
||||
$autoRedirect = config('auth.auto_initiate');
|
||||
if (!$autoRedirect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$socialDrivers = $this->socialDriverManager->getActive();
|
||||
$authMethod = config('auth.method');
|
||||
$autoRedirect = config('auth.auto_initiate');
|
||||
|
||||
return $autoRedirect && count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']);
|
||||
return count($socialDrivers) === 0 && in_array($authMethod, ['oidc', 'saml2']);
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class OidcProviderSettings
|
||||
public ?string $redirectUri;
|
||||
public ?string $authorizationEndpoint;
|
||||
public ?string $tokenEndpoint;
|
||||
public ?string $endSessionEndpoint;
|
||||
|
||||
/**
|
||||
* @var string[]|array[]
|
||||
@ -132,6 +133,10 @@ class OidcProviderSettings
|
||||
$discoveredSettings['keys'] = $this->filterKeys($keys);
|
||||
}
|
||||
|
||||
if (!empty($result['end_session_endpoint'])) {
|
||||
$discoveredSettings['endSessionEndpoint'] = $result['end_session_endpoint'];
|
||||
}
|
||||
|
||||
return $discoveredSettings;
|
||||
}
|
||||
|
||||
|
@ -84,6 +84,7 @@ class OidcService
|
||||
'redirectUri' => url('/oidc/callback'),
|
||||
'authorizationEndpoint' => $config['authorization_endpoint'],
|
||||
'tokenEndpoint' => $config['token_endpoint'],
|
||||
'endSessionEndpoint' => $config['end_session_endpoint'],
|
||||
]);
|
||||
|
||||
// Use keys if configured
|
||||
@ -100,6 +101,11 @@ class OidcService
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent use of RP-initiated logout if specifically disabled
|
||||
if ($config['end_session_endpoint'] === false) {
|
||||
$settings->endSessionEndpoint = null;
|
||||
}
|
||||
|
||||
$settings->validate();
|
||||
|
||||
return $settings;
|
||||
@ -291,20 +297,23 @@ class OidcService
|
||||
* Start the RP-initiated logout flow if active, otherwise start a standard logout flow.
|
||||
* Returns a post-app-logout redirect URL.
|
||||
* Reference: https://openid.net/specs/openid-connect-rpinitiated-1_0.html
|
||||
* @throws OidcException
|
||||
*/
|
||||
public function logout(): string
|
||||
{
|
||||
$endSessionEndpoint = $this->config()["end_session_endpoint"];
|
||||
|
||||
// TODO - Add autodiscovery and false/null config value support.
|
||||
|
||||
$oidcToken = session()->pull("oidc_id_token");
|
||||
$defaultLogoutUrl = url($this->loginService->logout());
|
||||
$oidcSettings = $this->getProviderSettings();
|
||||
|
||||
if (!$oidcSettings->endSessionEndpoint) {
|
||||
return $defaultLogoutUrl;
|
||||
}
|
||||
|
||||
$endpointParams = [
|
||||
'id_token_hint' => $oidcToken,
|
||||
'post_logout_redirect_uri' => $defaultLogoutUrl,
|
||||
];
|
||||
|
||||
return $endSessionEndpoint . '?' . http_build_query($endpointParams);
|
||||
return $oidcSettings->endSessionEndpoint . '?' . http_build_query($endpointParams);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user