oidc: put clients into the db
This commit is contained in:
+108
-41
@@ -2,7 +2,13 @@
|
||||
|
||||
exports = module.exports = {
|
||||
getProvider,
|
||||
upsertClient,
|
||||
clients: {
|
||||
add: clientsAdd,
|
||||
get: clientsGet,
|
||||
del: clientsDel,
|
||||
update: clientsUpdate,
|
||||
list: clientsList
|
||||
},
|
||||
routes: {
|
||||
renderInteractionPage,
|
||||
interactionLogin,
|
||||
@@ -12,21 +18,66 @@ exports = module.exports = {
|
||||
};
|
||||
|
||||
const assert = require('assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
database = require('./database.js'),
|
||||
debug = require('debug')('box:oidc'),
|
||||
fs = require('fs'),
|
||||
middleware = require('./middleware'),
|
||||
path = require('path'),
|
||||
paths = require('./paths.js'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
HttpError = require('connect-lastmile').HttpError,
|
||||
HttpSuccess = require('connect-lastmile').HttpSuccess,
|
||||
users = require('./users.js'),
|
||||
safe = require('safetydance'),
|
||||
settings = require('./settings.js');
|
||||
|
||||
// currently non-persistent client store instead of .json file
|
||||
// FIXME this has to go to our db
|
||||
const gClients = {};
|
||||
const OIDC_CLIENTS_TABLE_NAME = 'oidcClients';
|
||||
const OIDC_CLIENTS_FIELDS = [ 'id', 'secret', 'redirectUri' ];
|
||||
|
||||
async function clientsAdd(id, secret, redirectUri) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof secret, 'string');
|
||||
assert.strictEqual(typeof redirectUri, 'string');
|
||||
|
||||
const query = 'INSERT INTO oidcClients (id, secret, redirectUri) VALUES (?, ?, ?)';
|
||||
const args = [ id, secret, redirectUri ];
|
||||
|
||||
const [error] = await safe(database.query(query, args));
|
||||
if (error && error.code === 'ER_DUP_ENTRY') throw new BoxError(BoxError.ALREADY_EXISTS, 'client already exists');
|
||||
if (error) throw error;
|
||||
}
|
||||
|
||||
async function clientsGet(id) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
|
||||
debug(`clientsGet: id:${id}`);
|
||||
|
||||
const result = await database.query(`SELECT ${OIDC_CLIENTS_FIELDS} FROM ${OIDC_CLIENTS_TABLE_NAME} WHERE id = ?`, [ id ]);
|
||||
if (result.length === 0) return null;
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
async function clientsUpdate(id, secret, redirectUri) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof secret, 'string');
|
||||
assert.strictEqual(typeof redirectUri, 'string');
|
||||
|
||||
const result = await database.query(`UPDATE ${OIDC_CLIENTS_TABLE_NAME} SET secret=?, redirectUri=? WHERE id = ?`, [ secret, redirectUri, id]);
|
||||
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'client not found');
|
||||
}
|
||||
|
||||
async function clientsDel(id) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
|
||||
const result = await database.query(`DELETE FROM ${OIDC_CLIENTS_TABLE_NAME} WHERE id = ?`, [ id ]);
|
||||
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'client not found');
|
||||
}
|
||||
|
||||
async function clientsList() {
|
||||
const results = await database.query(`SELECT * FROM ${OIDC_CLIENTS_TABLE_NAME}`, []);
|
||||
return results;
|
||||
}
|
||||
|
||||
class CloudronAdapter {
|
||||
|
||||
@@ -44,8 +95,8 @@ class CloudronAdapter {
|
||||
constructor(name) {
|
||||
this.name = name;
|
||||
|
||||
if (name === 'Client') {
|
||||
this.store = gClients;
|
||||
if (this.name === 'Client') {
|
||||
this.store = null;
|
||||
this.fileStorePath = null;
|
||||
} else {
|
||||
this.fileStorePath = path.join(paths.OIDC_STORE_DIR, `${name}.json`);
|
||||
@@ -78,8 +129,12 @@ class CloudronAdapter {
|
||||
async upsert(id, payload, expiresIn) {
|
||||
debug(`[${this.name}] upsert id:${id} expiresIn:${expiresIn}`, payload);
|
||||
|
||||
this.store[id] = { id, expiresIn, payload, consumed: false };
|
||||
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
|
||||
if (this.name === 'Client') {
|
||||
console.log('WARNING!! this should not happen as it is stored in our db');
|
||||
} else {
|
||||
this.store[id] = { id, expiresIn, payload, consumed: false };
|
||||
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,11 +150,24 @@ class CloudronAdapter {
|
||||
async find(id) {
|
||||
debug(`[${this.name}] find id:${id}`);
|
||||
|
||||
if (!this.store[id]) return false;
|
||||
if (this.name === 'Client') {
|
||||
const [error, client] = await safe(clientsGet(id));
|
||||
if (error) return null;
|
||||
|
||||
debug(`[${this.name}] find id:${id}`, this.store[id]);
|
||||
debug(`[${this.name}] find id:${id}`, client);
|
||||
|
||||
return this.store[id].payload;
|
||||
return {
|
||||
client_id: id,
|
||||
client_secret: client.secret,
|
||||
redirect_uris: [ client.redirectUri ],
|
||||
};
|
||||
} else {
|
||||
if (!this.store[id]) return false;
|
||||
|
||||
debug(`[${this.name}] find id:${id}`, this.store[id]);
|
||||
|
||||
return this.store[id].payload;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,11 +198,15 @@ class CloudronAdapter {
|
||||
async findByUid(uid) {
|
||||
debug(`[${this.name}] findByUid uid:${uid}`);
|
||||
|
||||
for (let d in this.store) {
|
||||
if (this.store[d].payload.uid === uid) return this.store[d].payload;
|
||||
}
|
||||
if (this.name === 'Client') {
|
||||
console.log('WARNING!! this should not happen as it is stored in our db');
|
||||
} else {
|
||||
for (let d in this.store) {
|
||||
if (this.store[d].payload.uid === uid) return this.store[d].payload;
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,9 +223,13 @@ class CloudronAdapter {
|
||||
async consume(id) {
|
||||
debug(`[${this.name}] consume id:${id}`);
|
||||
|
||||
if (this.store[id]) this.store[id].consumed = true;
|
||||
if (this.name === 'Client') {
|
||||
console.log('WARNING!! this should not happen as it is stored in our db');
|
||||
} else {
|
||||
if (this.store[id]) this.store[id].consumed = true;
|
||||
|
||||
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
|
||||
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -169,9 +245,13 @@ class CloudronAdapter {
|
||||
async destroy(id) {
|
||||
debug(`[${this.name}] destroy id:${id}`);
|
||||
|
||||
delete this.store[id];
|
||||
if (this.name === 'Client') {
|
||||
console.log('WARNING!! this should not happen as it is stored in our db');
|
||||
} else {
|
||||
delete this.store[id];
|
||||
|
||||
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
|
||||
if (this.fileStorePath) fs.writeFileSync(this.fileStorePath, JSON.stringify(this.store), 'utf8');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,32 +267,19 @@ class CloudronAdapter {
|
||||
async revokeByGrantId(grantId) {
|
||||
debug(`[${this.name}] revokeByGrantId grantId:${grantId}`);
|
||||
|
||||
for (let d in this.store) {
|
||||
if (this.store[d].grantId === grantId) {
|
||||
delete this.store[d];
|
||||
return;
|
||||
if (this.name === 'Client') {
|
||||
console.log('WARNING!! this should not happen as it is stored in our db');
|
||||
} else {
|
||||
for (let d in this.store) {
|
||||
if (this.store[d].grantId === grantId) {
|
||||
delete this.store[d];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function upsertClient(provider, clientId, clientSecret, redirectUri) {
|
||||
assert.strictEqual(typeof provider, 'object');
|
||||
assert.strictEqual(typeof clientId, 'string');
|
||||
assert.strictEqual(typeof clientSecret, 'string');
|
||||
assert.strictEqual(typeof redirectUri, 'string');
|
||||
|
||||
debug(`upsertClient clientId:${clientId} clientSecret:${clientSecret} redirectUri:${redirectUri}`);
|
||||
|
||||
const payload = {
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
redirect_uris: [ redirectUri ],
|
||||
}
|
||||
|
||||
gClients[clientId] = { id: clientId, expiresIn: 0, payload, consumed: false };
|
||||
}
|
||||
|
||||
function renderInteractionPage(routePrefix, provider) {
|
||||
assert.strictEqual(typeof routePrefix, 'string');
|
||||
assert.strictEqual(typeof provider, 'object');
|
||||
|
||||
Reference in New Issue
Block a user