Add Permissions and Users pages
This commit is contained in:
1 parent
f878d828eb
commit
3b3369a236
16 files changed
+1223
-77
No files matched your search
@@ -2,7 +2,7 @@ import pass from "./validators/pass";
|
||||
import test from "./validators/test";
|
||||
import { PermissionSet } from "../types";
|
||||
|
||||
const validators = { pass, test };
|
||||
export const validators = { pass, test };
|
||||
|
||||
export default class Authorizer {
|
||||
private permissionSets: PermissionSet[];
|
||||
|
||||
@@ -33,6 +33,8 @@ export let tasksCollection,
|
||||
faultsCollection,
|
||||
filesCollection,
|
||||
operationsCollection,
|
||||
permissionsCollection,
|
||||
usersCollection,
|
||||
configCollection;
|
||||
|
||||
export let client;
|
||||
@@ -57,6 +59,8 @@ export function connect(callback): void {
|
||||
virtualParametersCollection = db.collection("virtualParameters");
|
||||
faultsCollection = db.collection("faults");
|
||||
operationsCollection = db.collection("operations");
|
||||
permissionsCollection = db.collection("permissions");
|
||||
usersCollection = db.collection("users");
|
||||
configCollection = db.collection("config");
|
||||
|
||||
callback();
|
||||
@@ -931,3 +935,27 @@ export function getConfig(callback): void {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function getPermissions(
|
||||
callback: (
|
||||
err?: Error,
|
||||
permissions?: {
|
||||
role: string;
|
||||
resource: string;
|
||||
access: number;
|
||||
filter: string;
|
||||
validate: string;
|
||||
}[]
|
||||
) => void
|
||||
): void {
|
||||
permissionsCollection.find().toArray(callback);
|
||||
}
|
||||
|
||||
export function getUsers(
|
||||
callback: (
|
||||
err?: Error,
|
||||
users?: { _id: string; password: string; roles: string }[]
|
||||
) => void
|
||||
): void {
|
||||
usersCollection.find().toArray(callback);
|
||||
}
|
||||
+64
-11
@@ -26,7 +26,20 @@ import * as query from "./query";
|
||||
import * as logger from "./logger";
|
||||
import * as scheduling from "./scheduling";
|
||||
import * as expression from "./common/expression";
|
||||
import { Preset } from "./types";
|
||||
import { parse } from "./common/expression-parser";
|
||||
import { Preset, Expression } from "./types";
|
||||
|
||||
interface Permissions {
|
||||
[role: string]: {
|
||||
[access: number]: {
|
||||
[resource: string]: {
|
||||
access: number;
|
||||
filter: Expression;
|
||||
validate: { [validator: string]: boolean };
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
const REFRESH = 3000;
|
||||
const EVICT_TIMEOUT = 60000;
|
||||
@@ -301,6 +314,48 @@ function refresh(callback): void {
|
||||
})
|
||||
);
|
||||
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
db.getPermissions((err, perms) => {
|
||||
if (err) return void reject(err);
|
||||
const permissions: Permissions = {};
|
||||
for (const p of perms) {
|
||||
if (!permissions[p.role]) permissions[p.role] = {};
|
||||
if (!permissions[p.role][p.access])
|
||||
permissions[p.role][p.access] = {};
|
||||
|
||||
const validate = {};
|
||||
permissions[p.role][p.access][p.resource] = {
|
||||
access: p.access,
|
||||
filter: parse(p.filter || "true"),
|
||||
validate: validate
|
||||
};
|
||||
|
||||
for (const v of (p.validate || "").split(","))
|
||||
validate[v.trim()] = true;
|
||||
}
|
||||
|
||||
resolve(permissions);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
db.getUsers((err, _users) => {
|
||||
if (err) return void reject(err);
|
||||
const users = {};
|
||||
for (const user of _users) {
|
||||
users[user._id] = {
|
||||
password: user.password,
|
||||
roles: user.roles.split(",").map(s => s.trim())
|
||||
};
|
||||
}
|
||||
resolve(users);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
db.getConfig((err, conf) => {
|
||||
@@ -311,11 +366,7 @@ function refresh(callback): void {
|
||||
const _config = {};
|
||||
|
||||
for (const c of conf) {
|
||||
if (
|
||||
c.id.startsWith("auth.") ||
|
||||
c.id.startsWith("permissions.") ||
|
||||
c.id.startsWith("ui.")
|
||||
) {
|
||||
if (c.id.startsWith("ui.")) {
|
||||
const keys = c.id.split(".");
|
||||
let ref = _config;
|
||||
while (keys.length > 1) {
|
||||
@@ -343,7 +394,9 @@ function refresh(callback): void {
|
||||
provisions: res[1],
|
||||
virtualParameters: res[2],
|
||||
files: res[3],
|
||||
config: res[4]
|
||||
permissions: res[4],
|
||||
users: res[5],
|
||||
config: res[6]
|
||||
};
|
||||
|
||||
if (currentSnapshot) {
|
||||
@@ -465,18 +518,18 @@ export function getConfig(
|
||||
return expression.evaluate(snapshot.config[key], context, now || Date.now());
|
||||
}
|
||||
|
||||
export function getAuthConfig(snapshotKey): {} {
|
||||
export function getUsers(snapshotKey): {} {
|
||||
const snapshot = snapshots.get(snapshotKey);
|
||||
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||
|
||||
return snapshot.config.auth;
|
||||
return snapshot.users;
|
||||
}
|
||||
|
||||
export function getPermissionsConfig(snapshotKey): {} {
|
||||
export function getPermissions(snapshotKey): {} {
|
||||
const snapshot = snapshots.get(snapshotKey);
|
||||
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||
|
||||
return snapshot.config.permissions;
|
||||
return snapshot.permissions;
|
||||
}
|
||||
|
||||
export function getUiConfig(snapshotKey): {} {
|
||||
|
||||
@@ -9,7 +9,6 @@ import koaJwt from "koa-jwt";
|
||||
import * as config from "./config";
|
||||
import api from "./ui/api";
|
||||
import Authorizer from "./common/authorizer";
|
||||
import { parse } from "./common/expression-parser";
|
||||
import * as logger from "./logger";
|
||||
import * as localCache from "./local-cache";
|
||||
import { PermissionSet } from "./types";
|
||||
@@ -27,41 +26,18 @@ const JWT_SECRET = "" + config.get("UI_JWT_SECRET");
|
||||
const JWT_COOKIE = "genieacs-ui-jwt";
|
||||
|
||||
function getPermissionSets(ctx): PermissionSet[] {
|
||||
const allPermissions = localCache.getPermissionsConfig(
|
||||
ctx.state.configSnapshot
|
||||
const allPermissions = localCache.getPermissions(ctx.state.configSnapshot);
|
||||
const permissionSets = ctx.state.user.roles.map(role =>
|
||||
Object.values(allPermissions[role] || {})
|
||||
);
|
||||
const permissionSets = ctx.state.user.roles.map(role => {
|
||||
return Object.values(allPermissions[role] || {}).map(p => {
|
||||
p = Object.assign({}, p);
|
||||
for (let [k, v] of Object.entries(p)) {
|
||||
p[k] = v = Object.assign({}, v);
|
||||
if (
|
||||
[
|
||||
"devices",
|
||||
"faults",
|
||||
"presets",
|
||||
"provisions",
|
||||
"virtualParameters",
|
||||
"files"
|
||||
].includes(k)
|
||||
) {
|
||||
if (v.filter == null || v.filter === "") v.filter = true;
|
||||
else v.filter = parse(v.filter);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
});
|
||||
});
|
||||
return permissionSets;
|
||||
}
|
||||
|
||||
function authSimple(ctx, username, password): Promise<string[]> {
|
||||
const authConfig = localCache.getAuthConfig(ctx.state.configSnapshot);
|
||||
const user = authConfig["simple"].users[username];
|
||||
if (user && user.password === password) {
|
||||
const roles = user.roles.split(",").map(s => s.trim());
|
||||
return Promise.resolve(roles);
|
||||
}
|
||||
const users = localCache.getUsers(ctx.state.configSnapshot);
|
||||
const user = users[username];
|
||||
if (user && user.password === password) return Promise.resolve(user.roles);
|
||||
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,14 @@ export function deleteResource(resource, id): Promise<void> {
|
||||
case "config":
|
||||
promise = db.deleteConfig(id);
|
||||
break;
|
||||
|
||||
case "permissions":
|
||||
promise = db.deletePermission(id);
|
||||
break;
|
||||
|
||||
case "users":
|
||||
promise = db.deleteUser(id);
|
||||
break;
|
||||
}
|
||||
|
||||
promise
|
||||
@@ -183,6 +191,8 @@ export function putResource(resource, id, data): Promise<void> {
|
||||
else if (resource === "virtualParameters")
|
||||
promise = db.putVirtualParameter(id, data);
|
||||
else if (resource === "config") promise = db.putConfig(id, data);
|
||||
else if (resource === "permissions") promise = db.putPermission(id, data);
|
||||
else if (resource === "users") promise = db.putUser(id, data);
|
||||
|
||||
promise
|
||||
.then(() => {
|
||||
|
||||
@@ -26,6 +26,8 @@ const RESOURCE_IDS = {
|
||||
files: "_id",
|
||||
virtualParameters: "_id",
|
||||
config: "_id",
|
||||
permissions: "_id",
|
||||
users: "_id",
|
||||
faults: "_id",
|
||||
tasks: "_id"
|
||||
};
|
||||
@@ -37,6 +39,8 @@ const resources = {
|
||||
files: 0 | RESOURCE_DELETE,
|
||||
virtualParameters: 0 | RESOURCE_DELETE | RESOURCE_PUT,
|
||||
config: 0 | RESOURCE_DELETE | RESOURCE_PUT,
|
||||
permissions: 0 | RESOURCE_DELETE | RESOURCE_PUT,
|
||||
users: 0 | RESOURCE_DELETE | RESOURCE_PUT,
|
||||
faults: 0 | RESOURCE_DELETE,
|
||||
tasks: 0
|
||||
};
|
||||
|
||||
@@ -107,6 +107,9 @@ export function query(
|
||||
: options.projection
|
||||
);
|
||||
}
|
||||
|
||||
if (resource === "users") cursor.project({ password: 0 });
|
||||
|
||||
if (options.skip) cursor.skip(options.skip);
|
||||
if (options.limit) cursor.limit(options.limit);
|
||||
|
||||
@@ -282,6 +285,38 @@ export function deleteConfig(id): Promise<void> {
|
||||
return deleteResource("config", id);
|
||||
}
|
||||
|
||||
export function putPermission(id, object): Promise<void> {
|
||||
return putResource("permissions", id, object);
|
||||
}
|
||||
|
||||
export function deletePermission(id): Promise<void> {
|
||||
return deleteResource("permissions", id);
|
||||
}
|
||||
|
||||
export function putUser(id, object): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getClient()
|
||||
.then(client => {
|
||||
const collection = client.db().collection("users");
|
||||
// update instead of replace to keep the password if not set by user
|
||||
collection.updateOne(
|
||||
{ _id: id },
|
||||
{ $set: object },
|
||||
{ upsert: true },
|
||||
err => {
|
||||
if (err) return void reject(err);
|
||||
resolve();
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
}
|
||||
|
||||
export function deleteUser(id): Promise<void> {
|
||||
return deleteResource("users", id);
|
||||
}
|
||||
|
||||
export function putFile(filename, metadata, contentStream): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getClient()
|
||||
|
||||
Reference in new issue
Block a user