From e566891456cd6aeb72129959ddd0f7bf875c6463 Mon Sep 17 00:00:00 2001 From: Kurt Junghanns Date: Fri, 8 Dec 2017 17:08:03 +0100 Subject: [PATCH 1/7] [SSO] Started implementing the first route. Enhanced instances.js --- application/configs/instances.js | 37 ++++++ application/controllers/handler_social.js | 132 +++++++++++++++++++++- application/models/user.js | 11 ++ application/routes.js | 32 ++++++ application/server.js | 2 +- 5 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 application/configs/instances.js diff --git a/application/configs/instances.js b/application/configs/instances.js new file mode 100644 index 0000000..b14eb70 --- /dev/null +++ b/application/configs/instances.js @@ -0,0 +1,37 @@ +'use strict'; + +module.exports = { + org: { + url: 'https://slidewiki.org', + emailcheck: 'https://userservice.slidewiki.org/information/email/', + entry: 'https://slidewiki.org/SSO', + login: 'https://userservice.slidewiki.org/login', + validate: 'https://userservice.slidewiki.org/social/provider/slidewiki', + userinfo: 'https://userservice.slidewiki.org/user/{id}/profile' + }, + aksw: { + url: 'https://slidewiki.aksw.org', + emailcheck: 'https://userservice.slidewiki.aksw.org/information/email/', + entry: 'https://slidewiki.aksw.org/SSO', + login: 'https://userservice.slidewiki.aksw.org/login', + validate: 'https://userservice.slidewiki.aksw.org/social/provider/slidewiki', + userinfo: 'https://userservice.slidewiki.aksw.org/user/{id}/profile' + }, + exp: { + url: 'https://platform.experimental.slidewiki.org', + emailcheck: 'https://userservice.experimental.slidewiki.org/information/email/', + entry: 'https://platform.experimental.slidewiki.org/SSO', + login: 'https://userservice.experimental.slidewiki.org/login', + validate: 'https://userservice.experimental.slidewiki.org/social/provider/slidewiki', + userinfo: 'https://userservice.experimental.slidewiki.org/user/{id}/profile' + }, + local: { + url: 'http://localhost:3000', + emailcheck: 'http://localhost:1500/information/email/', + entry: 'http://localhost:3000/SSO', + login: 'http://localhost:1500/login', + validate: 'http://localhost:1500/social/provider/slidewiki', + userinfo: 'http://localhost:1500/user/{id}/profile' + }, + self: 'local' +}; diff --git a/application/controllers/handler_social.js b/application/controllers/handler_social.js index a9a6c37..b0e825b 100644 --- a/application/controllers/handler_social.js +++ b/application/controllers/handler_social.js @@ -12,7 +12,8 @@ const boom = require('boom'), //Boom gives us some predefined http codes and pro config = require('../configuration'), jwt = require('./jwt'), socialProvider = require('./social_provider'), - util = require('./util'); + util = require('./util'), + instances = require('../configs/instances.js'); const PROVIDERS = ['github', 'google', 'facebook'], PLATFORM_SOCIAL_URL = require('../configs/microservices').platform.uri + '/socialLogin', @@ -430,9 +431,138 @@ module.exports = { return res(providers); }); + }, + + slidewiki: (req, res) => { + if (!instances[req.query.instance]) { + return res(boom.notFound('Instance unknown.')); + } + + //get detailed user + const options = { + url: instances[req.query.instance].userinfo.replace('{id}', req.query.userid), + method: 'GET', + json: true, + headers: { + '----jwt----': req.query.jwt + } + }; + + function callback(error, response, body) { + console.log('got detailed user: ', error, response.statusCode, body); + + if (!error && (response.statusCode === 200)) { + let user = body; + user.userid = user._id + 0; + user._id = undefined; + + //check if user is already migrated + userCtrl.find({ + migratedFrom: { + instance: req.query.instance, + userid: req.query.userid + } + }) + .then((cursor) => cursor.toArray()) + .then((array) => { + if (array === undefined || array === null || array.length < 1) { + //now migrate it + return migrateUser(req, res, user); + } + else { + //do a sign in + return signInMigratedUser(req, res, user); + } + }); + } else { + console.log('Error', (response) ? response.statusCode : undefined, error, body); + return res(boom.badImplementation('Failed to retrieve user data')); //TODO redirect to homepage? + } + } + + if (process.env.NODE_ENV === 'test') { + callback(null, {statusCode: 200}, {}); + } + else + request(options, callback); } }; +function migrateUser(req, res, user) { + user.migratedFrom = { + instance: req.query.instance, + userid: user.userid + 0 + }; + user.userid = undefined; + user.reviewed = undefined; + user.suspended = undefined; + user.lastReviewDoneBy = undefined; + user.registered = (new Date()).toISOString(); + + return userCtrl.find({ + $or: [ + { + username: user.username + }, + { + email: user.email + } + ] + }) + .then((cursor) => cursor.toArray()) + .then((array) => { + if (array === undefined || array === null || array.length < 1) { + //save the user as a new one + //Send email before creating the user + return util.sendEMail(user.email, + 'Your new account on SlideWiki', + 'Dear '+user.forename+' '+user.surname+',\n\nwelcome to SlideWiki! You have migrated your account with the username '+user.username+' from '+instances[req.query.instance].url+' to '+instances[instances.self].url+'. In order to start using your account and learn how get started with the platform please navigate to the following link:\n\n'+PLATFORM_INFORMATION_URL+'/welcome\n\nGreetings,\nthe SlideWiki Team') + .then(() => { + return userCtrl.create(user) + .then((result) => { + console.log('migrated user: create result: ', result); + + if (result[0] !== undefined && result[0] !== null) { + //Error + console.log('ajv error', result, co.parseAjvValidationErrors(result)); + return res(boom.badImplementation('registration failed because data is wrong: ', co.parseAjvValidationErrors(result))); + } + + if (result.insertedCount === 1) { + //success + user._id = result.insertedId; + + return res({//TODO redirect with jwt and data is needed plus flag that this user needs a fetchUser + userid: result.insertedId, + username: user.username, + access_token: 'dummy', + expires_in: 0 + }) + .header(config.JWT.HEADER, jwt.createToken(user)); + } + + res(boom.badImplementation()); + }) + .catch((error) => { + console.log('Error - create user failed:', error, 'used user object:', user); + res(boom.badImplementation('Error', error)); + }); + }) + .catch((error) => { + console.log('Error sending the email:', error); + return res(boom.badImplementation('Error', error)); + }); + } + else { + //save user temp. to change username + } + }); +} + +function signInMigratedUser(req, res, user) { + +} + function isProviderSupported(provider) { return PROVIDERS.indexOf(provider) !== -1; } diff --git a/application/models/user.js b/application/models/user.js index b442970..5b1abeb 100644 --- a/application/models/user.js +++ b/application/models/user.js @@ -138,6 +138,17 @@ const user = { }, lastReviewDoneBy: { type: 'integer' + }, + migratedFrom: { + type: 'object', + properties: { + instance: { + type: 'String' + }, + userid: { + type: 'integer' + } + } } }, required: ['email', 'username', 'frontendLanguage'] diff --git a/application/routes.js b/application/routes.js index 6385aa8..db854db 100644 --- a/application/routes.js +++ b/application/routes.js @@ -575,6 +575,38 @@ module.exports = function (server) { } }); + server.route({ + method: 'GET', + path: '/social/useprovider/slidewiki', + handler: handlers_social.slidewiki, + config: { + validate: { + query: { + jwt: Joi.string().required().description('JWT header provided by /login'), + instance: Joi.string().required() + } + }, + tags: ['api'], + description: 'Uses JWT and gets userdata from the given instance to sign up or sign in this user', + plugins: { + 'hapi-swagger': { + responses: { + ' 200 ': { + 'description': 'Successful', + }, + ' 404 ': { + 'description': 'Instance or userid unknown.' + } + }, + payloadType: 'form' + }, + yar: { + skip: true + } + } + } + }); + server.route({ method: 'PUT', path: '/social/provider/{provider}', diff --git a/application/server.js b/application/server.js index feddd86..f9884e2 100644 --- a/application/server.js +++ b/application/server.js @@ -15,7 +15,7 @@ const hapi = require('hapi'), //Initiate the webserver with standard or given port const server = new hapi.Server({ connections: {routes: {validate: { options: {convert : false}}}}}); -let port = (!co.isEmpty(process.env.APPLICATION_PORT)) ? process.env.APPLICATION_PORT : 3000; +let port = 1500;//(!co.isEmpty(process.env.APPLICATION_PORT)) ? process.env.APPLICATION_PORT : 3000; server.connection({ port: port }); From 6602c91b787d3faff7b5fe201a0b73260d29a947 Mon Sep 17 00:00:00 2001 From: Kurt Junghanns Date: Mon, 11 Dec 2017 17:13:27 +0100 Subject: [PATCH 2/7] [SSO] Save work --- application/configs/instances.js | 14 ++- application/controllers/handler_social.js | 131 +++++++++++++++++++--- application/database/user.js | 20 ++-- application/models/user.js | 2 +- application/routes.js | 41 ++++++- 5 files changed, 179 insertions(+), 29 deletions(-) diff --git a/application/configs/instances.js b/application/configs/instances.js index b14eb70..e2c8dfa 100644 --- a/application/configs/instances.js +++ b/application/configs/instances.js @@ -7,7 +7,8 @@ module.exports = { entry: 'https://slidewiki.org/SSO', login: 'https://userservice.slidewiki.org/login', validate: 'https://userservice.slidewiki.org/social/provider/slidewiki', - userinfo: 'https://userservice.slidewiki.org/user/{id}/profile' + userinfo: 'https://userservice.slidewiki.org/user/{id}/profile', + finalize: 'https://userservice.slidewiki.org/social/finalize/{hash}' }, aksw: { url: 'https://slidewiki.aksw.org', @@ -15,7 +16,8 @@ module.exports = { entry: 'https://slidewiki.aksw.org/SSO', login: 'https://userservice.slidewiki.aksw.org/login', validate: 'https://userservice.slidewiki.aksw.org/social/provider/slidewiki', - userinfo: 'https://userservice.slidewiki.aksw.org/user/{id}/profile' + userinfo: 'https://userservice.slidewiki.aksw.org/user/{id}/profile', + finalize: 'https://userservice.slidewiki.aksw.org/social/finalize/{hash}' }, exp: { url: 'https://platform.experimental.slidewiki.org', @@ -23,7 +25,8 @@ module.exports = { entry: 'https://platform.experimental.slidewiki.org/SSO', login: 'https://userservice.experimental.slidewiki.org/login', validate: 'https://userservice.experimental.slidewiki.org/social/provider/slidewiki', - userinfo: 'https://userservice.experimental.slidewiki.org/user/{id}/profile' + userinfo: 'https://userservice.experimental.slidewiki.org/user/{id}/profile', + finalize: 'https://userservice.experimental.slidewiki.org/social/finalize/{hash}' }, local: { url: 'http://localhost:3000', @@ -31,7 +34,8 @@ module.exports = { entry: 'http://localhost:3000/SSO', login: 'http://localhost:1500/login', validate: 'http://localhost:1500/social/provider/slidewiki', - userinfo: 'http://localhost:1500/user/{id}/profile' + userinfo: 'http://localhost:1500/user/{id}/profile', + finalize: 'http://localhost:1500/social/finalize/{hash}' }, - self: 'local' + _self: 'local' }; diff --git a/application/controllers/handler_social.js b/application/controllers/handler_social.js index b0e825b..392a2e0 100644 --- a/application/controllers/handler_social.js +++ b/application/controllers/handler_social.js @@ -11,12 +11,14 @@ const boom = require('boom'), //Boom gives us some predefined http codes and pro providerCtrl = require('../database/provider'), config = require('../configuration'), jwt = require('./jwt'), + request = require('request'), socialProvider = require('./social_provider'), util = require('./util'), instances = require('../configs/instances.js'); const PROVIDERS = ['github', 'google', 'facebook'], PLATFORM_SOCIAL_URL = require('../configs/microservices').platform.uri + '/socialLogin', + PLATFORM_MIGRATE_URL = require('../configs/microservices').platform.uri + '/migrateUser', PLATFORM_INFORMATION_URL = require('../configs/microservices').platform.uri + ''; module.exports = { @@ -449,7 +451,7 @@ module.exports = { }; function callback(error, response, body) { - console.log('got detailed user: ', error, response.statusCode, body); + console.log('got detailed user: ', error, response.statusCode, body, options); if (!error && (response.statusCode === 200)) { let user = body; @@ -471,7 +473,7 @@ module.exports = { } else { //do a sign in - return signInMigratedUser(req, res, user); + return signInMigratedUser(req, res, user, array[0]); } }); } else { @@ -485,10 +487,77 @@ module.exports = { } else request(options, callback); + }, + + finalizeUser: (req, res) => { + return util.isIdentityAssigned(req.payload.email, req.payload.username) + .then((result) => { + if (result.assigned) { + return res(boom.conflict()); + } + + return userCtrl.find({_id: req.params.hash}, true) + .then((cursor) => cursor.toArray()) + .then((result) => { + //console.log('finalizeUser: result: ', result); + + switch (result.length) { + case 0: return res(boom.notFound()); + break; + case 1: let user = result[0]; + user.username = req.payload.username; + user.email = req.payload.email; + user._id = undefined; + + console.log('create new user'); + //save the user as a new one + //Send email before creating the user + return util.sendEMail(user.email, + 'Your new account on SlideWiki', + 'Dear '+user.forename+' '+user.surname+',\n\nwelcome to SlideWiki! You have migrated your account with the username '+user.username+' from '+instances[user.migratedFrom.instance].url+' to '+instances[instances._self].url+'. In order to start using your account and learn how get started with the platform please navigate to the following link:\n\n'+PLATFORM_INFORMATION_URL+'/welcome\n\nGreetings,\nthe SlideWiki Team') + .then(() => { + return userCtrl.create(user) + .then((result) => { + console.log('migrated user: create result: ', result.result); + + if (result[0] !== undefined && result[0] !== null) { + //Error + console.log('ajv error', result, co.parseAjvValidationErrors(result)); + return res(boom.badImplementation('registration failed because data is wrong: ' + co.parseAjvValidationErrors(result))); + } + + if (result.insertedCount === 1) { + //success + user._id = result.insertedId; + + return res({ + userid: result.insertedId, + username: user.username + }) + .header(config.JWT.HEADER, jwt.createToken(user)); + } + + res(boom.badImplementation()); + }) + .catch((error) => { + console.log('Error - create user failed:', error, 'used user object:', user); + res(boom.badImplementation('Error', error)); + }); + }) + .catch((error) => { + console.log('Error sending the email:', error); + return res(boom.badImplementation('Error', error)); + }); + break; + default: return res(boom.badImplementation()) + }; + }); + }); } }; function migrateUser(req, res, user) { + console.log('migrateUser()'); user.migratedFrom = { instance: req.query.instance, userid: user.userid + 0 @@ -512,33 +581,34 @@ function migrateUser(req, res, user) { .then((cursor) => cursor.toArray()) .then((array) => { if (array === undefined || array === null || array.length < 1) { + console.log('create new user'); //save the user as a new one //Send email before creating the user return util.sendEMail(user.email, 'Your new account on SlideWiki', - 'Dear '+user.forename+' '+user.surname+',\n\nwelcome to SlideWiki! You have migrated your account with the username '+user.username+' from '+instances[req.query.instance].url+' to '+instances[instances.self].url+'. In order to start using your account and learn how get started with the platform please navigate to the following link:\n\n'+PLATFORM_INFORMATION_URL+'/welcome\n\nGreetings,\nthe SlideWiki Team') + 'Dear '+user.forename+' '+user.surname+',\n\nwelcome to SlideWiki! You have migrated your account with the username '+user.username+' from '+instances[req.query.instance].url+' to '+instances[instances._self].url+'. In order to start using your account and learn how get started with the platform please navigate to the following link:\n\n'+PLATFORM_INFORMATION_URL+'/welcome\n\nGreetings,\nthe SlideWiki Team') .then(() => { return userCtrl.create(user) .then((result) => { - console.log('migrated user: create result: ', result); + console.log('migrated user: create result: ', result.result); if (result[0] !== undefined && result[0] !== null) { //Error console.log('ajv error', result, co.parseAjvValidationErrors(result)); - return res(boom.badImplementation('registration failed because data is wrong: ', co.parseAjvValidationErrors(result))); + return res(boom.badImplementation('registration failed because data is wrong: ' + co.parseAjvValidationErrors(result))); } if (result.insertedCount === 1) { //success user._id = result.insertedId; - return res({//TODO redirect with jwt and data is needed plus flag that this user needs a fetchUser - userid: result.insertedId, - username: user.username, - access_token: 'dummy', - expires_in: 0 - }) - .header(config.JWT.HEADER, jwt.createToken(user)); + return res() + .redirect(PLATFORM_MIGRATE_URL + '?data=' + encodeURIComponent(JSON.stringify({ + userid: result.insertedId, + username: user.username, + jwt: jwt.createToken(user) + }))) + .temporary(true); } res(boom.badImplementation()); @@ -554,13 +624,46 @@ function migrateUser(req, res, user) { }); } else { + console.log('save user temp.'); //save user temp. to change username + userCtrl.create(user, true) + .then((result) => { + if (result[0] !== undefined && result[0] !== null) { + //Error + console.log('ajv error', result, co.parseAjvValidationErrors(result)); + return res(boom.badData('migration failed because data is wrong: ', co.parseAjvValidationErrors(result))); + } + + if (result.insertedCount === 1) { + //success + user._id = result.insertedId; + + return res() + .redirect(PLATFORM_MIGRATE_URL + '?data=' + encodeURIComponent(JSON.stringify({ + hash: result.insertedId, + username: user.username, + email: user.email + }))) + .temporary(true); + } + + res(boom.badImplementation()); + }); } }); } -function signInMigratedUser(req, res, user) { - +function signInMigratedUser(req, res, userFromOtherInstance, userFromThisInstance) { + console.log('signInMigratedUser()'); + + //TODO update userFromThisInstance? + return res() + .redirect(PLATFORM_MIGRATE_URL + '?data=' + encodeURIComponent(JSON.stringify({ + userid: userFromThisInstance._id, + username: userFromThisInstance.username, + jwt: jwt.createToken(userFromThisInstance) + }))) + .temporary(true); } function isProviderSupported(provider) { diff --git a/application/database/user.js b/application/database/user.js index 2e98c11..e567bc0 100644 --- a/application/database/user.js +++ b/application/database/user.js @@ -2,7 +2,8 @@ const helper = require('./helper'), userModel = require('../models/user.js'), - collectionName = 'users'; + collectionName = 'users', + collectionNameTemp = 'temp_users'; // hardcoded (static) users // the attributes included are only the public user attributes needed @@ -18,13 +19,14 @@ const staticUsers = [ ]; let self = module.exports = { - create: (user) => { + create: (user, temp = false) => { + let name = (temp) ? collectionNameTemp : collectionName; return helper.connectToDatabase() - .then((dbconn) => helper.getNextIncrementationValueForCollection(dbconn, collectionName)) + .then((dbconn) => helper.getNextIncrementationValueForCollection(dbconn, name)) .then((newId) => { // console.log('newId', newId); return helper.connectToDatabase() //db connection have to be accessed again in order to work with more than one collection - .then((db2) => db2.collection(collectionName)) + .then((db2) => db2.collection(name)) .then((collection) => { let isValid = false; user._id = newId; @@ -70,17 +72,19 @@ let self = module.exports = { }); }, - delete: (userid) => { + delete: (userid, temp = false) => { + let name = (temp) ? collectionNameTemp : collectionName; return helper.connectToDatabase() - .then((dbconn) => dbconn.collection(collectionName)) + .then((dbconn) => dbconn.collection(name)) .then((collection) => collection.remove({ _id: userid })); }, - find: (query) => { + find: (query, temp = false) => { + let name = (temp) ? collectionNameTemp : collectionName; return helper.connectToDatabase() - .then((dbconn) => dbconn.collection(collectionName)) + .then((dbconn) => dbconn.collection(name)) .then((collection) => collection.find(query)); }, diff --git a/application/models/user.js b/application/models/user.js index 5b1abeb..3405fe6 100644 --- a/application/models/user.js +++ b/application/models/user.js @@ -143,7 +143,7 @@ const user = { type: 'object', properties: { instance: { - type: 'String' + type: 'string' }, userid: { type: 'integer' diff --git a/application/routes.js b/application/routes.js index db854db..c5de57c 100644 --- a/application/routes.js +++ b/application/routes.js @@ -583,7 +583,8 @@ module.exports = function (server) { validate: { query: { jwt: Joi.string().required().description('JWT header provided by /login'), - instance: Joi.string().required() + instance: Joi.string().required(), + userid: Joi.string() } }, tags: ['api'], @@ -607,6 +608,44 @@ module.exports = function (server) { } }); + server.route({ + method: 'POST', + path: '/social/finalize/{hash}', + handler: handlers_social.finalizeUser, + config: { + validate: { + params: { + hash: Joi.string() + }, + payload: Joi.object().keys({ + username: Joi.string().regex(USERNAME_REGEX), + email: Joi.string().email() + }).requiredKeys('email', 'username'), + }, + tags: ['api'], + description: 'Finalizes the migration of a user.', + plugins: { + 'hapi-swagger': { + responses: { + ' 200 ': { + 'description': 'Successful', + }, + ' 404 ': { + 'description': 'User not prepared for migration.' + }, + ' 409 ': { + 'description': 'Username or email is already in use.' + }, + }, + payloadType: 'form' + }, + yar: { + skip: true + } + } + } + }); + server.route({ method: 'PUT', path: '/social/provider/{provider}', From faf73314f31918870c83aa05118d5993599e15a8 Mon Sep 17 00:00:00 2001 From: Kurt Junghanns Date: Tue, 12 Dec 2017 16:43:56 +0100 Subject: [PATCH 3/7] [SSO] Fixed bugs --- application/controllers/handler_social.js | 40 ++++++++++++++--------- application/routes.js | 2 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/application/controllers/handler_social.js b/application/controllers/handler_social.js index 392a2e0..cd420a0 100644 --- a/application/controllers/handler_social.js +++ b/application/controllers/handler_social.js @@ -441,22 +441,25 @@ module.exports = { } //get detailed user + let headers = {}; + headers[config.JWT.HEADER] = req.query.jwt const options = { url: instances[req.query.instance].userinfo.replace('{id}', req.query.userid), method: 'GET', json: true, - headers: { - '----jwt----': req.query.jwt - } + headers: headers }; function callback(error, response, body) { - console.log('got detailed user: ', error, response.statusCode, body, options); + console.log('got detailed user: ', error, response.statusCode, body, options, body.providers); - if (!error && (response.statusCode === 200)) { + if (!error && (response.statusCode === 200) && body.username) { let user = body; user.userid = user._id + 0; user._id = undefined; + user.providers = []; + if (!user.frontendLanguage) + user.frontendLanguage = 'en' //check if user is already migrated userCtrl.find({ @@ -482,10 +485,10 @@ module.exports = { } } - if (process.env.NODE_ENV === 'test') { - callback(null, {statusCode: 200}, {}); - } - else + // if (process.env.NODE_ENV === 'test') { + // callback(null, {statusCode: 200}, {}); + // } + // else request(options, callback); }, @@ -499,7 +502,7 @@ module.exports = { return userCtrl.find({_id: req.params.hash}, true) .then((cursor) => cursor.toArray()) .then((result) => { - //console.log('finalizeUser: result: ', result); + console.log('finalizeUser: result: ', result); switch (result.length) { case 0: return res(boom.notFound()); @@ -530,11 +533,18 @@ module.exports = { //success user._id = result.insertedId; - return res({ - userid: result.insertedId, - username: user.username - }) - .header(config.JWT.HEADER, jwt.createToken(user)); + return userCtrl.delete(hash, true) + .then(() => { + return res({ + userid: result.insertedId, + username: user.username + }) + .header(config.JWT.HEADER, jwt.createToken(user)); + }) + .catch((error) => { + console.log('Error - unable to delete user from temp. collection:', error); + res(boom.badImplementation('Error', error)); + }); } res(boom.badImplementation()); diff --git a/application/routes.js b/application/routes.js index c5de57c..7ebe3c3 100644 --- a/application/routes.js +++ b/application/routes.js @@ -577,7 +577,7 @@ module.exports = function (server) { server.route({ method: 'GET', - path: '/social/useprovider/slidewiki', + path: '/social/provider/slidewiki', handler: handlers_social.slidewiki, config: { validate: { From 6ca8367bcb5d3755340d751be7a772762ae3a070 Mon Sep 17 00:00:00 2001 From: Kurt Junghanns Date: Tue, 12 Dec 2017 17:23:17 +0100 Subject: [PATCH 4/7] [SSO] Fixed bugs --- application/controllers/handler_social.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/application/controllers/handler_social.js b/application/controllers/handler_social.js index cd420a0..f15d300 100644 --- a/application/controllers/handler_social.js +++ b/application/controllers/handler_social.js @@ -458,18 +458,22 @@ module.exports = { user.userid = user._id + 0; user._id = undefined; user.providers = []; + user.groups = undefined; + user.hasPassword = false; if (!user.frontendLanguage) user.frontendLanguage = 'en' //check if user is already migrated - userCtrl.find({ + let query = { migratedFrom: { instance: req.query.instance, - userid: req.query.userid + userid: util.parseStringToInteger(req.query.userid) } - }) + }; + userCtrl.find(query) .then((cursor) => cursor.toArray()) .then((array) => { + console.log('searched for already migrated user:', query, array); if (array === undefined || array === null || array.length < 1) { //now migrate it return migrateUser(req, res, user); @@ -570,7 +574,7 @@ function migrateUser(req, res, user) { console.log('migrateUser()'); user.migratedFrom = { instance: req.query.instance, - userid: user.userid + 0 + userid: util.parseStringToInteger(user.userid) + 0 }; user.userid = undefined; user.reviewed = undefined; From 6b2a2f11950410cc41bbf582ea968b4bac084a20 Mon Sep 17 00:00:00 2001 From: Kurt Junghanns Date: Wed, 13 Dec 2017 10:59:46 +0100 Subject: [PATCH 5/7] [SSO] Fixed bugs --- application/controllers/handler_social.js | 13 +++-- application/database/user.js | 60 +++++++++++++++-------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/application/controllers/handler_social.js b/application/controllers/handler_social.js index f15d300..114a138 100644 --- a/application/controllers/handler_social.js +++ b/application/controllers/handler_social.js @@ -14,7 +14,8 @@ const boom = require('boom'), //Boom gives us some predefined http codes and pro request = require('request'), socialProvider = require('./social_provider'), util = require('./util'), - instances = require('../configs/instances.js'); + instances = require('../configs/instances.js'), + ObjectId = require('mongodb').ObjectID; const PROVIDERS = ['github', 'google', 'facebook'], PLATFORM_SOCIAL_URL = require('../configs/microservices').platform.uri + '/socialLogin', @@ -503,10 +504,10 @@ module.exports = { return res(boom.conflict()); } - return userCtrl.find({_id: req.params.hash}, true) + return userCtrl.find({_id: ObjectId(req.params.hash)}, true) .then((cursor) => cursor.toArray()) .then((result) => { - console.log('finalizeUser: result: ', result); + console.log('finalizeUser: result: ', result, req.params.hash); switch (result.length) { case 0: return res(boom.notFound()); @@ -515,6 +516,10 @@ module.exports = { user.username = req.payload.username; user.email = req.payload.email; user._id = undefined; + for(let k in user) { + if (user[k] === null) + user[k] = undefined; + } console.log('create new user'); //save the user as a new one @@ -537,7 +542,7 @@ module.exports = { //success user._id = result.insertedId; - return userCtrl.delete(hash, true) + return userCtrl.delete(ObjectId(req.params.hash), true) .then(() => { return res({ userid: result.insertedId, diff --git a/application/database/user.js b/application/database/user.js index e567bc0..a133442 100644 --- a/application/database/user.js +++ b/application/database/user.js @@ -21,27 +21,47 @@ const staticUsers = [ let self = module.exports = { create: (user, temp = false) => { let name = (temp) ? collectionNameTemp : collectionName; - return helper.connectToDatabase() - .then((dbconn) => helper.getNextIncrementationValueForCollection(dbconn, name)) - .then((newId) => { - // console.log('newId', newId); - return helper.connectToDatabase() //db connection have to be accessed again in order to work with more than one collection - .then((db2) => db2.collection(name)) - .then((collection) => { - let isValid = false; - user._id = newId; - try { - isValid = userModel(user); - if (!isValid) { - return userModel.errors; - } - return collection.insertOne(user); - } catch (e) { - console.log('user validation failed', e); - throw e; + + if (temp) { + return helper.connectToDatabase() //db connection have to be accessed again in order to work with more than one collection + .then((db2) => db2.collection(name)) + .then((collection) => { + let isValid = false; + try { + isValid = userModel(user); + if (!isValid) { + return userModel.errors; } - }); //id is created and concatinated automatically - }); + return collection.insertOne(user); + } catch (e) { + console.log('user validation failed', e); + throw e; + } + }); //id is created and concatinated automatically + } + else { + return helper.connectToDatabase() + .then((dbconn) => helper.getNextIncrementationValueForCollection(dbconn, name)) + .then((newId) => { + // console.log('newId', newId); + return helper.connectToDatabase() //db connection have to be accessed again in order to work with more than one collection + .then((db2) => db2.collection(name)) + .then((collection) => { + let isValid = false; + user._id = newId; + try { + isValid = userModel(user); + if (!isValid) { + return userModel.errors; + } + return collection.insertOne(user); + } catch (e) { + console.log('user validation failed', e); + throw e; + } + }); //id is created and concatinated automatically + }); + } }, read: (userid) => { From 020667fa428fda409e60b0312b50e7ef868abd7c Mon Sep 17 00:00:00 2001 From: Kurt Junghanns Date: Mon, 18 Dec 2017 12:49:50 +0100 Subject: [PATCH 6/7] [SSO] Added url to users attribute migratedFrom --- application/controllers/handler_social.js | 3 ++- application/models/user.js | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/application/controllers/handler_social.js b/application/controllers/handler_social.js index 114a138..4fbad0c 100644 --- a/application/controllers/handler_social.js +++ b/application/controllers/handler_social.js @@ -579,7 +579,8 @@ function migrateUser(req, res, user) { console.log('migrateUser()'); user.migratedFrom = { instance: req.query.instance, - userid: util.parseStringToInteger(user.userid) + 0 + userid: util.parseStringToInteger(user.userid) + 0, + url: instances[req.query.instance].url }; user.userid = undefined; user.reviewed = undefined; diff --git a/application/models/user.js b/application/models/user.js index 3405fe6..bc7be0b 100644 --- a/application/models/user.js +++ b/application/models/user.js @@ -147,6 +147,9 @@ const user = { }, userid: { type: 'integer' + }, + url: { + type: 'string' } } } From dfb5309a963c24001ed9d5499bd22d2bde1a8136 Mon Sep 17 00:00:00 2001 From: Kurt Junghanns Date: Tue, 19 Dec 2017 10:52:35 +0100 Subject: [PATCH 7/7] [SSO] Fixed linter issues --- application/controllers/handler_social.js | 157 +++++++++++----------- 1 file changed, 80 insertions(+), 77 deletions(-) diff --git a/application/controllers/handler_social.js b/application/controllers/handler_social.js index 4fbad0c..23849ce 100644 --- a/application/controllers/handler_social.js +++ b/application/controllers/handler_social.js @@ -1,3 +1,5 @@ +/*eslint no-case-declarations: "warn"*/ + /* Handles the requests by executing stuff and replying to the client. Uses promises to get stuff done. Instance for social function - handler.js got too big @@ -443,7 +445,7 @@ module.exports = { //get detailed user let headers = {}; - headers[config.JWT.HEADER] = req.query.jwt + headers[config.JWT.HEADER] = req.query.jwt; const options = { url: instances[req.query.instance].userinfo.replace('{id}', req.query.userid), method: 'GET', @@ -462,7 +464,7 @@ module.exports = { user.groups = undefined; user.hasPassword = false; if (!user.frontendLanguage) - user.frontendLanguage = 'en' + user.frontendLanguage = 'en'; //check if user is already migrated let query = { @@ -494,7 +496,7 @@ module.exports = { // callback(null, {statusCode: 200}, {}); // } // else - request(options, callback); + request(options, callback); }, finalizeUser: (req, res) => { @@ -510,9 +512,10 @@ module.exports = { console.log('finalizeUser: result: ', result, req.params.hash); switch (result.length) { - case 0: return res(boom.notFound()); + case 0: res(boom.notFound()); break; - case 1: let user = result[0]; + case 1: + let user = result[0]; user.username = req.payload.username; user.email = req.payload.email; user._id = undefined; @@ -524,7 +527,7 @@ module.exports = { console.log('create new user'); //save the user as a new one //Send email before creating the user - return util.sendEMail(user.email, + util.sendEMail(user.email, 'Your new account on SlideWiki', 'Dear '+user.forename+' '+user.surname+',\n\nwelcome to SlideWiki! You have migrated your account with the username '+user.username+' from '+instances[user.migratedFrom.instance].url+' to '+instances[instances._self].url+'. In order to start using your account and learn how get started with the platform please navigate to the following link:\n\n'+PLATFORM_INFORMATION_URL+'/welcome\n\nGreetings,\nthe SlideWiki Team') .then(() => { @@ -568,8 +571,8 @@ module.exports = { return res(boom.badImplementation('Error', error)); }); break; - default: return res(boom.badImplementation()) - }; + default: return res(boom.badImplementation()); + } }); }); } @@ -598,79 +601,79 @@ function migrateUser(req, res, user) { } ] }) - .then((cursor) => cursor.toArray()) - .then((array) => { - if (array === undefined || array === null || array.length < 1) { - console.log('create new user'); - //save the user as a new one - //Send email before creating the user - return util.sendEMail(user.email, - 'Your new account on SlideWiki', - 'Dear '+user.forename+' '+user.surname+',\n\nwelcome to SlideWiki! You have migrated your account with the username '+user.username+' from '+instances[req.query.instance].url+' to '+instances[instances._self].url+'. In order to start using your account and learn how get started with the platform please navigate to the following link:\n\n'+PLATFORM_INFORMATION_URL+'/welcome\n\nGreetings,\nthe SlideWiki Team') - .then(() => { - return userCtrl.create(user) - .then((result) => { - console.log('migrated user: create result: ', result.result); - - if (result[0] !== undefined && result[0] !== null) { - //Error - console.log('ajv error', result, co.parseAjvValidationErrors(result)); - return res(boom.badImplementation('registration failed because data is wrong: ' + co.parseAjvValidationErrors(result))); - } + .then((cursor) => cursor.toArray()) + .then((array) => { + if (array === undefined || array === null || array.length < 1) { + console.log('create new user'); + //save the user as a new one + //Send email before creating the user + return util.sendEMail(user.email, + 'Your new account on SlideWiki', + 'Dear '+user.forename+' '+user.surname+',\n\nwelcome to SlideWiki! You have migrated your account with the username '+user.username+' from '+instances[req.query.instance].url+' to '+instances[instances._self].url+'. In order to start using your account and learn how get started with the platform please navigate to the following link:\n\n'+PLATFORM_INFORMATION_URL+'/welcome\n\nGreetings,\nthe SlideWiki Team') + .then(() => { + return userCtrl.create(user) + .then((result) => { + console.log('migrated user: create result: ', result.result); - if (result.insertedCount === 1) { - //success - user._id = result.insertedId; - - return res() - .redirect(PLATFORM_MIGRATE_URL + '?data=' + encodeURIComponent(JSON.stringify({ - userid: result.insertedId, - username: user.username, - jwt: jwt.createToken(user) - }))) - .temporary(true); - } + if (result[0] !== undefined && result[0] !== null) { + //Error + console.log('ajv error', result, co.parseAjvValidationErrors(result)); + return res(boom.badImplementation('registration failed because data is wrong: ' + co.parseAjvValidationErrors(result))); + } - res(boom.badImplementation()); - }) - .catch((error) => { - console.log('Error - create user failed:', error, 'used user object:', user); - res(boom.badImplementation('Error', error)); - }); - }) - .catch((error) => { - console.log('Error sending the email:', error); - return res(boom.badImplementation('Error', error)); - }); - } - else { - console.log('save user temp.'); - //save user temp. to change username - userCtrl.create(user, true) - .then((result) => { - if (result[0] !== undefined && result[0] !== null) { - //Error - console.log('ajv error', result, co.parseAjvValidationErrors(result)); - return res(boom.badData('migration failed because data is wrong: ', co.parseAjvValidationErrors(result))); - } + if (result.insertedCount === 1) { + //success + user._id = result.insertedId; + + return res() + .redirect(PLATFORM_MIGRATE_URL + '?data=' + encodeURIComponent(JSON.stringify({ + userid: result.insertedId, + username: user.username, + jwt: jwt.createToken(user) + }))) + .temporary(true); + } - if (result.insertedCount === 1) { - //success - user._id = result.insertedId; - - return res() - .redirect(PLATFORM_MIGRATE_URL + '?data=' + encodeURIComponent(JSON.stringify({ - hash: result.insertedId, - username: user.username, - email: user.email - }))) - .temporary(true); - } + res(boom.badImplementation()); + }) + .catch((error) => { + console.log('Error - create user failed:', error, 'used user object:', user); + res(boom.badImplementation('Error', error)); + }); + }) + .catch((error) => { + console.log('Error sending the email:', error); + return res(boom.badImplementation('Error', error)); + }); + } + else { + console.log('save user temp.'); + //save user temp. to change username + userCtrl.create(user, true) + .then((result) => { + if (result[0] !== undefined && result[0] !== null) { + //Error + console.log('ajv error', result, co.parseAjvValidationErrors(result)); + return res(boom.badData('migration failed because data is wrong: ', co.parseAjvValidationErrors(result))); + } - res(boom.badImplementation()); - }); - } - }); + if (result.insertedCount === 1) { + //success + user._id = result.insertedId; + + return res() + .redirect(PLATFORM_MIGRATE_URL + '?data=' + encodeURIComponent(JSON.stringify({ + hash: result.insertedId, + username: user.username, + email: user.email + }))) + .temporary(true); + } + + res(boom.badImplementation()); + }); + } + }); } function signInMigratedUser(req, res, userFromOtherInstance, userFromThisInstance) {