Salt and hash passwords

This commit is contained in:
Shweelan Samson authored and Zaid Abdulla committed 2019-03-27 02:17:48 -07:00
1 parent 88ad9451e2
commit d5b194b9e8
13 files changed
+410 -83

No files matched your search

+30 -6
View File
@@ -2,6 +2,8 @@ import { exec } from "child_process";
import { ObjectID } from "mongodb";
import * as db from "./db";
import { del } from "../cache";
import { getUsers } from "../local-cache";
import { hashPassword } from "../auth";
import {
insertTasks,
watchTask,
@@ -186,13 +188,21 @@ export function putResource(resource, id, data): Promise<void> {
return new Promise((resolve, reject) => {
let promise;
if (resource === "presets") promise = db.putPreset(id, data);
else if (resource === "provisions") promise = db.putProvision(id, data);
else if (resource === "virtualParameters")
if (resource === "presets") {
promise = db.putPreset(id, data);
} else if (resource === "provisions") {
promise = db.putProvision(id, data);
} 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);
} else if (resource === "config") {
promise = db.putConfig(id, data);
} else if (resource === "permissions") {
promise = db.putPermission(id, data);
} else if (resource === "users") {
delete data.password;
delete data.salt;
promise = db.putUser(id, data);
}
promise
.then(() => {
@@ -204,3 +214,17 @@ export function putResource(resource, id, data): Promise<void> {
.catch(reject);
});
}
export function authSimple(snapshot, username, password): Promise<string[]> {
return new Promise((resolve, reject) => {
const users = getUsers(snapshot);
const user = users[username];
if (!user || !user.password) return void resolve(null);
hashPassword(password, user.salt)
.then(hash => {
if (hash === user.password) resolve(user.roles);
else resolve(null);
})
.catch(reject);
});
}
+63
View File
@@ -7,6 +7,8 @@ import { parse } from "../common/expression-parser";
import * as logger from "../logger";
import { getConfig } from "../local-cache";
import { QueryOptions, Expression } from "../types";
import { generateSalt, hashPassword } from "../auth";
import { del } from "../cache";
const router = new Router();
export default router;
@@ -497,3 +499,64 @@ router.get("/ping/:host", async ctx => {
ctx.body = `${err.name}: ${err.message}`;
}
});
router.put("/users/:id/password", async (ctx, next) => {
const username = ctx.params.id;
const log = {
message: "Change password",
context: ctx,
username: username
};
const authorizer = ctx.state.authorizer;
if (!ctx.state.user) {
// User not logged in
if (
!(await apiFunctions.authSimple(
ctx.state.configSnapshot,
username,
ctx.request.body.authPassword
))
) {
logUnauthorizedWarning(log);
ctx.status = 401;
ctx.body = "Authentication failed, check your username and password";
return;
}
} else if (!authorizer.hasAccess("users", 3)) {
logUnauthorizedWarning(log);
return void next();
}
const filter = ["=", ["PARAM", RESOURCE_IDS.users], username];
const res = await db.query("users", filter);
if (!res.length) return void next();
const newPassword = ctx.request.body.newPassword;
if (ctx.state.user) {
const validate = authorizer.getValidator("users", res[0]);
if (!validate("password", { password: newPassword })) {
logUnauthorizedWarning(log);
return void (ctx.status = 403);
}
}
const salt = await generateSalt(64);
const password = await hashPassword(newPassword, salt);
await db.putUser(username, { password, salt });
function delCache(): Promise<void> {
return new Promise((resolve, reject) => {
del("presets_hash", err => {
if (err) return void reject(err);
resolve();
});
});
}
await delCache();
logger.accessInfo(log);
ctx.body = "";
});
+11 -4
View File
@@ -82,12 +82,19 @@ export function query(
filter = expression.evaluate(filter, null, Date.now());
if (Array.isArray(filter)) {
if (resource === "devices")
if (resource === "devices") {
filter = mongodbFunctions.processDeviceFilter(filter);
else if (resource === "tasks")
} else if (resource === "tasks") {
filter = mongodbFunctions.processTasksFilter(filter);
else if (resource === "faults")
} else if (resource === "faults") {
filter = mongodbFunctions.processFaultsFilter(filter);
} else if (resource === "users") {
// Protect against brute force, and dictionary attacks
const params = expression.extractParams(filter);
if (params.includes("password") || params.includes("salt"))
return Promise.reject(new Error("Invalid users filter"));
}
q = mongodbFunctions.filterToMongoQuery(filter);
} else if (filter != null && !filter) {
return Promise.resolve([]);
@@ -111,7 +118,7 @@ export function query(
cursor.project(projection);
}
if (resource === "users") cursor.project({ password: 0 });
if (resource === "users") cursor.project({ password: 0, salt: 0 });
if (options.skip) cursor.skip(options.skip);
if (options.limit) cursor.limit(options.limit);