Skip to content

Commit

Permalink
fix(User): Match token login name by UID or e-mail address
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
haffmans committed Jan 18, 2025
1 parent e0c1ea2 commit c740144
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 4 deletions.
11 changes: 7 additions & 4 deletions lib/private/User/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -780,12 +780,15 @@ private function validateToken($token, $user = null) {
* Check if login names match
*/
private function validateTokenLoginName(?string $loginName, IToken $token): bool {
if ($token->getLoginName() !== $loginName) {
// TODO: this makes it impossible to use different login names on browser and client
// e.g. login by e-mail '[email protected]' on browser for generating the token will not
// allow to use the client token with the login name 'user'.
$tokenUser = $this->manager->get($token->getUID());
if (!is_null($tokenUser)) {
$tokenEmail = $tokenUser->getEMailAddress();
}

if ($token->getLoginName() !== $loginName && (is_null($tokenUser) || $tokenEmail !== $loginName)) {
$this->logger->error('App token login name does not match', [
'tokenLoginName' => $token->getLoginName(),
'tokenEmailAddress' => $tokenEmail,
'sessionLoginName' => $loginName,
'app' => 'core',
'user' => $token->getUID(),
Expand Down
39 changes: 39 additions & 0 deletions tests/lib/User/SessionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,45 @@ public function testLogClientInWithTokenPassword(): void {
$this->assertTrue($userSession->logClientIn('john', 'I-AM-AN-APP-PASSWORD', $request, $this->throttler));
}

public function testLogClientInWithEmailTokenPassword(): void {
$manager = $this->createMock(Manager::class);
$session = $this->createMock(ISession::class);
$request = $this->createMock(IRequest::class);

/** @var Session $userSession */
$userSession = $this->getMockBuilder(Session::class)
->setConstructorArgs([$manager, $session, $this->timeFactory, $this->tokenProvider, $this->config, $this->random, $this->lockdownManager, $this->logger, $this->dispatcher])
->setMethods(['isTokenPassword', 'login', 'supportsCookies', 'createSessionToken', 'getUser'])
->getMock();

$user = $this->createMock(IUser::class);
$user
->method('getUID')
->willReturn('john');
$user
->method('getEMailAddress')
->willReturn('[email protected]');
$manager
->method('get')
->with('john')
->willReturn($user);
$userSession->expects($this->once())
->method('isTokenPassword')
->willReturn(true);
$userSession->expects($this->once())
->method('login')
->with('[email protected]')
->willReturn(false);
$token = new PublicKeyToken();
$token->setLoginName('john');
$token->setUid('john');
$this->tokenProvider
->method('getToken')
->with('I-AM-AN-APP-PASSWORD')
->willReturn($token);

$this->assertTrue($userSession->logClientIn('[email protected]', 'I-AM-AN-APP-PASSWORD', $request, $this->throttler));
}

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

0 comments on commit c740144

Please sign in to comment.