diff --git a/server/models/ApiKey.js b/server/models/ApiKey.js new file mode 100644 index 0000000..d846f04 --- /dev/null +++ b/server/models/ApiKey.js @@ -0,0 +1,29 @@ +const mongoose = require('mongoose'); +mongoose.set('useFindAndModify', false); +const crypto = require("crypto"); +//mongoose.set('debug', true) + + +const schema = new mongoose.Schema({ + user: { + type: mongoose.Types.ObjectId, ref: 'User' + }, + created: { + type: Date, + default: Date.now + }, + updated: { + type: Date, + default: Date.now + }, + apiKey: { + type: String, + default: function() { + return crypto.randomBytes(64).toString('hex'); + }, + index: true + } +}); + + +module.exports = mongoose.model('ApiKey', schema) \ No newline at end of file diff --git a/server/mongo.js b/server/mongo.js index a22e4ec..9e1e024 100644 --- a/server/mongo.js +++ b/server/mongo.js @@ -36,6 +36,7 @@ const Destroy = require('./models/Destroy'); const User = require('./models/User'); const Scenario = require('./models/Scenario'); const VmType = require('./models/VmType'); +const ApiKey = require('./models/ApiKey'); const getOid = async (oid, reply) => { try { @@ -130,6 +131,7 @@ module.exports = { destroy: _m(Destroy), scenario: mScenarios, vmtype: _m(VmType), + apiKey: _m(ApiKey), user: { get: async (filter, reply) => { return get(User, filter, reply); @@ -149,7 +151,6 @@ module.exports = { } } - async function asyncForEach(array, callback) { for (let index = 0; index < array.length; index++) { await callback(array[index], index, array); diff --git a/server/passport.js b/server/passport.js index 002f0e8..2911468 100644 --- a/server/passport.js +++ b/server/passport.js @@ -197,29 +197,42 @@ module.exports.init = function(app){ }); }; -module.exports.ensureAuthenticatedDoLogin = function(req, res, next) { - if ( req.isAuthenticated() ) { +async function isApiKeyAuthenticated(req) { + if (req.query && req.query.apiKey){ + let key = req.query.apiKey; + var result = await db.apiKey.get({apiKey: key}); + if ( result.length > 0 ) { + req.user = result[0].user; + } + return result.length > 0; + }else { + return false; + } +} + +module.exports.ensureAuthenticatedDoLogin = async function(req, res, next) { + if ( await isApiKeyAuthenticated(req) || req.isAuthenticated() ) { return next(); } res.redirect('/login'); }; -module.exports.ensureAuthenticated = function(req, res, next) { - if ( req.isAuthenticated() ) { +module.exports.ensureAuthenticated = async function(req, res, next) { + if ( await isApiKeyAuthenticated(req) || req.isAuthenticated() ) { return next(); } res.status(401).send({"error": "Unauthorized"}); }; -module.exports.ensureAuthenticatedAndAdmin = function(req, res, next) { - if ( req.isAuthenticated() && (req.user.role === 'admin' || req.user.role === 'superadmin') ) { +module.exports.ensureAuthenticatedAndAdmin = async function(req, res, next) { + if ( ( await isApiKeyAuthenticated(req) || req.isAuthenticated()) && (req.user.role === 'admin' || req.user.role === 'superadmin') ) { return next(); } res.status(401).send({"error": "Unauthorized"}); }; -module.exports.ensureAuthenticatedAndIsMe = function (req, res, next) { - if ( req.isAuthenticated() ) { +module.exports.ensureAuthenticatedAndIsMe = async function (req, res, next) { + if ( await isApiKeyAuthenticated(req) || req.isAuthenticated() ) { if ( req.user._id == req.params.userId || req.user.role === 'admin' || req.user.role === 'superadmin' ) { return next(); } else { diff --git a/server/server.js b/server/server.js index d9f7472..4e836b9 100644 --- a/server/server.js +++ b/server/server.js @@ -106,12 +106,22 @@ const options = { "email": "DL-Enterprise-ArchitectsGEAR@qlik.com" } }, - "servers": [ - { + servers: [{ "url": "/api/v1", "description": "Production Server" - } - ] + }], + components: { + securitySchemes: { + ApiKeyAuth: { + type: "apiKey", + name: "apiKey", + in: "query" + } + }, + }, + security: [{ + ApiKeyAuth: [] + }] }, // List of files to be processes. You can also set globs './routes/*.js' apis: [ @@ -119,7 +129,7 @@ const options = { 'server/routes/api-users.js', 'server/routes/api-provisions.js', 'server/routes/api-destroyprovisions.js', - ], + ] }; const specs = swaggerJsdoc(options);