Skip to content
This repository was archived by the owner on Jan 23, 2025. It is now read-only.

Commit 8ed3154

Browse files
committed
TopCoder NodeJS Auth0 Callback API v1.0
1 parent ada065c commit 8ed3154

22 files changed

+778
-5
lines changed

actions/auth0.js

+365
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
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

Comments
 (0)