@@ -6,6 +6,7 @@ import { HTTP } from 'meteor/http';
66import { ServiceConfiguration } from 'meteor/service-configuration' ;
77import _ from 'underscore' ;
88
9+ import { normalizers , fromTemplate , renameInvalidProperties } from './transform_helpers' ;
910import { mapRolesFromSSO , updateRolesFromSSO } from './oauth_helpers' ;
1011import { Logger } from '../../logger' ;
1112import { Users } from '../../models' ;
@@ -17,107 +18,6 @@ const logger = new Logger('CustomOAuth');
1718const Services = { } ;
1819const 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-
12121export 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