Upgrade to 3.5.1
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Kirby\Cms;
|
||||
|
||||
use Kirby\Cms\Auth\Status;
|
||||
use Kirby\Data\Data;
|
||||
use Kirby\Exception\InvalidArgumentException;
|
||||
use Kirby\Exception\LogicException;
|
||||
@@ -32,9 +33,41 @@ class Auth
|
||||
*/
|
||||
public static $challenges = [];
|
||||
|
||||
/**
|
||||
* Currently impersonated user
|
||||
*
|
||||
* @var \Kirby\Cms\User|null
|
||||
*/
|
||||
protected $impersonate;
|
||||
|
||||
/**
|
||||
* Kirby instance
|
||||
*
|
||||
* @var \Kirby\Cms\App
|
||||
*/
|
||||
protected $kirby;
|
||||
|
||||
/**
|
||||
* Cache of the auth status object
|
||||
*
|
||||
* @var \Kirby\Cms\Auth\Status
|
||||
*/
|
||||
protected $status;
|
||||
|
||||
/**
|
||||
* Instance of the currently logged in user or
|
||||
* `false` if the user was not yet determined
|
||||
*
|
||||
* @var \Kirby\Cms\User|null|false
|
||||
*/
|
||||
protected $user = false;
|
||||
|
||||
/**
|
||||
* Exception that was thrown while
|
||||
* determining the current user
|
||||
*
|
||||
* @var \Throwable
|
||||
*/
|
||||
protected $userException;
|
||||
|
||||
/**
|
||||
@@ -53,15 +86,13 @@ class Auth
|
||||
* @param string $email
|
||||
* @param bool $long If `true`, a long session will be created
|
||||
* @param string $mode Either 'login' or 'password-reset'
|
||||
* @return string|null Name of the challenge that was created;
|
||||
* `null` if the user does not exist or no
|
||||
* challenge was available for the user
|
||||
* @return \Kirby\Cms\Auth\Status
|
||||
*
|
||||
* @throws \Kirby\Exception\LogicException If there is no suitable authentication challenge (only in debug mode)
|
||||
* @throws \Kirby\Exception\NotFoundException If the user does not exist (only in debug mode)
|
||||
* @throws \Kirby\Exception\PermissionException If the rate limit is exceeded
|
||||
*/
|
||||
public function createChallenge(string $email, bool $long = false, string $mode = 'login'): ?string
|
||||
public function createChallenge(string $email, bool $long = false, string $mode = 'login')
|
||||
{
|
||||
// ensure that email addresses with IDN domains are in Unicode format
|
||||
$email = Idn::decodeEmail($email);
|
||||
@@ -91,8 +122,7 @@ class Auth
|
||||
if ($user = $this->kirby->users()->find($email)) {
|
||||
$timeout = $this->kirby->option('auth.challenge.timeout', 10 * 60);
|
||||
|
||||
$challenges = $this->kirby->option('auth.challenges', ['email']);
|
||||
foreach (A::wrap($challenges) as $name) {
|
||||
foreach ($this->enabledChallenges() as $name) {
|
||||
$class = static::$challenges[$name] ?? null;
|
||||
if (
|
||||
$class &&
|
||||
@@ -115,7 +145,7 @@ class Auth
|
||||
}
|
||||
|
||||
// if no suitable challenge was found, `$challenge === null` at this point;
|
||||
// only leak this in debug mode, otherwise `null` is returned below
|
||||
// only leak this in debug mode
|
||||
if ($challenge === null && $this->kirby->option('debug') === true) {
|
||||
throw new LogicException('Could not find a suitable authentication challenge');
|
||||
}
|
||||
@@ -142,7 +172,10 @@ class Auth
|
||||
// avoid leaking whether the user exists
|
||||
usleep(random_int(1000, 300000));
|
||||
|
||||
return $challenge;
|
||||
// clear the status cache
|
||||
$this->status = null;
|
||||
|
||||
return $this->status($session, false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,15 +263,7 @@ class Auth
|
||||
*/
|
||||
public function currentUserFromSession($session = null)
|
||||
{
|
||||
// use passed session options or session object if set
|
||||
if (is_array($session) === true) {
|
||||
$session = $this->kirby->session($session);
|
||||
}
|
||||
|
||||
// try session in header or cookie
|
||||
if (is_a($session, 'Kirby\Session\Session') === false) {
|
||||
$session = $this->kirby->session(['detect' => true]);
|
||||
}
|
||||
$session = $this->session($session);
|
||||
|
||||
$id = $session->data()->get('kirby.userId');
|
||||
|
||||
@@ -256,6 +281,17 @@ class Auth
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of enabled challenges in the
|
||||
* configured order
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function enabledChallenges(): array
|
||||
{
|
||||
return A::wrap($this->kirby->option('auth.challenges', ['email']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Become any existing user or disable the current user
|
||||
*
|
||||
@@ -268,6 +304,9 @@ class Auth
|
||||
*/
|
||||
public function impersonate(?string $who = null)
|
||||
{
|
||||
// clear the status cache
|
||||
$this->status = null;
|
||||
|
||||
switch ($who) {
|
||||
case null:
|
||||
return $this->impersonate = null;
|
||||
@@ -359,6 +398,9 @@ class Auth
|
||||
$user = $this->validatePassword($email, $password);
|
||||
$user->loginPasswordless($options);
|
||||
|
||||
// clear the status cache
|
||||
$this->status = null;
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
@@ -368,8 +410,7 @@ class Auth
|
||||
* @param string $email
|
||||
* @param string $password
|
||||
* @param bool $long
|
||||
* @return string|null Name of the challenge that was created;
|
||||
* `null` if no challenge was available for the user
|
||||
* @return \Kirby\Cms\Auth\Status
|
||||
*
|
||||
* @throws \Kirby\Exception\PermissionException If the rate limit was exceeded or if any other error occured with debug mode off
|
||||
* @throws \Kirby\Exception\NotFoundException If the email was invalid
|
||||
@@ -394,6 +435,57 @@ class Auth
|
||||
$this->impersonate = null;
|
||||
|
||||
$this->user = $user;
|
||||
|
||||
// clear the status cache
|
||||
$this->status = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the authentication status object
|
||||
*
|
||||
* @param \Kirby\Session\Session|array|null $session
|
||||
* @param bool $allowImpersonation If set to false, only the actually
|
||||
* logged in user will be returned
|
||||
* @return \Kirby\Cms\Auth\Status
|
||||
*/
|
||||
public function status($session = null, bool $allowImpersonation = true)
|
||||
{
|
||||
// try to return from cache
|
||||
if ($this->status && $session === null && $allowImpersonation === true) {
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
$sessionObj = $this->session($session);
|
||||
|
||||
$props = ['kirby' => $this->kirby];
|
||||
if ($user = $this->user($sessionObj, $allowImpersonation)) {
|
||||
// a user is currently logged in
|
||||
if ($allowImpersonation === true && $this->impersonate !== null) {
|
||||
$props['status'] = 'impersonated';
|
||||
} else {
|
||||
$props['status'] = 'active';
|
||||
}
|
||||
|
||||
$props['email'] = $user->email();
|
||||
} elseif ($email = $sessionObj->get('kirby.challenge.email')) {
|
||||
// a challenge is currently pending
|
||||
$props['status'] = 'pending';
|
||||
$props['email'] = $email;
|
||||
$props['challenge'] = $sessionObj->get('kirby.challenge.type');
|
||||
$props['challengeFallback'] = A::last($this->enabledChallenges());
|
||||
} else {
|
||||
// no active authentication
|
||||
$props['status'] = 'inactive';
|
||||
}
|
||||
|
||||
$status = new Status($props);
|
||||
|
||||
// only cache the default object
|
||||
if ($session === null && $allowImpersonation === true) {
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -534,6 +626,9 @@ class Auth
|
||||
$session->remove('kirby.challenge.email');
|
||||
$session->remove('kirby.challenge.timeout');
|
||||
$session->remove('kirby.challenge.type');
|
||||
|
||||
// clear the status cache
|
||||
$this->status = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -545,6 +640,7 @@ class Auth
|
||||
public function flush(): void
|
||||
{
|
||||
$this->impersonate = null;
|
||||
$this->status = null;
|
||||
$this->user = null;
|
||||
}
|
||||
|
||||
@@ -718,6 +814,9 @@ class Auth
|
||||
$this->logout();
|
||||
$user->loginPasswordless();
|
||||
|
||||
// clear the status cache
|
||||
$this->status = null;
|
||||
|
||||
return $user;
|
||||
} else {
|
||||
throw new PermissionException(['key' => 'access.code']);
|
||||
@@ -744,4 +843,25 @@ class Auth
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a session object from the passed options
|
||||
*
|
||||
* @param \Kirby\Session\Session|array|null $session
|
||||
* @return \Kirby\Session\Session
|
||||
*/
|
||||
protected function session($session = null)
|
||||
{
|
||||
// use passed session options or session object if set
|
||||
if (is_array($session) === true) {
|
||||
return $this->kirby->session($session);
|
||||
}
|
||||
|
||||
// try session in header or cookie
|
||||
if (is_a($session, 'Kirby\Session\Session') === false) {
|
||||
return $this->kirby->session(['detect' => true]);
|
||||
}
|
||||
|
||||
return $session;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user