1
+ /*
2
+ * Copyright (C) 2014 TopCoder Inc., All Rights Reserved.
3
+ *
4
+ * @version 1.0
5
+ * @author TCSASSEMBLER
6
+ */
7
+ "use strict" ;
8
+
9
+ var async = require ( 'async' ) ;
10
+ var _ = require ( 'underscore' ) ;
11
+ var request = require ( 'request' ) ;
12
+
13
+ var IllegalArgumentError = require ( '../errors/IllegalArgumentError' ) ;
14
+ var NotFoundError = require ( '../errors/NotFoundError' ) ;
15
+
16
+ /**
17
+ * The login page.
18
+ */
19
+ var LOGIN = "login" ;
20
+
21
+ /**
22
+ * The register page.
23
+ */
24
+ var REGISTER = "register" ;
25
+
26
+ /**
27
+ * Set the name by provider id.
28
+ *
29
+ * @param resp - the json String
30
+ * @param socialAccount - the socialAccount instance
31
+ * @param helper - the helper instance
32
+ * @returns socialAccount - the socialAccount instance
33
+ */
34
+ function setName ( resp , socialAccount , helper ) {
35
+ var providerId = socialAccount . providerId ;
36
+
37
+ if ( providerId === helper . socialProviders . twitter ) {
38
+ socialAccount . name = resp . screen_name ;
39
+ } else if ( providerId === helper . socialProviders . github ) {
40
+ socialAccount . name = resp . nickname ;
41
+ } else if ( providerId === helper . socialProviders . ad ) {
42
+ socialAccount . name = resp . nickname ;
43
+ socialAccount . enterpriseLogin = true ;
44
+ } else {
45
+ socialAccount . name = '' ;
46
+ }
47
+
48
+ return socialAccount ;
49
+ }
50
+
51
+ /**
52
+ * Parse the response json String to entity.
53
+ *
54
+ * @param resp - the response json String.
55
+ * @param helper - the helper instance
56
+ * @returns socialAccount - the parsed socialAccount instance.
57
+ */
58
+ function parseUserInfo ( resp , helper ) {
59
+ //set the default value
60
+ var socialAccount = {
61
+ "name" : '' ,
62
+ "email" : '' ,
63
+ "givenName" : '' ,
64
+ "familyName" : '' ,
65
+ "emailVerified" : false ,
66
+ "providerId" : 0 ,
67
+ "enterpriseLogin" : false ,
68
+ "socialUserId" : '' ,
69
+ "jsonWebToken" : '' ,
70
+ "accessToken" : ''
71
+ } ;
72
+
73
+ if ( _ . isDefined ( resp . identities ) && resp . identities . length > 0 ) {
74
+ socialAccount . socialUserId = resp . identities [ 0 ] . user_id ;
75
+ }
76
+
77
+ helper . getProviderId ( resp . user_id , function ( tmp , providerId ) {
78
+ socialAccount . providerId = providerId ;
79
+ } ) ;
80
+ socialAccount = setName ( resp , socialAccount , helper ) ;
81
+
82
+ if ( _ . isDefined ( resp . email ) ) {
83
+ socialAccount . email = resp . email ;
84
+ }
85
+
86
+ if ( _ . isDefined ( resp . email_verified ) ) {
87
+ socialAccount . emailVerified = resp . email_verified ;
88
+ }
89
+
90
+ if ( _ . isDefined ( resp . family_name ) ) {
91
+ socialAccount . familyName = resp . family_name ;
92
+ }
93
+
94
+ if ( _ . isDefined ( resp . given_name ) ) {
95
+ socialAccount . givenName = resp . given_name ;
96
+ }
97
+
98
+ return socialAccount ;
99
+ }
100
+
101
+ /**
102
+ * The method that exposes the auth0 Callback API.
103
+ */
104
+ exports . action = {
105
+ name : 'auth0Callback' ,
106
+ description : 'The Auth0 Callback Method' ,
107
+ inputs : {
108
+ required : [ 'code' ] ,
109
+ optional : [ 'state' ]
110
+ } ,
111
+ blockedConnectionTypes : [ ] ,
112
+ outputExample : { } ,
113
+ version : 'v2' ,
114
+ transaction : 'write' ,
115
+ databases : [ "common_oltp" ] ,
116
+ run : function ( api , connection , next ) {
117
+ var helper = api . helper , code = connection . params . code , state = connection . params . state ,
118
+ dbConnectionMap = connection . dbConnectionMap , sqlParams = { } , accessToken , idToken , responseResult = { } ,
119
+ socialAccount , foundUserId = '' , nextPage = '' ;
120
+
121
+ api . log ( "Executing auth0Callback#run" , 'debug' ) ;
122
+ api . log ( "code: " + code , 'debug' ) ;
123
+ api . log ( "state: " + state , 'debug' ) ;
124
+
125
+ if ( ! connection . dbConnectionMap ) {
126
+ api . helper . handleNoConnection ( api , connection , next ) ;
127
+ return ;
128
+ }
129
+
130
+ async . waterfall ( [
131
+ function ( cb ) {
132
+ if ( _ . isDefined ( state ) ) {
133
+ var urls = state . split ( "?" ) , np , params ;
134
+ if ( urls . length > 1 ) {
135
+ np = decodeURI ( urls [ 0 ] ) ;
136
+ params = urls [ 1 ] . split ( "&" ) ;
137
+ if ( params . length > 1 ) {
138
+ nextPage = np ;
139
+ } else {
140
+ nextPage = decodeURI ( state ) ;
141
+ }
142
+ } else {
143
+ nextPage = decodeURI ( state ) ;
144
+ }
145
+ responseResult . state = state ;
146
+ }
147
+ responseResult . code = code ;
148
+
149
+ cb ( ) ;
150
+ } , function ( cb ) {
151
+ //get access token from auth0
152
+ request . post ( "https://" + api . config . general . oauthDomain + ".auth0.com/oauth/token" , function ( err , res , body ) {
153
+ api . log ( "response body: " + body , 'debug' ) ;
154
+ api . log ( "err: " + err , 'debug' ) ;
155
+ if ( err || ( res . statusCode !== 200 && res . statusCode !== 201 ) ) {
156
+ cb ( new IllegalArgumentError ( "Fails to get access token from auth0." ) ) ;
157
+ return ;
158
+ }
159
+ var resp = JSON . parse ( body ) ;
160
+ accessToken = resp . access_token ;
161
+ idToken = resp . id_token ;
162
+ cb ( ) ;
163
+ } ) . form ( {
164
+ "client_id" : api . config . general . oauthClientId ,
165
+ "client_secret" : api . config . auth0 . clientSecret ,
166
+ "redirect_uri" : api . config . auth0 . serverName + api . config . auth0 . redirectUrl ,
167
+ "grant_type" : "authorization_code" ,
168
+ "code" : code ,
169
+ "scope" : "openid"
170
+ } ) ;
171
+ } , function ( cb ) {
172
+ //get user info from auth0
173
+ request ( "https://" + api . config . general . oauthDomain + ".auth0.com/userinfo?access_token=" + accessToken ,
174
+ function ( err , res , body ) {
175
+ api . log ( "response body: " + body , 'debug' ) ;
176
+ if ( err || ( res . statusCode !== 200 && res . statusCode !== 201 ) ) {
177
+ cb ( new IllegalArgumentError ( "Fails to get user info from auth0." ) ) ;
178
+ return ;
179
+ }
180
+
181
+ var resp = JSON . parse ( body ) ;
182
+ socialAccount = parseUserInfo ( resp , helper ) ;
183
+ socialAccount . accessToken = accessToken ;
184
+ socialAccount . jsonWebToken = idToken ;
185
+
186
+ cb ( ) ;
187
+ } ) ;
188
+ } , function ( cb ) {
189
+ if ( socialAccount . enterpriseLogin === true ) {
190
+ api . log ( "ldap login - get user" , "debug" ) ;
191
+ sqlParams . handle = socialAccount . name ;
192
+ api . dataAccess . executeQuery ( 'get_user_by_handle' , sqlParams , dbConnectionMap , cb ) ;
193
+ } else {
194
+ cb ( null , null ) ;
195
+ }
196
+ } , function ( data , cb ) {
197
+ if ( socialAccount . enterpriseLogin === true ) {
198
+ api . log ( "ldap login - get password" , "debug" ) ;
199
+ if ( data . length !== 0 ) {
200
+ responseResult . handle = data [ 0 ] . handle ;
201
+ responseResult . userId = data [ 0 ] . id ;
202
+ sqlParams . userId = data [ 0 ] . id ;
203
+ } else {
204
+ responseResult . handle = '' ;
205
+ responseResult . userId = 0 ;
206
+ sqlParams . userId = 0 ;
207
+ }
208
+
209
+ api . dataAccess . executeQuery ( 'get_password_by_user_id' , sqlParams , dbConnectionMap , cb ) ;
210
+ } else {
211
+ cb ( null , null ) ;
212
+ }
213
+ } , function ( data , cb ) {
214
+ if ( socialAccount . enterpriseLogin === true ) {
215
+ api . log ( "ldap login - forward" , "debug" ) ;
216
+ if ( data . length !== 0 ) {
217
+ responseResult . password = data [ 0 ] . password ;
218
+ } else {
219
+ responseResult . password = '' ;
220
+ }
221
+
222
+ responseResult . result = LOGIN ;
223
+ responseResult . nextPage = nextPage ;
224
+ responseResult . socialAccount = socialAccount ;
225
+ connection . response = responseResult ;
226
+ next ( connection , true ) ;
227
+ return ;
228
+ }
229
+
230
+ if ( socialAccount . socialUserId !== '' ) {
231
+ api . log ( "social login" , "debug" ) ;
232
+ sqlParams . socialUserId = socialAccount . socialUserId ;
233
+ sqlParams . providerId = socialAccount . providerId ;
234
+ api . dataAccess . executeQuery ( 'get_user_id_by_social_user_id_and_provider_id' , sqlParams ,
235
+ dbConnectionMap , cb ) ;
236
+ } else {
237
+ cb ( null , null ) ;
238
+ }
239
+ } ,
240
+ function ( data , cb ) {
241
+ if ( data !== null && data . length > 0 ) {
242
+ foundUserId = data [ 0 ] . user_id ;
243
+ }
244
+ api . log ( "foundUserId:" + foundUserId , "debug" ) ;
245
+
246
+ if ( foundUserId === null || foundUserId === '' ) {
247
+ if ( socialAccount . email === '' && socialAccount . name === '' ) {
248
+ cb ( new NotFoundError ( "The social account should have at least one valid email or one valid username." ) ) ;
249
+ return ;
250
+ }
251
+
252
+ async . parallel ( {
253
+ getUserIdByEmail : function ( cbx ) {
254
+ if ( socialAccount . email !== '' ) {
255
+ sqlParams . email = socialAccount . email ;
256
+ if ( socialAccount . emailVerified === true ) {
257
+ sqlParams . emailVerified = 't' ;
258
+ } else {
259
+ sqlParams . emailVerified = 'f' ;
260
+ }
261
+ sqlParams . providerId = socialAccount . providerId ;
262
+ api . dataAccess . executeQuery ( 'get_user_id_by_social_account_email' , sqlParams ,
263
+ dbConnectionMap , cbx ) ;
264
+ } else {
265
+ cbx ( ) ;
266
+ }
267
+ } ,
268
+ getUserIdByName : function ( cbx ) {
269
+ if ( socialAccount . name !== '' ) {
270
+ sqlParams . userName = socialAccount . name ;
271
+ sqlParams . providerId = socialAccount . providerId ;
272
+ api . dataAccess . executeQuery ( 'get_user_id_by_social_account_name' , sqlParams ,
273
+ dbConnectionMap , cbx ) ;
274
+ } else {
275
+ cbx ( ) ;
276
+ }
277
+ }
278
+ } , cb ) ;
279
+ } else {
280
+ cb ( null , null ) ;
281
+ }
282
+ } , function ( data , cb ) {
283
+ api . log ( "foundUserId:" + foundUserId , "debug" ) ;
284
+ if ( foundUserId === null || foundUserId === '' ) {
285
+ if ( data !== null && data . getUserIdByEmail !== null && data . getUserIdByEmail !== undefined
286
+ && data . getUserIdByEmail . length > 0 ) {
287
+ foundUserId = data . getUserIdByEmail [ 0 ] . user_id ;
288
+ } else if ( data !== null && data . getUserIdByName !== null && data . getUserIdByName !== undefined
289
+ && data . getUserIdByName . length > 0 ) {
290
+ foundUserId = data . getUserIdByName [ 0 ] . user_id ;
291
+ }
292
+
293
+ if ( foundUserId !== null && foundUserId !== '' ) {
294
+ sqlParams . socialUserId = socialAccount . socialUserId ;
295
+ sqlParams . userId = foundUserId ;
296
+ api . dataAccess . executeQuery ( 'update_social_user_id' , sqlParams , dbConnectionMap , cb ) ;
297
+ } else {
298
+ cb ( null ) ;
299
+ }
300
+ } else {
301
+ cb ( null ) ;
302
+ }
303
+ } , function ( cb ) {
304
+ if ( foundUserId !== null && foundUserId !== '' ) {
305
+ sqlParams . userId = foundUserId ;
306
+ api . dataAccess . executeQuery ( 'get_user_by_user_id' , sqlParams , dbConnectionMap , cb ) ;
307
+ } else {
308
+ cb ( null , null ) ;
309
+ }
310
+ } , function ( data , cb ) {
311
+ if ( foundUserId !== null && foundUserId !== '' ) {
312
+ if ( data . length !== 0 ) {
313
+ responseResult . handle = data [ 0 ] . handle ;
314
+ responseResult . userId = data [ 0 ] . id ;
315
+ sqlParams . userId = data [ 0 ] . id ;
316
+ } else {
317
+ responseResult . handle = '' ;
318
+ responseResult . userId = 0 ;
319
+ sqlParams . userId = 0 ;
320
+ }
321
+
322
+ api . dataAccess . executeQuery ( 'get_password_by_user_id' , sqlParams , dbConnectionMap , cb ) ;
323
+ } else {
324
+ cb ( null , null ) ;
325
+ }
326
+ } , function ( data , cb ) {
327
+ //found user, redirect to next page
328
+ if ( foundUserId !== null && foundUserId !== '' ) {
329
+ if ( data . length !== 0 ) {
330
+ responseResult . password = data [ 0 ] . password ;
331
+ } else {
332
+ responseResult . password = '' ;
333
+ }
334
+
335
+ responseResult . result = LOGIN ;
336
+ responseResult . nextPage = nextPage ;
337
+ responseResult . socialAccount = socialAccount ;
338
+
339
+ connection . response = responseResult ;
340
+ next ( connection , true ) ;
341
+ return ;
342
+ }
343
+
344
+ //did not find the user, redirect to register page
345
+ responseResult . regUrl = "http://www.topcoder.com/?action=callback#access_token="
346
+ + socialAccount . accessToken + "&id_token="
347
+ + socialAccount . jsonWebToken
348
+ + "&token_type=bearer&state=http%3A%2F%2Fwww.topcoder.com" ;
349
+
350
+ responseResult . nextPage = nextPage ;
351
+ responseResult . result = REGISTER ;
352
+ responseResult . socialAccount = socialAccount ;
353
+ connection . response = responseResult ;
354
+ cb ( ) ;
355
+ }
356
+
357
+ ] , function ( err ) {
358
+ if ( err ) {
359
+ helper . handleError ( api , connection , err ) ;
360
+ }
361
+
362
+ next ( connection , true ) ;
363
+ } ) ;
364
+ }
365
+ } ;
0 commit comments