oidc-lib
Version:
A library for creating OIDC Service Providers
349 lines (308 loc) • 12.5 kB
JavaScript
module.exports = {
initialize: initialize,
createOrUpdateDocument: createOrUpdateDocument,
getDocument: getDocument,
deleteDocument: deleteDocument,
queryCollection: queryCollection
/*
cleanup: cleanup,
createDocument: createDocument,
getDocument: getDocument,
queryCollection: queryCollection,
replaceDocument: replaceDocument,
deleteDocument: deleteDocument,
isDbDisabled: isDbDisabled
*/
};
var pk = null;
const documentDbDocumentClient = require("documentdb").DocumentClient;
const HttpStatusCodes = { NOTFOUND: 404 };
function initialize(pkInput, contentModuleName, provider){
return new Promise((resolve, reject) => {
pk = pkInput;
var dbInfo = {
provider: provider,
contentModuleName: contentModuleName
};
validateModuleConfig(contentModuleName);
pk.util.log_debug("Initializing DocumentDb in content module " + contentModuleName);
dbInfo.contentModuleName = contentModuleName;
dbInfo.databaseName = getDbModuleConfigProperty(contentModuleName, 'databaseName');
dbInfo.endpoint = getDbModuleConfigProperty(contentModuleName, 'endpoint');
dbInfo.primaryKey = getDbModuleConfigProperty(contentModuleName, 'primaryKey');
dbInfo.client = new documentDbDocumentClient(dbInfo.endpoint, { "masterKey": dbInfo.primaryKey });
dbInfo.databaseDefinition = { id: dbInfo.databaseName };
dbInfo.databaseUrl = `dbs/${dbInfo.databaseDefinition.id}`;
dbInfo.collections = {};
var collectionNames = getDbModuleConfigProperty(contentModuleName, 'collectionNames');
for (var count=0; count < collectionNames.length; count++){
collectionName = collectionNames[count];
var collectionInfo = {
definition: { "id": collectionName },
url: `${dbInfo.databaseUrl}/colls/${collectionName}`
};
dbInfo.collections[collectionName] = collectionInfo;
}
pk.dbs[contentModuleName] = dbInfo;
var promises = [];
getDatabase(dbInfo)
.then(function() {
for (var key in dbInfo.collections){
promises.push(getCollection(dbInfo, key));
}
Promise.all(promises).then(function(data){
resolve(dbInfo);
});
}, function(err){
pk.util.log_error('Initialize', "Error getting database in content module " + contentModuleName);
})
.then(function() {}, function(err){
if (err.code !== undefined){
switch (err.code){
case 'ENOENT':
if (err.syscall === 'getaddrinfo'){
pk.util.log_debug('Unable to lookup database service in DNS in module ' + contentModuleName);
pk.util.log_debug('Hostname: ' + err.hostname);
return;
}
break;
default:
break;
}
}
pk.util.log_debug('Database initialization failed for module ' + contentModuleName);
reject(err);
});
});
};
function getDatabase (dbInfo) {
return new Promise((resolve, reject) => {
dbInfo.client.readDatabase(dbInfo.databaseUrl, (err, result) => {
if (err) {
if (err.code == HttpStatusCodes.NOTFOUND) {
dbInfo.client.createDatabase(dbInfo.databaseDefinition, (err, created) => {
if (err){
reject(err)
}
else{
resolve(created);
}
});
} else {
reject(err);
}
} else {
resolve(result);
}
});
});
};
function getCollection(dbInfo, collectionName) {
var collectionInfo = dbInfo.collections[collectionName];
return new Promise((resolve, reject) => {
dbInfo.client.readCollection(collectionInfo.url, (err, result) => {
if (err) {
if (err.code == HttpStatusCodes.NOTFOUND) {
dbInfo.client.createCollection(dbInfo.databaseUrl, collectionInfo.definition, { offerThroughput: 400 }, (err, created) => {
if (err) reject(err)
else resolve(created);
});
} else {
reject(err);
}
} else {
resolve(result);
}
});
});
}
function getDocument(dbInfo, collectionName, id) {
var collectionInfo = dbInfo.collections[collectionName];
let documentUrl = `${collectionInfo.url}/docs/${id}`;
return new Promise((resolve, reject) => {
dbInfo.client.readDocument(documentUrl, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
};
function createDocument(dbInfo, collectionName, document){
var collectionInfo = dbInfo.collections[collectionName];
return new Promise((resolve, reject) => {
dbInfo.client.createDocument(collectionInfo.url, document, (err, created) => {
if (err){
pk.util.log_detail('Document creation error', err);
reject(err);
}
else{
pk.util.log_debug('Document creation succeeded');
resolve(created);
}
});
});
};
function createOrUpdateDocument(dbInfo, collectionName, document, updateLogic){
pk.util.log_debug('Attempting to create or update document');
var collectionInfo = dbInfo.collections[collectionName];
let documentUrl = `${collectionInfo.url}/docs/${document.id}`;
return new Promise((resolve, reject) => {
dbInfo.client.readDocument(documentUrl, (err, result) => {
if (err) {
if (err.code === HttpStatusCodes.NOTFOUND){
pk.util.log_debug('Document does not exist so creating it');
dbInfo.client.createDocument(collectionInfo.url, document, (err, created) => {
if (err){
pk.util.log_detail('Document creation error', err);
reject(err);
}
else{
pk.util.log_debug('Document creation succeeded');
resolve(created);
}
});
}
else {
pk.util.log_detail('Unexpected error attempting to retrieve document', err);
reject(err);
}
} else {
if (updateLogic !== undefined){
pk.util.log_debug('Document existed - update logic being applied');
updateLogic(result, document);
}
dbInfo.client.upsertDocument(collectionInfo.url, document, (err, created) => {
if (err){
pk.util.log_detail('Document upset error', err);
reject(err);
}
else{
pk.util.log_debug('Document upsert succeeded');
resolve(created);
}
});
}
});
});
};
// currently indexName is not used in azure module
function queryCollection(dbInfo, collectionName, queryDictionaryOrString, indexName) {
var collectionInfo = dbInfo.collections[collectionName];
var queryString = queryDictionaryOrString;
if (typeof queryDictionaryOrString === 'object'){
queryString = 'SELECT * FROM ' + collectionName;
if (isset(queryDictionaryOrString)){
queryString += ' c WHERE ';
var starting = true;
for (var qKey in queryDictionaryOrString){
if (starting){
starting = false;
}
else {
queryString += " AND ";
}
queryString += 'c.' + qKey + ' = "' + queryDictionaryOrString[qKey] + '"';
}
}
}
return new Promise((resolve, reject) => {
dbInfo.client.queryDocuments(
collectionInfo.url,
queryString
).toArray((err, results) => {
if (err){
reject(err);
}
else {
resolve(results);
}
});
});
};
function replaceDocument(document) {
var collectionInfo = dbInfo.collections[collectionName];
let documentUrl = `${collectionInfo.url}/docs/${document.id}`;
pk.util.log_debug(`Replacing document:\n${document.id}\n`);
document.children[0].grade = 6;
return new Promise((resolve, reject) => {
dbInfo.client.replaceDocument(documentUrl, document, (err, result) => {
if (err) reject(err);
else {
resolve(result);
}
});
});
};
function deleteDocument(dbInfo, collectionName, id) {
var collectionInfo = dbInfo.collections[collectionName];
let documentUrl = `${collectionInfo.url}/docs/${id}`;
return new Promise((resolve, reject) => {
dbInfo.client.deleteDocument(documentUrl, (err, result) => {
if (err){
if (err.code === 404){
resolve(err);
}
else {
reject(err);
}
}
else {
resolve(result);
}
});
});
};
function cleanup(pkInput, contentModuleName) {
pk = pkInput;
validateModuleConfig(contentModuleName);
var endpoint = getDbModuleConfigProperty(contentModuleName, 'endpoint');
var primaryKey = getDbModuleConfigProperty(contentModuleName, 'primaryKey');
var client = new documentDbDocumentClient(endpoint, { "masterKey": primaryKey });
var databaseName = getDbModuleConfigProperty(contentModuleName, 'databaseName');
var databaseDefinition = { id: databaseName };
var databaseUrl = `dbs/${databaseDefinition.id}`;
pk.util.log_debug(`Cleaning up by deleting database ${databaseDefinition.id}`);
return new Promise((resolve, reject) => {
client.deleteDatabase(databaseUrl, (err) => {
if (err) reject(err)
else resolve(null);
});
});
}
function validateModuleConfig(contentModuleName){
if (contentModuleName !== 'sts'){
if (pk.util.config.content_modules[contentModuleName].db === undefined){
throw "The " + contentModuleName + " content module does not define a db property in claimer_config";
}
}
}
function getDbModuleConfigProperty(contentModuleName, propertyName, throwOnUndefined)
{
if (throwOnUndefined === undefined || throwOnUndefined === true){
var dbInstance = pk.util.config.sts.db;
if (contentModuleName !== 'sts'){
dbInstance = pk.util.config.content_modules[contentModuleName].db;
}
if (dbInstance[propertyName] === undefined){
throw "Configuration property " + propertyName + " is not defined in content module " + contentModuleName;
}
}
return dbInstance[propertyName];
}
function isDbDisabled(pkInput, contentModuleName){
pk = pkInput;
var isDisabled = getDbModuleConfigProperty('disabled', false, contentModuleName);
if (isDisabled === undefined){
isDisabled = false;
}
return isDisabled;
}
function isset(param){
if (typeof param !== 'object'){
if (param === undefined || param === null || param.length === 0)
return false;
}
return true;
}