Skip to content

Commit bfd8f06

Browse files
committed
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into adm/users_and_rooms
* 'develop' of github.com:RocketChat/Rocket.Chat: [IMPROVE] Administration -> Mailer Rewrite to React. (#17191) Regression: Storybook added flowrouter group mock (#17321) [NEW] Feature/custom oauth mail field and interpolation for mapped fields (#15690)
2 parents b345151 + 03cddfd commit bfd8f06

File tree

17 files changed

+495
-249
lines changed

17 files changed

+495
-249
lines changed

.storybook/mocks/meteor.js

+3
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ export const check = () => {};
6464

6565
export const FlowRouter = {
6666
route: () => {},
67+
group: () => ({
68+
route: () => {},
69+
}),
6770
};
6871

6972
export const BlazeLayout = {};

app/custom-oauth/server/custom_oauth_server.js

+49-126
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { HTTP } from 'meteor/http';
66
import { ServiceConfiguration } from 'meteor/service-configuration';
77
import _ from 'underscore';
88

9+
import { normalizers, fromTemplate, renameInvalidProperties } from './transform_helpers';
910
import { mapRolesFromSSO, updateRolesFromSSO } from './oauth_helpers';
1011
import { Logger } from '../../logger';
1112
import { Users } from '../../models';
@@ -17,107 +18,6 @@ const logger = new Logger('CustomOAuth');
1718
const Services = {};
1819
const BeforeUpdateOrCreateUserFromExternalService = [];
1920

20-
const normalizers = {
21-
// Set 'id' to '_id' for any sources that provide it
22-
_id(identity) {
23-
if (identity._id && !identity.id) {
24-
identity.id = identity._id;
25-
}
26-
},
27-
28-
// Fix for Reddit
29-
redit(identity) {
30-
if (identity.result) {
31-
return identity.result;
32-
}
33-
},
34-
35-
// Fix WordPress-like identities having 'ID' instead of 'id'
36-
wordpress(identity) {
37-
if (identity.ID && !identity.id) {
38-
identity.id = identity.ID;
39-
}
40-
},
41-
42-
// Fix Auth0-like identities having 'user_id' instead of 'id'
43-
user_id(identity) {
44-
if (identity.user_id && !identity.id) {
45-
identity.id = identity.user_id;
46-
}
47-
},
48-
49-
characterid(identity) {
50-
if (identity.CharacterID && !identity.id) {
51-
identity.id = identity.CharacterID;
52-
}
53-
},
54-
55-
// Fix Dataporten having 'user.userid' instead of 'id'
56-
dataporten(identity) {
57-
if (identity.user && identity.user.userid && !identity.id) {
58-
if (identity.user.userid_sec && identity.user.userid_sec[0]) {
59-
identity.id = identity.user.userid_sec[0];
60-
} else {
61-
identity.id = identity.user.userid;
62-
}
63-
identity.email = identity.user.email;
64-
}
65-
},
66-
67-
// Fix for Xenforo [BD]API plugin for 'user.user_id; instead of 'id'
68-
xenforo(identity) {
69-
if (identity.user && identity.user.user_id && !identity.id) {
70-
identity.id = identity.user.user_id;
71-
identity.email = identity.user.user_email;
72-
}
73-
},
74-
75-
// Fix general 'phid' instead of 'id' from phabricator
76-
phabricator(identity) {
77-
if (identity.phid && !identity.id) {
78-
identity.id = identity.phid;
79-
}
80-
},
81-
82-
// Fix Keycloak-like identities having 'sub' instead of 'id'
83-
kaycloak(identity) {
84-
if (identity.sub && !identity.id) {
85-
identity.id = identity.sub;
86-
}
87-
},
88-
89-
// Fix OpenShift identities where id is in 'metadata' object
90-
openshift(identity) {
91-
if (!identity.id && identity.metadata && identity.metadata.uid) {
92-
identity.id = identity.metadata.uid;
93-
identity.name = identity.fullName;
94-
}
95-
},
96-
97-
// Fix general 'userid' instead of 'id' from provider
98-
userid(identity) {
99-
if (identity.userid && !identity.id) {
100-
identity.id = identity.userid;
101-
}
102-
},
103-
104-
// Fix Nextcloud provider
105-
nextcloud(identity) {
106-
if (!identity.id && identity.ocs && identity.ocs.data && identity.ocs.data.id) {
107-
identity.id = identity.ocs.data.id;
108-
identity.name = identity.ocs.data.displayname;
109-
identity.email = identity.ocs.data.email;
110-
}
111-
},
112-
113-
// Fix when authenticating from a meteor app with 'emails' field
114-
meteor(identity) {
115-
if (!identity.email && (identity.emails && Array.isArray(identity.emails) && identity.emails.length >= 1)) {
116-
identity.email = identity.emails[0].address ? identity.emails[0].address : undefined;
117-
}
118-
},
119-
};
120-
12121
export class CustomOAuth {
12222
constructor(name, options) {
12323
logger.debug('Init CustomOAuth', name, options);
@@ -174,6 +74,7 @@ export class CustomOAuth {
17474
this.tokenSentVia = options.tokenSentVia;
17575
this.identityTokenSentVia = options.identityTokenSentVia;
17676
this.usernameField = (options.usernameField || '').trim();
77+
this.emailField = (options.emailField || '').trim();
17778
this.nameField = (options.nameField || '').trim();
17879
this.avatarField = (options.avatarField || '').trim();
17980
this.mergeUsers = options.mergeUsers;
@@ -334,6 +235,10 @@ export class CustomOAuth {
334235
identity.username = this.getUsername(identity);
335236
}
336237

238+
if (this.emailField) {
239+
identity.email = this.getEmail(identity);
240+
}
241+
337242
if (this.avatarField) {
338243
identity.avatarUrl = this.getAvatarUrl(identity);
339244
}
@@ -344,50 +249,64 @@ export class CustomOAuth {
344249
identity.name = this.getName(identity);
345250
}
346251

347-
return identity;
252+
return renameInvalidProperties(identity);
348253
}
349254

350255
retrieveCredential(credentialToken, credentialSecret) {
351256
return OAuth.retrieveCredential(credentialToken, credentialSecret);
352257
}
353258

354259
getUsername(data) {
355-
let username = '';
260+
try {
261+
const value = fromTemplate(this.usernameField, data);
262+
263+
if (!value) {
264+
throw new Meteor.Error('field_not_found', `Username field "${ this.usernameField }" not found in data`, data);
265+
}
266+
return value;
267+
} catch (error) {
268+
throw new Error('CustomOAuth: Failed to extract username', error.message);
269+
}
270+
}
356271

357-
username = this.usernameField.split('.').reduce(function(prev, curr) {
358-
return prev ? prev[curr] : undefined;
359-
}, data);
272+
getEmail(data) {
273+
try {
274+
const value = fromTemplate(this.emailField, data);
360275

361-
if (!username) {
362-
throw new Meteor.Error('field_not_found', `Username field "${ this.usernameField }" not found in data`, data);
276+
if (!value) {
277+
throw new Meteor.Error('field_not_found', `Email field "${ this.emailField }" not found in data`, data);
278+
}
279+
return value;
280+
} catch (error) {
281+
throw new Error('CustomOAuth: Failed to extract email', error.message);
363282
}
364-
return username;
365283
}
366284

367285
getCustomName(data) {
368-
let customName = '';
286+
try {
287+
const value = fromTemplate(this.nameField, data);
369288

370-
customName = this.nameField.split('.').reduce(function(prev, curr) {
371-
return prev ? prev[curr] : undefined;
372-
}, data);
289+
if (!value) {
290+
return this.getName(data);
291+
}
373292

374-
if (!customName) {
375-
return this.getName(data);
293+
return value;
294+
} catch (error) {
295+
throw new Error('CustomOAuth: Failed to extract custom name', error.message);
376296
}
377-
378-
return customName;
379297
}
380298

381299
getAvatarUrl(data) {
382-
const avatarUrl = this.avatarField.split('.').reduce(function(prev, curr) {
383-
return prev ? prev[curr] : undefined;
384-
}, data);
300+
try {
301+
const value = fromTemplate(this.avatarField, data);
385302

386-
if (!avatarUrl) {
387-
logger.debug(`Avatar field "${ this.avatarField }" not found in data`, data);
303+
if (!value) {
304+
logger.debug(`Avatar field "${ this.avatarField }" not found in data`, data);
305+
}
306+
return value;
307+
} catch (error) {
308+
throw new Error('CustomOAuth: Failed to extract avatar url', error.message);
388309
}
389-
390-
return avatarUrl;
391310
}
392311

393312
getName(identity) {
@@ -438,11 +357,15 @@ export class CustomOAuth {
438357
}
439358

440359
if (this.usernameField) {
441-
user.username = this.getUsername(user.services[this.name]);
360+
user.username = user.services[this.name].username;
361+
}
362+
363+
if (this.emailField) {
364+
user.email = user.services[this.name].email;
442365
}
443366

444367
if (this.nameField) {
445-
user.name = this.getCustomName(user.services[this.name]);
368+
user.name = user.services[this.name].name;
446369
}
447370

448371
if (this.mergeRoles) {

0 commit comments

Comments
 (0)