From 9457bf88079a23d28011ff7c65faa56a548b7817 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 21 Mar 2016 11:56:33 +0100 Subject: [PATCH] OAuth server: first draft --- package.json | 5 +- server.js | 8 +++ server/controllers/api/v1/index.js | 2 + server/controllers/api/v1/users.js | 22 ++++++ server/middlewares/oauth2.js | 11 +++ server/models/users.js | 108 +++++++++++++++++++++++++++++ 6 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 server/controllers/api/v1/users.js create mode 100644 server/middlewares/oauth2.js create mode 100644 server/models/users.js diff --git a/package.json b/package.json index a5f32fe11..e94d34fa1 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "client:tsc": "cd client && npm run tsc", "client:tsc:watch": "cd client && npm run tsc:w", "client:tsc:clean": "cd client && find angular -regextype posix-egrep -regex \".*\\.(js|map)$\" -exec rm -f {} \\;", - "dev": "npm run build && concurrently \"npm run livereload\" \"npm run client:tsc:watch\" \"npm run client:sass:watch\" \"npm start\"", + "dev": "npm run build && NODE_ENV=test concurrently \"npm run livereload\" \"npm run client:tsc:watch\" \"npm run client:sass:watch\" \"npm start\"", "livereload": "livereload ./client", "start": "node server", "test": "standard && mocha server/tests", @@ -48,6 +48,7 @@ "dezalgo": "^1.0.3", "electron-spawn": "https://github.com/Chocobozzz/electron-spawn", "express": "^4.12.4", + "express-oauth-server": "https://github.com/oauthjs/express-oauth-server", "express-validator": "^2.11.0", "js-yaml": "^3.5.4", "lodash-node": "^3.10.2", @@ -62,7 +63,7 @@ "segfault-handler": "^1.0.0", "ursa": "^0.9.1", "validator": "^5.0.0", - "webtorrent": "^0.85.1", + "webtorrent": "^0.86.0", "winston": "^2.1.1", "ws": "^1.0.1" }, diff --git a/server.js b/server.js index cf594453d..f9925eb24 100644 --- a/server.js +++ b/server.js @@ -119,6 +119,14 @@ app.use(function (err, req, res, next) { res.sendStatus(err.status || 500) }) +// TODO: move into initializer +require('./server/models/users').createClient('coucou', [ 'password' ], function (err, id) { + if (err) throw err + logger.info('Client id: ' + id) + + require('./server/models/users').createUser('floflo', 'coucou', function () {}) +}) + // ----------- Create the certificates if they don't already exist ----------- peertubeCrypto.createCertsIfNotExist(function (err) { if (err) throw err diff --git a/server/controllers/api/v1/index.js b/server/controllers/api/v1/index.js index 45f07ae1f..7b3ec32c0 100644 --- a/server/controllers/api/v1/index.js +++ b/server/controllers/api/v1/index.js @@ -6,10 +6,12 @@ const router = express.Router() const podsController = require('./pods') const remoteVideosController = require('./remoteVideos') +const usersController = require('./users') const videosController = require('./videos') router.use('/pods', podsController) router.use('/remotevideos', remoteVideosController) +router.use('/users', usersController) router.use('/videos', videosController) router.use('/*', badRequest) diff --git a/server/controllers/api/v1/users.js b/server/controllers/api/v1/users.js new file mode 100644 index 000000000..acb860c66 --- /dev/null +++ b/server/controllers/api/v1/users.js @@ -0,0 +1,22 @@ +'use strict' + +var express = require('express') +var oAuth2 = require('../../../middlewares/oauth2') + +const middleware = require('../../../middlewares') +const cacheMiddleware = middleware.cache + +const router = express.Router() + +router.post('/token', cacheMiddleware.cache(false), oAuth2.token(), success) +router.get('/authenticate', cacheMiddleware.cache(false), oAuth2.authenticate(), success) + +// --------------------------------------------------------------------------- + +module.exports = router + +// --------------------------------------------------------------------------- + +function success (req, res, next) { + res.end() +} diff --git a/server/middlewares/oauth2.js b/server/middlewares/oauth2.js new file mode 100644 index 000000000..a1fa61fbb --- /dev/null +++ b/server/middlewares/oauth2.js @@ -0,0 +1,11 @@ +'use strict' + +const OAuthServer = require('express-oauth-server') + +const oAuth2 = new OAuthServer({ + model: require('../models/users') +}) + +// --------------------------------------------------------------------------- + +module.exports = oAuth2 diff --git a/server/models/users.js b/server/models/users.js new file mode 100644 index 000000000..355d991bd --- /dev/null +++ b/server/models/users.js @@ -0,0 +1,108 @@ +const mongoose = require('mongoose') + +const logger = require('../helpers/logger') + +// --------------------------------------------------------------------------- + +const oAuthTokensSchema = mongoose.Schema({ + accessToken: String, + accessTokenExpiresOn: Date, + client: { type: mongoose.Schema.Types.ObjectId, ref: 'oAuthClients' }, + refreshToken: String, + refreshTokenExpiresOn: Date, + user: { type: mongoose.Schema.Types.ObjectId, ref: 'users' } +}) +const OAuthTokensDB = mongoose.model('oAuthTokens', oAuthTokensSchema) + +const oAuthClientsSchema = mongoose.Schema({ + clientSecret: String, + grants: Array, + redirectUris: Array +}) +const OAuthClientsDB = mongoose.model('oAuthClients', oAuthClientsSchema) + +const usersSchema = mongoose.Schema({ + password: String, + username: String +}) +const UsersDB = mongoose.model('users', usersSchema) + +// --------------------------------------------------------------------------- + +const Users = { + createClient: createClient, + createUser: createUser, + getAccessToken: getAccessToken, + getClient: getClient, + getRefreshToken: getRefreshToken, + getUser: getUser, + saveToken: saveToken +} + +function createClient (secret, grants, callback) { + logger.debug('Creating client.') + + const mongo_id = new mongoose.mongo.ObjectID() + return OAuthClientsDB.create({ _id: mongo_id, clientSecret: secret, grants: grants }, function (err) { + if (err) return callback(err) + + return callback(null, mongo_id) + }) +} + +function createUser (username, password, callback) { + logger.debug('Creating user.') + + return UsersDB.create({ username: username, password: password }, callback) +} + +function getAccessToken (bearerToken, callback) { + logger.debug('Getting access token (bearerToken: ' + bearerToken + ').') + + return OAuthTokensDB.findOne({ accessToken: bearerToken }).populate('user') +} + +function getClient (clientId, clientSecret) { + logger.debug('Getting Client (clientId: ' + clientId + ', clientSecret: ' + clientSecret + ').') + + // TODO req validator + const mongo_id = new mongoose.mongo.ObjectID(clientId) + return OAuthClientsDB.findOne({ _id: mongo_id, clientSecret: clientSecret }) +} + +function getRefreshToken (refreshToken) { + logger.debug('Getting RefreshToken (refreshToken: ' + refreshToken + ').') + + return OAuthTokensDB.findOne({ refreshToken: refreshToken }) +} + +function getUser (username, password) { + logger.debug('Getting User (username: ' + username + ', password: ' + password + ').') + return UsersDB.findOne({ username: username, password: password }) +} + +function saveToken (token, client, user) { + logger.debug('Saving token for client ' + client.id + ' and user ' + user.id + '.') + + const token_to_create = { + accessToken: token.accessToken, + accessTokenExpiresOn: token.accessTokenExpiresOn, + client: client.id, + refreshToken: token.refreshToken, + refreshTokenExpiresOn: token.refreshTokenExpiresOn, + user: user.id + } + + return OAuthTokensDB.create(token_to_create, function (err, token_created) { + if (err) throw err // node-oauth2-server library use Promise.try + + token_created.client = client + token_created.user = user + + return token_created + }) +} + +// --------------------------------------------------------------------------- + +module.exports = Users