mirror of
https://github.com/jambonz/jambonz-api-server.git
synced 2026-01-25 02:08:24 +00:00
more authentication tests
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
const Model = require('./model');
|
||||
const {getMysqlConnection} = require('../db');
|
||||
const listSqlSp = 'SELECT * from accounts WHERE service_provider_sid = ?';
|
||||
const listSqlAccount = 'SELECT * from accounts WHERE account_sid = ?';
|
||||
const retrieveSql = 'SELECT * from accounts WHERE WHERE service_provider_sid = ? AND account_sid = ?';
|
||||
const listSqlSp = 'SELECT * from accounts WHERE service_provider_sid = ?';
|
||||
const listSqlAccount = 'SELECT * from accounts WHERE account_sid = ?';
|
||||
const retrieveSql = 'SELECT * from accounts WHERE service_provider_sid = ? AND account_sid = ?';
|
||||
|
||||
class Account extends Model {
|
||||
constructor() {
|
||||
@@ -29,7 +29,7 @@ class Account extends Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve an accounts
|
||||
* retrieve an account
|
||||
*/
|
||||
static retrieve(sid, service_provider_sid) {
|
||||
if (!service_provider_sid) return super.retrieve(sid);
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
const Model = require('./model');
|
||||
const {getMysqlConnection} = require('../db');
|
||||
const serviceProviderSql = `
|
||||
SELECT * from ${this.table}
|
||||
const listSqlSp = `
|
||||
SELECT * from applications
|
||||
WHERE account_sid in (
|
||||
SELECT account_sid from accounts
|
||||
WHERE service_provider_sid = ?
|
||||
)`;
|
||||
const listSqlAccount = 'SELECT * from applications WHERE account_sid = ?';
|
||||
const retrieveSqlSp = `
|
||||
SELECT * from applications
|
||||
WHERE account_sid in (
|
||||
SELECT account_sid from accounts
|
||||
WHERE service_provider_sid = ?
|
||||
)
|
||||
AND application_sid = ?`;
|
||||
const retrieveSqlAccount = `
|
||||
SELECT * from applications
|
||||
WHERE account_sid = ?
|
||||
AND application_sid = ?`;
|
||||
|
||||
class Application extends Model {
|
||||
constructor() {
|
||||
@@ -13,13 +25,16 @@ class Application extends Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve all applications for an account
|
||||
* list all applications - for all service providers, for one service provider, or for one account
|
||||
*/
|
||||
static retrieveAllForAccount(account_sid) {
|
||||
static retrieveAll(service_provider_sid, account_sid) {
|
||||
if (!service_provider_sid && !account_sid) return super.retrieveAll();
|
||||
return new Promise((resolve, reject) => {
|
||||
getMysqlConnection((err, conn) => {
|
||||
if (err) return reject(err);
|
||||
conn.query(`SELECT * from ${this.table} WHERE account_sid = ?`, [account_sid], (err, results, fields) => {
|
||||
const sql = account_sid ? listSqlAccount : listSqlSp;
|
||||
const args = account_sid ? [account_sid] : [service_provider_sid];
|
||||
conn.query(sql, args, (err, results, fields) => {
|
||||
conn.release();
|
||||
if (err) return reject(err);
|
||||
resolve(results);
|
||||
@@ -29,13 +44,16 @@ class Application extends Model {
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieve all applications for a service provider
|
||||
* retrieve an application
|
||||
*/
|
||||
static retrieveAllForServiceProvider(service_provider_sid) {
|
||||
static retrieve(sid, service_provider_sid, account_sid) {
|
||||
if (!service_provider_sid && !account_sid) return super.retrieve(sid);
|
||||
return new Promise((resolve, reject) => {
|
||||
getMysqlConnection((err, conn) => {
|
||||
if (err) return reject(err);
|
||||
conn.query(serviceProviderSql, [service_provider_sid], (err, results, fields) => {
|
||||
const sql = account_sid ? retrieveSqlAccount : retrieveSqlSp;
|
||||
const args = account_sid ? [account_sid, sid] : [service_provider_sid, sid];
|
||||
conn.query(sql, args, (err, results, fields) => {
|
||||
conn.release();
|
||||
if (err) return reject(err);
|
||||
resolve(results);
|
||||
@@ -43,6 +61,7 @@ class Application extends Model {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Application.table = 'applications';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const router = require('express').Router();
|
||||
const {DbErrorBadRequest, DbErrorUnprocessableRequest} = require('../../utils/errors');
|
||||
const Application = require('../../models/application');
|
||||
const Account = require('../../models/account');
|
||||
const decorate = require('./decorate');
|
||||
const sysError = require('./error');
|
||||
const preconditions = {
|
||||
@@ -14,6 +15,14 @@ async function validateAdd(req) {
|
||||
if (req.user.account_sid) {
|
||||
req.body.account_sid = req.user.account_sid;
|
||||
}
|
||||
else if (req.user.hasServiceProviderAuth) {
|
||||
// make sure the account is being created for this service provider
|
||||
if (!req.body.account_sid) throw new DbErrorBadRequest('missing required field: \'account_sid\'');
|
||||
const result = await Account.retrieve(req.body.account_sid, req.user.service_provider_sid);
|
||||
if (result.length === 0) {
|
||||
throw new DbErrorBadRequest('insufficient privileges to create an application under the specified account');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function validateUpdate(req, sid) {
|
||||
@@ -30,25 +39,34 @@ async function validateDelete(req, sid) {
|
||||
if (assignedPhoneNumbers > 0) throw new DbErrorUnprocessableRequest('cannot delete application with phone numbers');
|
||||
}
|
||||
|
||||
decorate(router, Application, ['add', 'update', 'delete', 'retrieve'], preconditions);
|
||||
decorate(router, Application, ['add', 'update', 'delete'], preconditions);
|
||||
|
||||
/**
|
||||
* if account-level privileges, retrieve only applications for that account
|
||||
* ditto if service provider
|
||||
*/
|
||||
/* list */
|
||||
router.get('/', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
let results;
|
||||
if (req.user.hasAccountAuth) results = await Application.retrieveAllForAccount(req.user.account_sid);
|
||||
else if (req.user.hasAccountAuth) {
|
||||
results = await Application.retrieveAllForServiceProvider(req.user.service_provider_sid);
|
||||
}
|
||||
else results = await Application.retrieveAll();
|
||||
const service_provider_sid = req.user.hasServiceProviderAuth ? req.user.service_provider_sid : null;
|
||||
const account_sid = req.user.hasAccountAuth ? req.user.account_sid : null;
|
||||
const results = await Application.retrieveAll(service_provider_sid, account_sid);
|
||||
res.status(200).json(results);
|
||||
} catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
/* retrieve */
|
||||
router.get('/:sid', async(req, res) => {
|
||||
const logger = req.app.locals.logger;
|
||||
try {
|
||||
const service_provider_sid = req.user.hasServiceProviderAuth ? req.user.service_provider_sid : null;
|
||||
const account_sid = req.user.hasAccountAuth ? req.user.account_sid : null;
|
||||
const results = await Application.retrieve(req.params.sid, service_provider_sid, account_sid);
|
||||
if (results.length === 0) return res.status(404).end();
|
||||
return res.status(200).json(results);
|
||||
}
|
||||
catch (err) {
|
||||
sysError(logger, res, err);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -52,7 +52,7 @@ test('application tests', async(t) => {
|
||||
auth: authAdmin,
|
||||
json: true,
|
||||
});
|
||||
t.ok(result.name === 'daveh' , 'successfully retrieved application by sid');
|
||||
t.ok(result[0].name === 'daveh' , 'successfully retrieved application by sid');
|
||||
|
||||
/* update applications */
|
||||
result = await request.put(`/Applications/${sid}`, {
|
||||
|
||||
108
test/auth.js
108
test/auth.js
@@ -209,6 +209,111 @@ test('authentication tests', async(t) => {
|
||||
//console.log(`result: ${JSON.stringify(result)}`);
|
||||
t.ok(result.statusCode === 204, 'successfully updated account A1 using auth token for account A1');
|
||||
|
||||
/* add an application for accounts A1, A2, and B1 */
|
||||
result = await request.post('/Applications', {
|
||||
resolveWithFullResponse: true,
|
||||
auth: {bearer: accA1_token},
|
||||
json: true,
|
||||
body: {
|
||||
name: 'A1-app',
|
||||
call_hook: 'http://example.com',
|
||||
call_status_hook: 'http://example.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created application for account A1 (using account level token)');
|
||||
const appA1 = result.body.sid;
|
||||
|
||||
result = await request.post('/Applications', {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: {bearer: spB_token},
|
||||
json: true,
|
||||
body: {
|
||||
name: 'A2-app',
|
||||
account_sid: accA2,
|
||||
call_hook: 'http://example.com',
|
||||
call_status_hook: 'http://example.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 400 && result.body.msg === 'insufficient privileges to create an application under the specified account',
|
||||
'cannot create application for account A2 using service provider token B');
|
||||
|
||||
result = await request.post('/Applications', {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: {bearer: spA_token},
|
||||
json: true,
|
||||
body: {
|
||||
name: 'A2-app',
|
||||
account_sid: accA2,
|
||||
call_hook: 'http://example.com',
|
||||
call_status_hook: 'http://example.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created application for account A2 (using service provider token A)');
|
||||
const appA2 = result.body.sid;
|
||||
|
||||
result = await request.post('/Applications', {
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
auth: {bearer: spB_token},
|
||||
json: true,
|
||||
body: {
|
||||
name: 'B1-app',
|
||||
account_sid: accB1,
|
||||
call_hook: 'http://example.com',
|
||||
call_status_hook: 'http://example.com'
|
||||
}
|
||||
});
|
||||
t.ok(result.statusCode === 201, 'successfully created application for account B1 (using service provider token B)');
|
||||
const appB1 = result.body.sid;
|
||||
|
||||
/* see all apps using admin token */
|
||||
result = await request.get('/Applications', {
|
||||
auth: authAdmin,
|
||||
json: true
|
||||
});
|
||||
t.ok(result.length === 3, 'using admin token we see 3 applications');
|
||||
|
||||
/* see two apps using SP A token */
|
||||
result = await request.get('/Applications', {
|
||||
auth: {bearer: spA_token},
|
||||
json: true
|
||||
});
|
||||
t.ok(result.length === 2, 'using service provider A token we see 2 applications');
|
||||
|
||||
/* see one app using SP B token */
|
||||
result = await request.get('/Applications', {
|
||||
auth: {bearer: spB_token},
|
||||
json: true
|
||||
});
|
||||
t.ok(result.length === 1, 'using service provider B token we see 1 application');
|
||||
|
||||
/* see one app using account token token */
|
||||
result = await request.get('/Applications', {
|
||||
auth: {bearer: accA1_token},
|
||||
json: true
|
||||
});
|
||||
t.ok(result.length === 1, 'using account token we see 1 application');
|
||||
|
||||
/* see one app using account token */
|
||||
result = await request.get(`/Applications/${appA1}`, {
|
||||
auth: {bearer: accA1_token},
|
||||
json: true
|
||||
});
|
||||
//console.log(`result: ${JSON.stringify(result)}`);
|
||||
t.ok(result.length === 1, 'using account token A1 we are able to retrieve application A1');
|
||||
|
||||
/* cannot see app under another account using account token */
|
||||
result = await request.get(`/Applications/${appA2}`, {
|
||||
auth: {bearer: accA1_token},
|
||||
resolveWithFullResponse: true,
|
||||
simple: false,
|
||||
json: true
|
||||
});
|
||||
t.ok(result.statusCode === 404, 'using account token A1 we are not able to retrieve application A2s');
|
||||
|
||||
|
||||
/* service provider token can not be used to add phone number */
|
||||
result = await request.post('/PhoneNumbers', {
|
||||
auth: {bearer: spA_token},
|
||||
@@ -335,6 +440,9 @@ test('authentication tests', async(t) => {
|
||||
await deleteObjectBySid(request, '/ApiKeys', accA1_token_sid2);
|
||||
await deleteObjectBySid(request, '/ApiKeys', spA_token_sid);
|
||||
await deleteObjectBySid(request, '/ApiKeys', spB_token_sid);
|
||||
await deleteObjectBySid(request, '/Applications', appA1);
|
||||
await deleteObjectBySid(request, '/Applications', appA2);
|
||||
await deleteObjectBySid(request, '/Applications', appB1);
|
||||
await deleteObjectBySid(request, '/Accounts', accA1);
|
||||
await deleteObjectBySid(request, '/Accounts', accA2);
|
||||
await deleteObjectBySid(request, '/Accounts', accB1);
|
||||
|
||||
Reference in New Issue
Block a user