diff --git a/.gitignore b/.gitignore
index 3f3673d..6bd7c37 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@
# Environment
.env
+# Local config
+config.mk
+
# Secrets
/keytabs/
/volumes/
diff --git a/Dockerfile b/Dockerfile
index ba0b6a3..f8721da 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,16 +1,27 @@
+# syntax=docker/dockerfile:1
+
ARG utility_prefix=ghcr.io/amrc-factoryplus/utilities
-ARG utility_ver=v1.0.6
+ARG utility_ver=v1.0.8
FROM ${utility_prefix}-build:${utility_ver} AS build
# Install the node application on the build container where we can
# compile the native modules.
-RUN install -d -o node -g node /home/node/app
+USER root
+RUN <<'SHELL'
+ install -d -o node -g node /home/node/app
+ apk add git
+SHELL
WORKDIR /home/node/app
USER node
COPY package*.json ./
RUN npm install --save=false
-COPY . .
+COPY --chown=node . .
+RUN <<'SHELL'
+ git describe --tags --dirty \
+ | sed -re's/-[0-9]+-/-/;s/(.*)/export const GIT_VERSION="\1";/' \
+ > lib/git-version.js
+SHELL
FROM ${utility_prefix}-run:${utility_ver}
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..d413fbd
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,48 @@
+# On Windows try https://frippery.org/busybox/
+
+-include config.mk
+
+pkgver!=node -e 'console.log(JSON.parse(fs.readFileSync("package.json")).version)'
+
+version?=${pkgver}
+suffix?=
+registry?=ghcr.io/amrc-factoryplus
+repo?=acs-auth
+
+tag=${registry}/${repo}:${version}${suffix}
+
+all: build push
+
+.PHONY: all build push check-committed
+
+check-committed:
+ [ -z "$$(git status --porcelain)" ] || (git status; exit 1)
+
+build: check-committed
+ docker build -t "${tag}" .
+
+push:
+ docker push "${tag}"
+
+ifdef deployment
+
+.PHONY: deploy restart logs
+
+kdeploy= deploy/"${deployment}"
+
+deploy: all restart logs
+
+restart:
+ kubectl rollout restart ${kdeploy}
+ kubectl rollout status ${kdeploy}
+ sleep 2
+
+logs:
+ kubectl logs -f ${kdeploy}
+
+else
+
+deploy:
+ : Set $${deployment} for automatic k8s deployment
+
+endif
diff --git a/bin/authn.js b/bin/authn.js
index f46715d..9ca84ab 100644
--- a/bin/authn.js
+++ b/bin/authn.js
@@ -6,13 +6,16 @@
* Copyright 2022 AMRC
*/
-import { WebAPI, pkgVersion } from "@amrc-factoryplus/utilities";
+import { WebAPI, UUIDs } from "@amrc-factoryplus/utilities";
import AuthN from "../lib/authn.js";
import AuthZ from "../lib/authz.js";
import Editor from "../lib/editor.js";
-const Version = pkgVersion(import.meta);
+import { GIT_VERSION } from "../lib/git-version.js";
+
+/* This is the F+ service spec version */
+const Version = "1.0.0";
const authn = await new AuthN({ }).init();
const authz = await new AuthZ({
@@ -31,6 +34,12 @@ const editor = await new Editor({
const api = await new WebAPI({
ping: {
version: Version,
+ service: UUIDs.Service.Authentication,
+ software: {
+ vendor: "AMRC",
+ application: "acs-auth",
+ revision: GIT_VERSION,
+ },
},
realm: process.env.REALM,
hostname: process.env.HOSTNAME,
diff --git a/editor/editor.js b/editor/editor.js
index d5f8fea..c650b0b 100644
--- a/editor/editor.js
+++ b/editor/editor.js
@@ -14,6 +14,7 @@ const html = htm.bind(h);
const Uuid = {
General_Info: "64a8bfa9-7772-45c4-9d1a-9e6290690957",
+ Registration: "cb40bed5-49ad-4443-a7f5-08c75009da8f",
};
let Services;
@@ -83,9 +84,20 @@ async function fetch_json (service, path, method="GET", body=null) {
return json;
}
-async function get_name (obj) {
+async function _get_name (obj) {
const gi = await fetch_json("configdb", `v1/app/${Uuid.General_Info}/object/${obj}`);
- return gi ? gi.name : html`NO NAME`;
+ return gi
+ ? gi.deleted
+ ? html`${gi.name}`
+ : gi.name
+ : html`NO NAME`;
+}
+
+async function get_name (obj) {
+ const reg = await fetch_json("configdb", `v1/app/${Uuid.Registration}/object/${obj}`);
+ const name = await _get_name(obj);
+ const klass = reg ? await _get_name(reg.class) : html`NO CLASS`;
+ return html`${name} (${klass})`;
}
function sort_acl (list) {
diff --git a/lib/authz.js b/lib/authz.js
index 00117a0..77bd01d 100644
--- a/lib/authz.js
+++ b/lib/authz.js
@@ -155,14 +155,17 @@ export default class AuthZ {
if (!valid_uuid(uuid))
return res.status(400).end();
- const ok = await this.model.check_acl(
- req.auth, Perm.Manage_Krb, uuid, true);
+ const ids = await this.model.principal_get(uuid);
+
+ /* We can return 403 here as long as we don't return 404 until
+ * we've checked the permissions. */
+ const ok = req.auth == ids.kerberos
+ || await this.model.check_acl(req.auth, Perm.Read_Krb, uuid, true);
if (!ok) return res.status(403).end();
- const krb = await this.model.principal_get(uuid);
- if (krb == null)
+ if (ids == null)
return res.status(404).end();
- return res.status(200).json(krb);
+ return res.status(200).json(ids);
}
async principal_delete(req, res) {
@@ -181,22 +184,22 @@ export default class AuthZ {
/* This endpoint may change in future to allow searching for
* principals by other criteria, e.g. Node address. */
async principal_find(req, res) {
- const {kerberos} = req.query;
+ const kerberos = req.query?.kerberos ?? req.auth;
if (!valid_krb(kerberos))
return res.status(400).end();
- /* XXX I'm not sure this is right: this means any client that
- * wants to resolve Kerberos principals needs to be able to read
- * them all. I would like to check ACLs against the resolved
- * UUID, but then we have the problem of when to return 404,
- * when 403, etc. */
- const ok = await this.model.check_acl(
- req.auth, Perm.Read_Krb, UUIDs.Null, false);
- if (!ok) return res.status(403).end();
-
const uuid = await this.model.principal_find_by_krb(kerberos);
if (uuid == null)
return res.status(404).end();
+
+ /* We have to check permissions against the returned UUID. This
+ * means that we must return 404 instead of 403 if the check
+ * fails. Principals are always allowed to look up their own
+ * information. */
+ const ok = req.auth == kerberos
+ || await this.model.check_acl(req.auth, Perm.Read_Krb, uuid, true)
+ if (!ok) return res.status(404).end();
+
return res.status(200).json(uuid);
}
diff --git a/package.json b/package.json
index 89c07e8..1b6e02e 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "acs-auth",
- "version": "1.0.0",
+ "version": "1.0.1",
"description": "The Authorisation component of the AMRC Connectivity Stack",
"type": "module",
"main": "index.js",
@@ -21,10 +21,10 @@
"author": "AMRC",
"license": "MIT",
"dependencies": {
- "@amrc-factoryplus/utilities": "1.0.6",
+ "@amrc-factoryplus/utilities": "^1.0.8",
"express": "^4.18.1",
"express-basic-auth": "^1.2.1",
"http-errors": "^2.0.0",
"timers-promises": "^1.0.1"
}
-}
\ No newline at end of file
+}