RocketChat / RocketChat/Rocket.Chat
Users logged with CustomOAuth cannot login when username and name are different
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 46.1k
- Forks
- 13.9k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 130
Description
Description:
I have RocketChat deployed, where users' name field is set to their real names. After update to newest version (3.7.1), they are unable to login and getting message "User with username already exists". Unfortunately, update was from 1.0.3 and there there was no problem.
It turns out, that user can be passed only if fileds: name and services.<OAuthName>.name are the same and equal to username in database. Newly added users, get the same string for those fields.
Steps to reproduce:
- Go to chat main page.
- Click "Sign in with OAuth", where OAuth means configured Custom OAuth server
- OAuth server confirms user access with success.
Expected behavior:
User is able to login successfully and use chat.
Actual behavior:
User is denied to access the chat. Popup shows with message "User with username already exists".
Server Setup Information:
- Version of Rocket.Chat Server: 3.7.1
- Operating System: Ubuntu 18.04
- Deployment Method: manual from source
- Number of Running Instances: 4
- DB Replicaset Oplog:
- NodeJS Version: 12.18.4
- MongoDB Version: 4.0.20
Client Setup Information
- Desktop App or Browser Version: any
- Operating System: any
Additional context
OAuth server configuration red on application startup:
2020-10-23 22:37:39 972: server.js:204 CustomOAuth ➔ debug Init CustomOAuth <servicename> {
2020-10-23 22:37:39 972: serverURL: '<serverURL>',
2020-10-23 22:37:39 972: tokenPath: '<tokenPath>',
2020-10-23 22:37:39 972: identityPath: '<identityPath>',
2020-10-23 22:37:39 972: authorizePath: '<authorizePath>',
2020-10-23 22:37:39 972: scope: 'public extended',
2020-10-23 22:37:39 972: loginStyle: 'popup',
2020-10-23 22:37:39 972: tokenSentVia: 'payload',
2020-10-23 22:37:39 972: identityTokenSentVia: undefined,
2020-10-23 22:37:39 972: usernameField: undefined,
2020-10-23 22:37:39 972: emailField: undefined,
2020-10-23 22:37:39 972: nameField: undefined,
2020-10-23 22:37:39 972: avatarField: undefined,
2020-10-23 22:37:39 972: rolesClaim: undefined,
2020-10-23 22:37:39 972: mergeUsers: undefined,
2020-10-23 22:37:39 972: mergeRoles: undefined,
2020-10-23 22:37:39 972: accessTokenParam: '<access_token_param>',
2020-10-23 22:37:39 972: showButton: undefined
2020-10-23 22:37:39 972: }
DB entry which allows to pass for user:
{
"_id": "user's id",
"createdAt": ISODate("2016-04-24T18:43:54.571Z"),
"services": {
"resume": {
"loginTokens": [
{
"when": ISODate("2020-10-20T23:10:20.350Z"),
"hashedToken": "<token_hash>"
},
]
},
"<servicename>": {
"id": "<internal_id>",
"_OAuthCustom": true,
"accessToken": "<access_token>",
"email": "<username>@example.com",
"username": "<username>",
"expiresAt": 1603582767701,
"name": "<username>",
"serverURL": "<serverURL>"
},
"totp": {
"enabled": false,
"tempSecret": "<temp_secret>"
}
},
"type": "user",
"status": "online",
"active": true,
"name": "<username>",
"emails": [
{
"address": "<username>@example.com",
"verified": true
}
],
"roles": [
"user",
],
"lastLogin": ISODate("2020-10-24T21:56:49.776Z"),
"statusConnection": "online",
"utcOffset": 2,
"username": "<username>",
"settings": {
"preferences": {
"newRoomNotification": "door",
"newMessageNotification": "seasons",
"useEmojis": true,
"convertAsciiEmoji": true,
"saveMobileBandwidth": false,
"collapseMediaByDefault": false,
"autoImageLoad": true,
"emailNotificationMode": "nothing",
"unreadAlert": true,
"desktopNotificationDuration": 0,
"viewMode": 2,
"hideUsernames": true,
"hideRoles": false,
"hideAvatars": false,
"hideFlexTab": false,
"highlights": [
"<username>"
],
"sendOnEnter": "normal",
"roomsListExhibitionMode": "unread",
"sidebarHideAvatar": false,
"sidebarSortby": "activity",
"sidebarViewMode": "medium",
"sidebarShowUnread": true,
"sidebarShowDiscussion": false,
"sidebarGroupByType": false,
"sidebarShowFavorites": false
},
"profile": {}
},
"statusDefault": "online",
"statusLivechat": "available",
"_updatedAt": ISODate("2020-10-24T22:00:59.909Z"),
"language": "pl",
"__rooms": [
<room_list> ...
],
}
DB Entries when user cannot login:
- Both
nameand<servicename>.nameare set to<realname>
{
"_id": "user's id",
"createdAt": ISODate("2016-04-24T18:43:54.571Z"),
"services": {
"resume": {
"loginTokens": [
{
"when": ISODate("2020-10-20T23:10:20.350Z"),
"hashedToken": "<token_hash>"
},
]
},
"<servicename>": {
"id": "<internal_id>",
"_OAuthCustom": true,
"accessToken": "<access_token>",
"email": "<username>@example.com",
"username": "<username>",
"expiresAt": 1603582767701,
"name": "<realname>",
"serverURL": "<serverURL>"
},
"totp": {
"enabled": false,
"tempSecret": "<temp_secret>"
}
},
"type": "user",
"status": "online",
"active": true,
"name": "<realname>",
"emails": [
{
"address": "<username>@example.com",
"verified": true
}
],
"roles": [
"user",
],
"lastLogin": ISODate("2020-10-24T21:56:49.776Z"),
"statusConnection": "online",
"utcOffset": 2,
"username": "<username>",
"settings": {
"preferences": {
"newRoomNotification": "door",
"newMessageNotification": "seasons",
"useEmojis": true,
"convertAsciiEmoji": true,
"saveMobileBandwidth": false,
"collapseMediaByDefault": false,
"autoImageLoad": true,
"emailNotificationMode": "nothing",
"unreadAlert": true,
"desktopNotificationDuration": 0,
"viewMode": 2,
"hideUsernames": true,
"hideRoles": false,
"hideAvatars": false,
"hideFlexTab": false,
"highlights": [
"<username>"
],
"sendOnEnter": "normal",
"roomsListExhibitionMode": "unread",
"sidebarHideAvatar": false,
"sidebarSortby": "activity",
"sidebarViewMode": "medium",
"sidebarShowUnread": true,
"sidebarShowDiscussion": false,
"sidebarGroupByType": false,
"sidebarShowFavorites": false
},
"profile": {}
},
"statusDefault": "online",
"statusLivechat": "available",
"_updatedAt": ISODate("2020-10-24T22:00:59.909Z"),
"language": "pl",
"__rooms": [
<room_list> ...
],
}
- Only
nameis set to<realname>-> Actually used in 1.0.3. Allows to show users' real names in RocketChat profiles.
{
"_id": "user's id",
"createdAt": ISODate("2016-04-24T18:43:54.571Z"),
"services": {
"resume": {
"loginTokens": [
{
"when": ISODate("2020-10-20T23:10:20.350Z"),
"hashedToken": "<token_hash>"
},
]
},
"<servicename>": {
"id": "<internal_id>",
"_OAuthCustom": true,
"accessToken": "<access_token>",
"email": "<username>@example.com",
"username": "<username>",
"expiresAt": 1603582767701,
"name": "<username>",
"serverURL": "<serverURL>"
},
"totp": {
"enabled": false,
"tempSecret": "<temp_secret>"
}
},
"type": "user",
"status": "online",
"active": true,
"name": "<realname>",
"emails": [
{
"address": "<username>@example.com",
"verified": true
}
],
"roles": [
"user",
],
"lastLogin": ISODate("2020-10-24T21:56:49.776Z"),
"statusConnection": "online",
"utcOffset": 2,
"username": "<username>",
"settings": {
"preferences": {
"newRoomNotification": "door",
"newMessageNotification": "seasons",
"useEmojis": true,
"convertAsciiEmoji": true,
"saveMobileBandwidth": false,
"collapseMediaByDefault": false,
"autoImageLoad": true,
"emailNotificationMode": "nothing",
"unreadAlert": true,
"desktopNotificationDuration": 0,
"viewMode": 2,
"hideUsernames": true,
"hideRoles": false,
"hideAvatars": false,
"hideFlexTab": false,
"highlights": [
"<username>"
],
"sendOnEnter": "normal",
"roomsListExhibitionMode": "unread",
"sidebarHideAvatar": false,
"sidebarSortby": "activity",
"sidebarViewMode": "medium",
"sidebarShowUnread": true,
"sidebarShowDiscussion": false,
"sidebarGroupByType": false,
"sidebarShowFavorites": false
},
"profile": {}
},
"statusDefault": "online",
"statusLivechat": "available",
"_updatedAt": ISODate("2020-10-24T22:00:59.909Z"),
"language": "pl",
"__rooms": [
<room_list> ...
],
}
- Only
<servicename>.namefield is set to<realname>
{
"_id": "user's id",
"createdAt": ISODate("2016-04-24T18:43:54.571Z"),
"services": {
"resume": {
"loginTokens": [
{
"when": ISODate("2020-10-20T23:10:20.350Z"),
"hashedToken": "<token_hash>"
},
]
},
"<servicename>": {
"id": "<internal_id>",
"_OAuthCustom": true,
"accessToken": "<access_token>",
"email": "<username>@example.com",
"username": "<username>",
"expiresAt": 1603582767701,
"name": "<realname>",
"serverURL": "<serverURL>"
},
"totp": {
"enabled": false,
"tempSecret": "<temp_secret>"
}
},
"type": "user",
"status": "online",
"active": true,
"name": "<username>",
"emails": [
{
"address": "<username>@example.com",
"verified": true
}
],
"roles": [
"user",
],
"lastLogin": ISODate("2020-10-24T21:56:49.776Z"),
"statusConnection": "online",
"utcOffset": 2,
"username": "<username>",
"settings": {
"preferences": {
"newRoomNotification": "door",
"newMessageNotification": "seasons",
"useEmojis": true,
"convertAsciiEmoji": true,
"saveMobileBandwidth": false,
"collapseMediaByDefault": false,
"autoImageLoad": true,
"emailNotificationMode": "nothing",
"unreadAlert": true,
"desktopNotificationDuration": 0,
"viewMode": 2,
"hideUsernames": true,
"hideRoles": false,
"hideAvatars": false,
"hideFlexTab": false,
"highlights": [
"<username>"
],
"sendOnEnter": "normal",
"roomsListExhibitionMode": "unread",
"sidebarHideAvatar": false,
"sidebarSortby": "activity",
"sidebarViewMode": "medium",
"sidebarShowUnread": true,
"sidebarShowDiscussion": false,
"sidebarGroupByType": false,
"sidebarShowFavorites": false
},
"profile": {}
},
"statusDefault": "online",
"statusLivechat": "available",
"_updatedAt": ISODate("2020-10-24T22:00:59.909Z"),
"language": "pl",
"__rooms": [
<room_list> ...
],
}
Relevant logs:
Debug logs:
- Response from OAuth server
2020-10-25 00:04:16 064: server.js:204 CustomOAuth ➔ debug Identity response {
2020-10-25 00:04:16 064: "id": "<internal_id>",
2020-10-25 00:04:16 064: "email": "<username>@example.com",
2020-10-25 00:04:16 064: "username": "<username>"
2020-10-25 00:04:16 064: }
- Error with stacktrace:
2020-10-25 00:01:17 319: server.js:204 API ➔ debug POST: /api/v1/method.callAnon/login
2020-10-25 00:01:17 347: Exception while invoking method login Error: User with username <username> already exists [CustomOAuth]
2020-10-25 00:01:17 347: at AccountsServer.<anonymous> (app/custom-oauth/server/custom_oauth_server.js:339:12)
2020-10-25 00:01:17 347: at AccountsServer.Accounts.updateOrCreateUserFromExternalService (app/custom-oauth/server/custom_oauth_server.js:420:8)
2020-10-25 00:01:17 347: at AccountsServer.Accounts.updateOrCreateUserFromExternalService (server/configuration/accounts_meld.js:51:52)
2020-10-25 00:01:17 347: at MethodInvocation.<anonymous> (packages/accounts-oauth/oauth_server.js:55:21)
2020-10-25 00:01:17 347: at packages/accounts-base/accounts_server.js:475:31
2020-10-25 00:01:17 347: at tryLoginMethod (packages/accounts-base/accounts_server.js:1309:14)
2020-10-25 00:01:17 347: at AccountsServer._runLoginHandlers (packages/accounts-base/accounts_server.js:473:22)
2020-10-25 00:01:17 347: at AccountsServer.Accounts._runLoginHandlers (app/lib/server/lib/loginErrorMessageOverride.js:7:35)
2020-10-25 00:01:17 347: at MethodInvocation.methods.login (packages/accounts-base/accounts_server.js:533:31)
2020-10-25 00:01:17 347: at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1771:12)
2020-10-25 00:01:17 347: at packages/ddp-server/livedata_server.js:1689:15
2020-10-25 00:01:17 347: at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1234:12)
2020-10-25 00:01:17 347: at packages/ddp-server/livedata_server.js:1687:36
2020-10-25 00:01:17 347: at new Promise (<anonymous>)
2020-10-25 00:01:17 347: at Server.applyAsync (packages/ddp-server/livedata_server.js:1686:12)
2020-10-25 00:01:17 347: at Server.apply (packages/ddp-server/livedata_server.js:1625:26)
2020-10-25 00:01:17 347: at Server.call (packages/ddp-server/livedata_server.js:1607:17)
2020-10-25 00:01:17 347: at Object.post (app/api/server/v1/misc.js:262:26)
2020-10-25 00:01:17 347: at app/api/server/api.js:394:82
2020-10-25 00:01:17 347: at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1234:12)
2020-10-25 00:01:17 347: at Object._internalRouteActionHandler [as action] (app/api/server/api.js:394:39)
2020-10-25 00:01:17 347: at Route.share.Route.Route._callEndpoint (packages/nimble_restivus/lib/route.coffee:150:32)
2020-10-25 00:01:17 347: at packages/nimble_restivus/lib/route.coffee:59:33
2020-10-25 00:01:17 348: at packages/simple_json-routes.js:98:9
2020-10-25 00:01:17 348: => awaited here:
2020-10-25 00:01:17 348: at Promise.await ($DEPLOY_DIR/server/bundle/programs/server/npm/node_modules/meteor/promise/node_modules/meteor-promise/promise_server.js:60:12)
2020-10-25 00:01:17 348: at Server.apply (packages/ddp-server/livedata_server.js:1638:22)
2020-10-25 00:01:17 348: at Server.call (packages/ddp-server/livedata_server.js:1607:17)
2020-10-25 00:01:17 348: at Object.post (app/api/server/v1/misc.js:262:26)
2020-10-25 00:01:17 348: at app/api/server/api.js:394:82
2020-10-25 00:01:17 348: at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1234:12)
2020-10-25 00:01:17 348: at Object._internalRouteActionHandler [as action] (app/api/server/api.js:394:39)
2020-10-25 00:01:17 348: at Route.share.Route.Route._callEndpoint (packages/nimble_restivus/lib/route.coffee:150:32)
2020-10-25 00:01:17 348: at packages/nimble_restivus/lib/route.coffee:59:33
2020-10-25 00:01:17 348: at packages/simple_json-routes.js:98:9
2020-10-25 00:01:17 349: server.js:204 API ➔ debug Success {
2020-10-25 00:01:17 349: statusCode: 200,
2020-10-25 00:01:17 349: body: {
2020-10-25 00:01:17 349: message: '{"msg":"result","id":"26","error":{"isClientSafe":true,"error":"CustomOAuth","reason":"User with username <username> already exists","message":"User with username <username> already exists [CustomOAuth]","errorType":"Meteor.Error"}}',
2020-10-25 00:01:17 349: success: true
2020-10-25 00:01:17 349: }
2020-10-25 00:01:17 350: }
2020-10-25 00:24:46 188: server.js:204 Meteor ➔ method UserPresence:online -> userId: null, arguments: [{}]
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the CustomOAuth login flow and inspect how the OAuth identity's username and name are reconciled with the existing user record. Reproduce the case with differing values and verify completion by a successful login without the duplicate-username error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- mongodb, node.js, typescript
- Domain
- authentication, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100