Improved account login/switch handling

This commit is contained in:
djmaze 2021-12-14 12:42:41 +01:00
parent 3af8652175
commit abe2af153d
7 changed files with 45 additions and 101 deletions

View file

@ -79,7 +79,7 @@ trait Accounts
throw new ClientException(Notifications::AccountDoesNotExist);
}
$oNewAccount = $this->LoginProcess($sEmail, $sPassword, false, $oMainAccount);
$oNewAccount = $this->LoginProcess($sEmail, $sPassword, false, false);
$aAccounts[$oNewAccount->Email()] = $oNewAccount->asTokenArray($oMainAccount);
$this->SetAccounts($oMainAccount, $aAccounts);

View file

@ -200,14 +200,9 @@ trait User
public function DoLogout() : array
{
$oAccount = $this->getAccountFromToken(false);
if ($oAccount) {
if ($oAccount instanceof \RainLoop\Model\MainAccount) {
$this->ClearSignMeData();
Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
}
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
}
$bMain = empty($_COOKIE[self::AUTH_ADDITIONAL_TOKEN_KEY]);
$this->Logout($bMain);
$bMain && $this->ClearSignMeData();
return $this->TrueResponse(__FUNCTION__);
}

View file

@ -21,7 +21,7 @@ trait UserAuth
/**
* @throws \RainLoop\Exceptions\ClientException
*/
public function LoginProcess(string &$sEmail, string &$sPassword, bool $bSignMe = false, Account $oMainAccount = null): Account
public function LoginProcess(string &$sEmail, string &$sPassword, bool $bSignMe = false, bool $bMainAccount = true): Account
{
$sInputEmail = $sEmail;
@ -114,10 +114,10 @@ trait UserAuth
$oAccount = null;
$sClientCert = \trim($this->Config()->Get('ssl', 'client_cert', ''));
try {
if ($oMainAccount) {
$oAccount = AdditionalAccount::NewInstanceByLogin($this, $sEmail, $sLogin, $sPassword, $sClientCert, true);
if ($bMainAccount) {
$oAccount = MainAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $sPassword, $sClientCert, true);
} else {
$oAccount = MainAccount::NewInstanceByLogin($this, $sEmail, $sLogin, $sPassword, $sClientCert, true);
$oAccount = AdditionalAccount::NewInstanceFromCredentials($this, $sEmail, $sLogin, $sPassword, $sClientCert, true);
}
if (!$oAccount) {
@ -131,7 +131,7 @@ trait UserAuth
try {
$this->CheckMailConnection($oAccount, true);
if (!$oMainAccount) {
if ($bMainAccount) {
$bSignMe && $this->SetSignMeToken($oAccount);
$this->StorageProvider()->Put($oAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true');
}
@ -144,6 +144,18 @@ trait UserAuth
return $oAccount;
}
private static function SetAccountCookie(string $sName, ?Account $oAccount)
{
if ($oAccount) {
Utils::SetCookie(
$sName,
\MailSo\Base\Utils::UrlSafeBase64Encode(\SnappyMail\Crypt::EncryptToJSON($oAccount))
);
} else {
Utils::ClearCookie($sName);
}
}
public function switchAccount(string $sEmail) : bool
{
$this->Http()->ServerNoCache();
@ -165,6 +177,9 @@ trait UserAuth
if (!$oAccountToLogin) {
throw new ClientException(Notifications::AccountSwitchFailed);
}
// $this->CheckMailConnection($oAccountToLogin);
$this->SetAdditionalAuthToken($oAccountToLogin);
return true;
}
@ -233,12 +248,10 @@ trait UserAuth
} else {
$oMainAuthAccount && $this->StorageProvider()->Clear($oMainAuthAccount, StorageType::SESSION, $sToken);
Utils::ClearCookie(Utils::SESSION_TOKEN);
Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
$this->Logout(true);
}
} else {
Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
$this->Logout(true);
}
} else {
$oAccount = $this->GetAccountFromSignMeToken();
@ -252,7 +265,7 @@ trait UserAuth
}
if ($this->oMainAuthAccount) {
$this->StorageProvider()->Put($this->oMainAuthAccount, StorageType::SESSION, $sToken, 'true');
$this->StorageProvider()->Put($this->oMainAuthAccount, StorageType::SESSION, Utils::GetSessionToken(), 'true');
}
}
@ -263,17 +276,13 @@ trait UserAuth
{
$this->oAdditionalAuthAccount = false;
$this->oMainAuthAccount = $oAccount;
Utils::SetSecureCookie(self::AUTH_SPEC_TOKEN_KEY, $oAccount);
static::SetAccountCookie(self::AUTH_SPEC_TOKEN_KEY, $oAccount);
}
public function SetAdditionalAuthToken(?AdditionalAccount $oAccount): void
{
$this->oAdditionalAuthAccount = $oAccount ?: false;
if ($oAccount) {
Utils::SetSecureCookie(self::AUTH_ADDITIONAL_TOKEN_KEY, $oAccount);
} else {
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
}
static::SetAccountCookie(self::AUTH_ADDITIONAL_TOKEN_KEY, $oAccount);
}
/**
@ -288,7 +297,6 @@ trait UserAuth
if (isset($aResult['e'], $aResult['u']) && \SnappyMail\UUID::isValid($aResult['u'])) {
return $aResult;
}
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
}
return null;
}
@ -350,10 +358,10 @@ trait UserAuth
catch (\Throwable $oException)
{
}
$this->ClearSignMeData();
}
$this->ClearSignMeData();
return null;
}
@ -362,8 +370,8 @@ trait UserAuth
$aTokenData = static::GetSignMeToken();
if ($aTokenData) {
$this->StorageProvider()->Clear($aTokenData['e'], StorageType::SIGN_ME, $aTokenData['u']);
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
}
Utils::ClearCookie(self::AUTH_SIGN_ME_TOKEN_KEY);
}
/**
@ -391,6 +399,12 @@ trait UserAuth
Utils::SetCookie(self::AUTH_SPEC_LOGOUT_CUSTOM_MSG_KEY, $sMessage);
}
protected function Logout(bool $bMain) : void
{
Utils::ClearCookie(self::AUTH_ADDITIONAL_TOKEN_KEY);
$bMain && Utils::ClearCookie(self::AUTH_SPEC_TOKEN_KEY);
}
/**
* @throws \RainLoop\Exceptions\ClientException
*/

View file

@ -143,20 +143,7 @@ abstract class Account implements \JsonSerializable
);
}
/**
* @throws \RainLoop\Exceptions\ClientException
*/
public static function NewInstanceFromAuthToken(\RainLoop\Actions $oActions, string $sToken): ?self
{
return empty($sToken) ? null
: static::NewInstanceFromTokenArray(
$oActions,
Utils::DecodeKeyValues($sToken),
false
);
}
public static function NewInstanceByLogin(\RainLoop\Actions $oActions,
public static function NewInstanceFromCredentials(\RainLoop\Actions $oActions,
string $sEmail, string $sLogin, string $sPassword, string $sClientCert = '',
bool $bThrowException = false): ?self
{
@ -176,7 +163,7 @@ abstract class Account implements \JsonSerializable
$oActions->Plugins()->RunHook('filter.account', array($oAccount));
if ($bThrowException && !$oAccount) {
throw new ClientException(Notifications::AuthError);
throw new ClientException(Notifications::AccountFilterError);
}
} else if ($bThrowException) {
throw new ClientException(Notifications::AccountNotAllowed);
@ -195,7 +182,7 @@ abstract class Account implements \JsonSerializable
bool $bThrowExceptionOnFalse = false): ?self
{
if (!empty($aAccountHash[0]) && 'account' === $aAccountHash[0] && 7 <= \count($aAccountHash)) {
$oAccount = static::NewInstanceByLogin(
$oAccount = static::NewInstanceFromCredentials(
$oActions,
$aAccountHash[1] ?: '',
$aAccountHash[2] ?: '',

View file

@ -47,6 +47,7 @@ class Notifications
const AccountAlreadyExists = 801;
const AccountDoesNotExist = 802;
const AccountSwitchFailed = 803;
const AccountFilterError = 804;
const MailServerError = 901;
const ClientViewError = 902;

View file

@ -717,7 +717,7 @@ class ServiceActions
$this->oActions->SetAuthToken($oAccount);
$bLogout = !($oAccount instanceof Model\Account);
$bLogout = !($oAccount instanceof Model\MainAccount);
}
catch (\Throwable $oException)
{
@ -751,7 +751,7 @@ class ServiceActions
{
$oAccount = $this->oActions->LoginProcess($sEmail, $sPassword);
$this->oActions->SetAuthToken($oAccount);
$bLogout = !($oAccount instanceof Model\Account);
$bLogout = !($oAccount instanceof Model\MainAccount);
}
catch (\Throwable $oException)
{
@ -768,49 +768,6 @@ class ServiceActions
return '';
}
public function ServiceExternalLogin() : string
{
$this->oHttp->ServerNoCache();
$oException = null;
$oAccount = null;
$bLogout = true;
switch (\strtolower($_REQUEST['Output'] ?? 'Redirect'))
{
case 'json':
\header('Content-Type: application/json; charset=utf-8');
$aResult = array(
'Action' => 'ExternalLogin',
'Result' => $oAccount instanceof Model\Account ? true : false,
'ErrorCode' => 0
);
if (!$aResult['Result'])
{
if ($oException instanceof Exceptions\ClientException)
{
$aResult['ErrorCode'] = $oException->getCode();
}
else
{
$aResult['ErrorCode'] = Notifications::AuthError;
}
}
return \MailSo\Base\Utils::Php2js($aResult, $this->Logger());
case 'redirect':
default:
$this->oActions->Location('./');
break;
}
return '';
}
/**
* @return mixed
*/

View file

@ -77,7 +77,7 @@ class Utils
$sToken = static::GetCookie(self::SESSION_TOKEN, null);
if (!$sToken) {
$sToken = \MailSo\Base\Utils::Sha1Rand(APP_SALT);
static::SetCookie(self::SESSION_TOKEN, $sToken, 0);
static::SetCookie(self::SESSION_TOKEN, $sToken);
}
return \sha1('Session'.APP_SALT.$sToken.'Token'.APP_SALT);
@ -149,16 +149,6 @@ class Utils
));
}
public static function SetSecureCookie(string $sName, $mValue, int $iExpire = 0, bool $bHttpOnly = true)
{
static::SetCookie(
$sName,
\MailSo\Base\Utils::UrlSafeBase64Encode(\SnappyMail\Crypt::EncryptToJSON($mValue)),
$iExpire,
true
);
}
public static function ClearCookie(string $sName)
{
if (isset($_COOKIE[$sName])) {