Files
Leantime/app/Domain/Oidc/Controllers/Login.php
wangruiguo d647428529
Some checks failed
Security Audit / Composer Security Audit (push) Has been cancelled
Security Audit / NPM Security Audit (push) Has been cancelled
Security Audit / CodeQL Analysis (push) Has been cancelled
OneBot: Leantime 改造版源码(BOM/Univer 表格/AI 接管/品牌替换等)
2026-09-03 18:49:20 +08:00

87 lines
3.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace Leantime\Domain\Oidc\Controllers;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;
use Leantime\Core\Controller\Controller;
use Leantime\Core\Controller\Frontcontroller;
use Leantime\Domain\Oidc\Services\Oidc as OidcService;
use Leantime\Domain\Plugins\Services\Plugins;
use Symfony\Component\HttpFoundation\Response;
class Login extends Controller
{
private OidcService $oidc;
private Plugins $plugins;
/**
* Initializes dependencies.
*
* @throws GuzzleException
*/
public function init(OidcService $oidc, Plugins $plugins): void
{
$this->oidc = $oidc;
$this->plugins = $plugins;
}
/**
* Redirects to the OIDC provider login page.
*
* @param array $params Request parameters
*/
public function get(array $params): Response
{
try {
// Mobile-brokered SSO: the app passes ?mobile=1&redirect_uri=<app scheme>
// + a PKCE code_challenge, so the callback mints a token + one-time
// code (bound to that challenge) and redirects back to the app instead
// of establishing a web session. The service validates the redirect
// scheme; a non-mobile web login passes none of these.
$mobile = ! empty($params['mobile']);
$redirectUri = is_string($params['redirect_uri'] ?? null) ? $params['redirect_uri'] : '';
$codeChallenge = is_string($params['code_challenge'] ?? null) ? $params['code_challenge'] : '';
// The mobile-brokered branch is an AdvancedAuth capability. Without the
// plugin, ignore the mobile params and fall back to normal web login —
// the mint endpoint refuses too, so no mobile session can be brokered.
if ($mobile && ! $this->plugins->isEnabled('AdvancedAuth')) {
return Frontcontroller::redirect(BASE_URL.'/auth/login');
}
// Mobile flow requires a PKCE challenge — otherwise the callback
// would mint a code whose exchange can never succeed (pkceMatches
// rejects an empty challenge). Fail loudly at the front door.
if ($mobile && $codeChallenge === '') {
$this->tpl->setNotification('Mobile login requires a PKCE code_challenge.', 'error');
return Frontcontroller::redirect(BASE_URL.'/auth/login');
}
// A PKCE S256 challenge is base64url(sha256(verifier)) — the
// base64url charset, 43–128 chars (RFC 7636). Reject a present-but-
// malformed value so a crafted request can't persist junk into the
// code store and to enforce the intended mobile contract.
if ($codeChallenge !== '' && ! preg_match('/^[A-Za-z0-9\-_]{43,128}$/', $codeChallenge)) {
$this->tpl->setNotification('Invalid PKCE code_challenge.', 'error');
return Frontcontroller::redirect(BASE_URL.'/auth/login');
}
$loginUrl = $this->oidc->buildLoginUrl($mobile, $redirectUri, $codeChallenge);
if ($loginUrl) {
return Frontcontroller::redirect($loginUrl, 302);
}
} catch (\Throwable $e) {
Log::error($e);
}
$this->tpl->setNotification('Auth URL could not be found. Check the logs for more details', 'error');
return Frontcontroller::redirect(BASE_URL.'/auth/login');
}
}