anbaric-cloud-hosting 1.63.0 → 1.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anbaric-cloud-hosting",
3
- "version": "1.63.0",
3
+ "version": "1.64.0",
4
4
  "description": "Anbaric Cloud hosting service: Postgres-backed job persistence and queuing exposed over an HTTP API",
5
5
  "license": "MIT",
6
6
  "author": "chris@anbaric.ai",
@@ -18,18 +18,18 @@
18
18
  "@aws-sdk/client-s3": "^3.1110.0",
19
19
  "@aws-sdk/client-secrets-manager": "^3.700.0",
20
20
  "@aws-sdk/client-servicediscovery": "^3.1110.0",
21
- "anbaric-data-store": "^1.63.0",
22
- "anbaric-plugins": "^1.63.0",
23
- "anbaric-tsapi": "^1.63.0",
24
- "anbaric-web": "^1.63.0",
21
+ "anbaric-data-store": "^1.64.0",
22
+ "anbaric-plugins": "^1.64.0",
23
+ "anbaric-tsapi": "^1.64.0",
24
+ "anbaric-web": "^1.64.0",
25
25
  "esbuild": "^0.28.2",
26
26
  "pg": "^8.16.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^26.2.0",
30
30
  "@types/pg": "^8.15.0",
31
- "anbaric-impl-cloud": "^1.63.0",
32
- "anbaric-state-machine": "^1.63.0",
31
+ "anbaric-impl-cloud": "^1.64.0",
32
+ "anbaric-state-machine": "^1.64.0",
33
33
  "tsx": "^4.20.0",
34
34
  "typescript": "^7.0.2"
35
35
  },
@@ -4,6 +4,15 @@ import {User} from "./User";
4
4
 
5
5
  const SESSION_COOKIE = "anbaric_session";
6
6
 
7
+ /* The identity cookie: who this person is, as the central login proved it,
8
+ set for the whole domain and never overwritten by a tenant platform. A
9
+ platform's own session cookie is bound to that platform - signed with its
10
+ secret - so moving between tenants invalidates it every time; this one is
11
+ bound to the person, and is what a platform falls back to before sending
12
+ anyone through the login again. Mirrors CENTRAL_SESSION_COOKIE in
13
+ anbaric-cloud-central; keep the two in step. */
14
+ const IDENTITY_COOKIE = "anbaric_central_session";
15
+
7
16
  abstract class Authenticator {
8
17
 
9
18
  abstract authenticate(session : string | undefined, request : IncomingMessage,
@@ -30,4 +39,4 @@ abstract class Authenticator {
30
39
 
31
40
  }
32
41
 
33
- export { Authenticator, SESSION_COOKIE }
42
+ export { Authenticator, SESSION_COOKIE, IDENTITY_COOKIE }
@@ -12,6 +12,8 @@ class Request {
12
12
 
13
13
  readonly rayId : string;
14
14
  session? : string;
15
+ // The identity cookie from the central login, when the browser holds one.
16
+ identity? : string;
15
17
  user? : User;
16
18
  tenant? : Tenant;
17
19
 
@@ -71,7 +71,12 @@ class AuthenticationMiddleware implements Middleware {
71
71
 
72
72
  if (!this.authenticator) return true;
73
73
 
74
- const authenticated = await this.authenticator.authenticate(request.session, request.raw, request.rawResponse);
74
+ /* No session this platform can verify. Before sending anyone back
75
+ through the login, offer the authenticator the identity cookie the
76
+ central login set for the whole domain: a person arriving from
77
+ another tenant carries that tenant's session, which this platform
78
+ cannot read, but their identity is the same and still proven. */
79
+ const authenticated = await this.authenticator.authenticate(request.identity ?? request.session, request.raw, request.rawResponse);
75
80
  if (!authenticated) return false;
76
81
 
77
82
  [request.user, request.tenant] = authenticated;
@@ -1,17 +1,18 @@
1
- import {SESSION_COOKIE} from "../../auth/Authenticator";
1
+ import {IDENTITY_COOKIE, SESSION_COOKIE} from "../../auth/Authenticator";
2
2
  import {Middleware} from "../Middleware";
3
3
  import {Request} from "../Request";
4
4
 
5
+ /* Lifts the two cookies authentication cares about off the request: this
6
+ platform's own session, and the identity the central login proved. The
7
+ first of each name wins, which is what a browser sends first. */
5
8
  class SessionMiddleware implements Middleware {
6
9
 
7
10
  async apply(request : Request) : Promise<boolean> {
8
11
  const cookies = String(request.header("cookie") ?? "").split(";");
9
12
  for (const cookie of cookies) {
10
13
  const [name, ...value] = cookie.trim().split("=");
11
- if (name === SESSION_COOKIE) {
12
- request.session = value.join("=");
13
- break;
14
- }
14
+ if (name === SESSION_COOKIE && request.session === undefined) request.session = value.join("=");
15
+ if (name === IDENTITY_COOKIE && request.identity === undefined) request.identity = value.join("=");
15
16
  }
16
17
  return true;
17
18
  }