Skip to content

Commit c740144

Browse files
committed
fix(User): Match token login name by UID or e-mail address
With this changes the login name gets matched against the token user's e-mail address in addition to the login name. This fixes the web login flow of the app, where the session is based on the e-mail address but the token uses the UID. Fixes #44164 Signed-off-by: Wouter Haffmans <wouter@simply-life.net>
1 parent e0c1ea2 commit c740144

2 files changed

Lines changed: 46 additions & 4 deletions

File tree

lib/private/User/Session.php

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -780,12 +780,15 @@ private function validateToken($token, $user = null) {
780780
* Check if login names match
781781
*/
782782
private function validateTokenLoginName(?string $loginName, IToken $token): bool {
783-
if ($token->getLoginName() !== $loginName) {
784-
// TODO: this makes it impossible to use different login names on browser and client
785-
// e.g. login by e-mail 'user@example.com' on browser for generating the token will not
786-
// allow to use the client token with the login name 'user'.
783+
$tokenUser = $this->manager->get($token->getUID());
784+
if (!is_null($tokenUser)) {
785+
$tokenEmail = $tokenUser->getEMailAddress();
786+
}
787+
788+
if ($token->getLoginName() !== $loginName && (is_null($tokenUser) || $tokenEmail !== $loginName)) {
787789
$this->logger->error('App token login name does not match', [
788790
'tokenLoginName' => $token->getLoginName(),
791+
'tokenEmailAddress' => $tokenEmail,
789792
'sessionLoginName' => $loginName,
790793
'app' => 'core',
791794
'user' => $token->getUID(),

tests/lib/User/SessionTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,45 @@ public function testLogClientInWithTokenPassword(): void {
516516
$this->assertTrue($userSession->logClientIn('john', 'I-AM-AN-APP-PASSWORD', $request, $this->throttler));
517517
}
518518

519+
public function testLogClientInWithEmailTokenPassword(): void {
520+
$manager = $this->createMock(Manager::class);
521+
$session = $this->createMock(ISession::class);
522+
$request = $this->createMock(IRequest::class);
523+
524+
/** @var Session $userSession */
525+
$userSession = $this->getMockBuilder(Session::class)
526+
->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
527+
->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser'])
528+
->getMock();
529+
530+
$user = $this->createMock(IUser::class);
531+
$user
532+
->method('getUID')
533+
->willReturn('john');
534+
$user
535+
->method('getEMailAddress')
536+
->willReturn('john@example.com');
537+
$manager
538+
->method('get')
539+
->with('john')
540+
->willReturn($user);
541+
$userSession->expects($this->once())
542+
->method('isTokenPassword')
543+
->willReturn(true);
544+
$userSession->expects($this->once())
545+
->method('login')
546+
->with('john@example.com')
547+
->willReturn(false);
548+
$token = new PublicKeyToken();
549+
$token->setLoginName('john');
550+
$token->setUid('john');
551+
$this->tokenProvider
552+
->method('getToken')
553+
->with('I-AM-AN-APP-PASSWORD')
554+
->willReturn($token);
555+
556+
$this->assertTrue($userSession->logClientIn('john@example.com', 'I-AM-AN-APP-PASSWORD', $request, $this->throttler));
557+
}
519558

520559
public function testLogClientInNoTokenPasswordNo2fa(): void {
521560
$this->expectException(PasswordLoginForbiddenException::class);

0 commit comments

Comments
 (0)