fix openldap init script paas user token saving,
add config file with BASE_DN, add async wrapper class for ldap client, implement addUser getUser delUser, add and implement addGroup delGroup methods
This commit is contained in:
parent
d541062eda
commit
9d6f62b4a3
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
|||||||
**/package-lock.json
|
**/package-lock.json
|
||||||
**/node_modules
|
**/node_modules
|
||||||
**/*.token
|
**/*.token
|
||||||
|
**/config.json
|
3
config/config.template.json
Normal file
3
config/config.template.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"basedn": "dc=example,dc=com"
|
||||||
|
}
|
@ -2,7 +2,7 @@ export BASE_DN=''
|
|||||||
read -p "Base DN: " BASE_DN
|
read -p "Base DN: " BASE_DN
|
||||||
|
|
||||||
export PAAS_PASSWD=$(tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_`{|}~' </dev/urandom | head -c 256; echo)
|
export PAAS_PASSWD=$(tr -dc 'A-Za-z0-9!"#$%&'\''()*+,-./:;<=>?@[\]^_`{|}~' </dev/urandom | head -c 256; echo)
|
||||||
echo "$PAAS_PASSWD" > paas.token
|
echo "$PAAS_PASSWD" -n > paas.token
|
||||||
echo "Saved PAAS Authentication Token (password) to paas.token"
|
echo "Saved PAAS Authentication Token (password) to paas.token"
|
||||||
|
|
||||||
envsubst '$BASE_DN' < auth.template.ldif > auth.ldif
|
envsubst '$BASE_DN' < auth.template.ldif > auth.ldif
|
||||||
|
11
src/config.js
Normal file
11
src/config.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { exit } from "process";
|
||||||
|
export default () => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(readFileSync(global.argv.configPath));
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(`Error: ${global.argv.configPath} was not found. Please follow the directions in the README to initialize localdb.json.`);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
186
src/ldap.js
186
src/ldap.js
@ -1,31 +1,179 @@
|
|||||||
import ldap from "ldapjs";
|
import ldap from "ldapjs";
|
||||||
import { exit } from "process";
|
|
||||||
|
|
||||||
export class LDAP {
|
export default class LDAP {
|
||||||
#client = null;
|
#client = null;
|
||||||
#paasBind = null;
|
#basedn = null;
|
||||||
#baseDN = null;
|
#peopledn = null;
|
||||||
|
#groupsdn = null;
|
||||||
|
|
||||||
constructor (url, paasBind, baseDN) {
|
constructor (url, basedn) {
|
||||||
const opts = {
|
const opts = {
|
||||||
url
|
url
|
||||||
};
|
};
|
||||||
|
this.#client = new LDAPJS_CLIENT_ASYNC_WRAPPER(opts);
|
||||||
|
this.#basedn = basedn;
|
||||||
|
this.#peopledn = `ou=people,${basedn}`;
|
||||||
|
this.#groupsdn = `ou=groups,${basedn}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async addUser (bind, uid, attrs) {
|
||||||
|
const result = await this.#client.bind(bind.dn, bind.password);
|
||||||
|
if (!result.ok) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const userDN = `uid=${uid},${this.#peopledn}`;
|
||||||
|
const entry = {
|
||||||
|
objectClass: "inetOrgPerson",
|
||||||
|
cn: attrs.cn,
|
||||||
|
sn: attrs.sn,
|
||||||
|
uid,
|
||||||
|
userPassword: attrs.userPassword
|
||||||
|
};
|
||||||
|
return await this.#client.add(userDN, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUser (bind, uid) {
|
||||||
|
const result = await this.#client.bind(bind.dn, bind.password);
|
||||||
|
if (!result.ok) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const opts = {
|
||||||
|
filter: `(uid=${uid})`,
|
||||||
|
scope: "sub"
|
||||||
|
};
|
||||||
|
return await this.#client.search(this.#peopledn, opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
async modUser (bind, uid, attrs) { }
|
||||||
|
|
||||||
|
async delUser (bind, uid) {
|
||||||
|
const result = await this.#client.bind(bind.dn, bind.password);
|
||||||
|
if (!result.ok) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const userDN = `uid=${uid},${this.#peopledn}`;
|
||||||
|
return await this.#client.del(userDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addGroup (bind, gid, attrs) {
|
||||||
|
const result = await this.#client.bind(bind.dn, bind.password);
|
||||||
|
if (!result.ok) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const groupDN = `cn=${gid},${this.#groupsdn}`;
|
||||||
|
const entry = {
|
||||||
|
objectClass: "groupOfNames",
|
||||||
|
member: "",
|
||||||
|
cn: gid
|
||||||
|
};
|
||||||
|
return await this.#client.add(groupDN, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
async delGroup (bind, gid) {
|
||||||
|
const result = await this.#client.bind(bind.dn, bind.password);
|
||||||
|
if (!result.ok) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
const groupDN = `cn=${gid},${this.#groupsdn}`;
|
||||||
|
return await this.#client.del(groupDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addUserToGroup (bind, uid, gid) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async delUserFromGroup (bind, uid, gid) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
class LDAPJS_CLIENT_ASYNC_WRAPPER {
|
||||||
|
#client = null;
|
||||||
|
constructor (opts) {
|
||||||
this.#client = ldap.createClient(opts);
|
this.#client = ldap.createClient(opts);
|
||||||
this.#client.on("connectError", (err) => {
|
this.#client.on("error", (err) => {
|
||||||
console.err(`Error: could not establish connection to ${url}`);
|
console.error(`An error occured:\n${err}`);
|
||||||
console.err(err);
|
});
|
||||||
exit(1);
|
this.#client.on("connectError", (err) => {
|
||||||
|
console.error(`Unable to connect to ${opts.url}:\n${err}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.#paasBind = paasBind;
|
|
||||||
this.#baseDN = baseDN;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addUser (uid, entry) {}
|
bind (dn, password) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
getUser (uid) {}
|
this.#client.bind(dn, password, (err) => {
|
||||||
|
if (err) {
|
||||||
modUser (uid, entry) {}
|
resolve({ ok: false, error: err });
|
||||||
|
}
|
||||||
delUser (uid) {}
|
else {
|
||||||
|
resolve({ ok: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
add (dn, entry) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.#client.add(dn, entry, (err) => {
|
||||||
|
if (err) {
|
||||||
|
resolve({ ok: false, error: err });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve({ ok: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
search (base, options) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.#client.search(base, options, (err, res) => {
|
||||||
|
if (err) {
|
||||||
|
return resolve({ ok: false, error: err });
|
||||||
|
}
|
||||||
|
const results = { ok: false, status: 1, message: "", entries: [] };
|
||||||
|
res.on("searchRequest", (searchRequest) => { });
|
||||||
|
res.on("searchEntry", (entry) => {
|
||||||
|
results.entries.push({ dn: entry.pojo.objectName, attributes: entry.pojo.attributes });
|
||||||
|
});
|
||||||
|
res.on("searchReference", (referral) => { });
|
||||||
|
res.on("error", (error) => {
|
||||||
|
results.ok = error.status === 0;
|
||||||
|
results.status = error.status;
|
||||||
|
results.message = error.message;
|
||||||
|
resolve(results);
|
||||||
|
});
|
||||||
|
res.on("end", (result) => {
|
||||||
|
results.ok = result.status === 0;
|
||||||
|
results.status = result.status;
|
||||||
|
results.message = result.message;
|
||||||
|
resolve(results);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
modify (name, changes) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.#client.modify(name, changes, (err) => {
|
||||||
|
if (err) {
|
||||||
|
resolve({ ok: false, error: err });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve({ ok: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
del (dn) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
this.#client.del(dn, (err) => {
|
||||||
|
if (err) {
|
||||||
|
resolve({ ok: false, error: err });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve({ ok: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
49
src/main.js
49
src/main.js
@ -2,29 +2,56 @@ import express from "express";
|
|||||||
import bodyParser from "body-parser";
|
import bodyParser from "body-parser";
|
||||||
import cookieParser from "cookie-parser";
|
import cookieParser from "cookie-parser";
|
||||||
import morgan from "morgan";
|
import morgan from "morgan";
|
||||||
import LDAP from "ldap.js";
|
|
||||||
|
import LDAP from "./ldap.js";
|
||||||
|
import _config from "./config.js";
|
||||||
|
import _package from "./package.js";
|
||||||
|
|
||||||
|
import parseArgs from "minimist";
|
||||||
|
|
||||||
|
global.argv = parseArgs(process.argv.slice(2), {
|
||||||
|
default: {
|
||||||
|
package: "package.json",
|
||||||
|
listenPort: 8082,
|
||||||
|
ldapURL: "ldap://localhost",
|
||||||
|
configPath: "config/config.json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
global.package = _package(global.argv.package);
|
||||||
|
global.config = _config(global.argv.configPath);
|
||||||
|
|
||||||
|
const ldap = new LDAP(global.argv.ldapURL, global.config.basedn);
|
||||||
|
|
||||||
|
/* import { readFileSync } from "fs";
|
||||||
|
const paas = {
|
||||||
|
dn: `uid=paas,ou=people,${global.config.basedn}`,
|
||||||
|
password: readFileSync("paas.token").toString()
|
||||||
|
};
|
||||||
|
console.log(await ldap.addUser(paas, "testuser", { cn: "test", sn: "test", userPassword: "test" }));
|
||||||
|
console.log((await ldap.getUser(paas, "testuser")).entries[0].attributes);
|
||||||
|
console.log(await ldap.delUser(paas, "testuser"));
|
||||||
|
console.log(await ldap.addGroup(paas, "testgroup"));
|
||||||
|
console.log(await ldap.delGroup(paas, "testgroup"));
|
||||||
|
exit(0); */
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(morgan("combined"));
|
app.use(morgan("combined"));
|
||||||
|
|
||||||
app.listen(global.db.listenPort, () => {
|
app.listen(global.argv.listenPort, () => {
|
||||||
console.log(`proxmoxaas-api v${global.api.version} listening on port ${global.db.listenPort}`);
|
console.log(`proxmoxaas-ldap v${global.package.version} listening on port ${global.argv.listenPort}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/:user", (req, res) => {
|
app.get("/:user", async (req, res) => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/:user", (req, res) => {
|
app.post("/:user", async (req, res) => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.delete("/:user", (req, res) => {
|
app.delete("/:user", async (req, res) => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post("/:user/password", (req, res) => {
|
app.post("/:user/password", async (req, res) => {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
11
src/package.js
Normal file
11
src/package.js
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { readFileSync } from "fs";
|
||||||
|
import { exit } from "process";
|
||||||
|
export default (path) => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(readFileSync(path));
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(`Error: ${path} was not found.`);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user