@o3co/auth-provider-foundation 0.14.0 → 0.16.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/README.ja.md +147 -61
- package/README.md +368 -81
- package/dist/endpointUrl.d.mts +20 -0
- package/dist/endpointUrl.d.mts.map +1 -1
- package/dist/endpointUrl.mjs +30 -0
- package/dist/index.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +20 -0
- package/dist/repositories/HttpUserRepository.d.mts +111 -7
- package/dist/repositories/HttpUserRepository.d.mts.map +1 -1
- package/dist/repositories/HttpUserRepository.mjs +434 -30
- package/dist/repositories/storeErrors.d.mts +81 -0
- package/dist/repositories/storeErrors.d.mts.map +1 -0
- package/dist/repositories/storeErrors.mjs +193 -0
- package/dist/repositories/wwwAuthenticate.d.mts +10 -0
- package/dist/repositories/wwwAuthenticate.d.mts.map +1 -0
- package/dist/repositories/wwwAuthenticate.mjs +58 -0
- package/package.json +4 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FederatedIdentityLink, type FederatedIdentityLookup, type FederatedIdentityLookupResult, type FederatedIdentityRegistration, type LinkFederatedIdentityResult, type User, type UserRepository } from "@o3co/auth-provider-core";
|
|
2
2
|
/**
|
|
3
3
|
* Default ceiling on an upstream response body, in bytes.
|
|
4
4
|
*
|
|
@@ -7,36 +7,114 @@ import type { FederatedIdentityLink, LinkFederatedIdentityResult, User, UserRepo
|
|
|
7
7
|
* process out of memory one login at a time (#285).
|
|
8
8
|
*/
|
|
9
9
|
export declare const DEFAULT_MAX_RESPONSE_BYTES: number;
|
|
10
|
+
/**
|
|
11
|
+
* What the Store declares it can place (#613): identities issued under one
|
|
12
|
+
* registration — the federation's name, the issuer and the client, exactly as
|
|
13
|
+
* a federation-grant connection is configured — given at least these claims
|
|
14
|
+
* from the verified id_token. The synchronous probe D7 check 5 asks at boot
|
|
15
|
+
* cannot reach the Store, so the operator relays the Store's own claim here;
|
|
16
|
+
* boot then holds every connection to it. `requiredClaims = []` is a strategy
|
|
17
|
+
* on the registration and the `sub` alone.
|
|
18
|
+
*/
|
|
19
|
+
export interface FederatedIdentityLookupCoverage {
|
|
20
|
+
readonly provider: string;
|
|
21
|
+
readonly issuer: string;
|
|
22
|
+
readonly clientId: string;
|
|
23
|
+
readonly requiredClaims: readonly string[];
|
|
24
|
+
}
|
|
10
25
|
/**
|
|
11
26
|
* `UserRepository` backed by "the Store" — the upstream user service defined
|
|
12
27
|
* on core's `User` doc (`@o3co/auth-provider-core`, `src/repositories/types.mts`).
|
|
13
28
|
*
|
|
14
|
-
*
|
|
15
|
-
* **construction**: a deployment configured with an
|
|
16
|
-
* at boot rather than leaking the first user's
|
|
17
|
-
* accepted for loopback hosts only — see
|
|
18
|
-
* carve-out and its rationale.
|
|
29
|
+
* Every endpoint receives a plaintext credential or a verified identity, so
|
|
30
|
+
* each is validated at **construction**: a deployment configured with an
|
|
31
|
+
* `http://` Store URL fails at boot rather than leaking the first user's
|
|
32
|
+
* password (#285). `http://` is accepted for loopback hosts only — see
|
|
33
|
+
* `src/endpointUrl.mts` for the carve-out and its rationale.
|
|
34
|
+
*
|
|
35
|
+
* No request follows a redirect, so a URL that passed that check is the only
|
|
36
|
+
* place its body is ever sent and the only one whose answer is taken: a `3xx`
|
|
37
|
+
* from the Store is an upstream failure, thrown like any other unexpected
|
|
38
|
+
* status, and its `Location` is never contacted.
|
|
39
|
+
*
|
|
40
|
+
* With `bearerToken` configured, every request — authentication, linking and
|
|
41
|
+
* the identity lookup alike — carries `Authorization: Bearer <token>`, so the
|
|
42
|
+
* Store can refuse a caller that is not this deployment; without it, no
|
|
43
|
+
* request carries an `Authorization` header. The Store says it refused THIS
|
|
44
|
+
* deployment by answering `401` or `403` with a `Bearer` challenge (RFC 6750
|
|
45
|
+
* §3), and that answer, while a token was sent, throws a
|
|
46
|
+
* {@link StoreCredentialRefusedError} on every request — never "no such user"
|
|
47
|
+
* or a refused link, which is what either status without the challenge still
|
|
48
|
+
* means.
|
|
49
|
+
*
|
|
50
|
+
* A transport's own error is never thrown: undici's parser errors quote the
|
|
51
|
+
* bytes they rejected, and a peer that reflects the request puts the
|
|
52
|
+
* `Authorization` header — or a password — there. A request that cannot be
|
|
53
|
+
* made, or an answer that cannot be read, throws a `StoreTransportError`
|
|
54
|
+
* (`src/repositories/storeErrors.mts`): a fixed message naming the endpoint
|
|
55
|
+
* and what failed, at most an allowlisted transport code, no cause.
|
|
56
|
+
*
|
|
57
|
+
* Every message names an endpoint by its origin and path alone
|
|
58
|
+
* (`endpointForMessage`, `src/endpointUrl.mts`): a Store URL may carry a
|
|
59
|
+
* query string, and a query may carry a credential, while every caller logs
|
|
60
|
+
* what this throws.
|
|
19
61
|
*/
|
|
20
62
|
export declare class HttpUserRepository implements UserRepository {
|
|
63
|
+
#private;
|
|
21
64
|
private authenticateUrl;
|
|
22
65
|
private authenticateByTokenUrl;
|
|
23
66
|
private timeout;
|
|
24
67
|
private maxResponseBytes;
|
|
25
68
|
private linkFederatedIdentityUrl?;
|
|
69
|
+
private findSubjectByFederatedIdentityUrl?;
|
|
70
|
+
private readonly coverage;
|
|
26
71
|
/**
|
|
27
72
|
* #482 — see {@link UserRepository.linkFederatedIdentity}. Present only when
|
|
28
73
|
* `linkFederatedIdentityUrl` is configured, which is how the federation routes
|
|
29
74
|
* know to refuse `?link=1` up front instead of at the callback.
|
|
30
75
|
*/
|
|
31
76
|
readonly linkFederatedIdentity?: (userId: string, identity: FederatedIdentityLink) => Promise<LinkFederatedIdentityResult>;
|
|
32
|
-
|
|
77
|
+
/**
|
|
78
|
+
* #613 — see {@link UserRepository.supportsFederatedIdentityLookup}. Present
|
|
79
|
+
* together with the lookup, only when `findSubjectByFederatedIdentityUrl` is
|
|
80
|
+
* configured: absent, a deployment that requires the lookup is refused at
|
|
81
|
+
* boot by the method's name, which is the message that says what to set.
|
|
82
|
+
* Answers from the declaration alone — the Store is not asked at boot.
|
|
83
|
+
*/
|
|
84
|
+
readonly supportsFederatedIdentityLookup?: (registration: FederatedIdentityRegistration, identityClaims: readonly string[]) => boolean;
|
|
85
|
+
/** #613 — see {@link UserRepository.findSubjectByFederatedIdentity}. Present with the probe. */
|
|
86
|
+
readonly findSubjectByFederatedIdentity?: (identity: FederatedIdentityLookup) => Promise<FederatedIdentityLookupResult>;
|
|
87
|
+
constructor({ authenticateUrl, authenticateByTokenUrl, linkFederatedIdentityUrl, findSubjectByFederatedIdentityUrl, federatedIdentityLookupCoverage, bearerToken, timeout, maxResponseBytes, }: {
|
|
33
88
|
authenticateUrl: string;
|
|
34
89
|
authenticateByTokenUrl: string;
|
|
35
90
|
/** #482: optional; the Store's link endpoint. Same https rule as the other two. */
|
|
36
91
|
linkFederatedIdentityUrl?: string;
|
|
92
|
+
/** #613: optional; the Store's identity lookup. Same https rule; carries a verified identity. */
|
|
93
|
+
findSubjectByFederatedIdentityUrl?: string;
|
|
94
|
+
/** #613: which registrations the Store's lookup covers. Needs the URL; `[]` covers none. */
|
|
95
|
+
federatedIdentityLookupCoverage?: readonly FederatedIdentityLookupCoverage[];
|
|
96
|
+
/**
|
|
97
|
+
* Optional; sent to the Store on every request as `Authorization: Bearer
|
|
98
|
+
* <token>`. A bare RFC 6750 token (no scheme) of at least
|
|
99
|
+
* `MIN_SECRET_ENTROPY_BYTES` of key material — `openssl rand -hex 32`.
|
|
100
|
+
*/
|
|
101
|
+
bearerToken?: string;
|
|
37
102
|
timeout: number;
|
|
38
103
|
maxResponseBytes?: number;
|
|
39
104
|
});
|
|
105
|
+
/** What every request carries: the body's type and, when configured, the credential. */
|
|
106
|
+
private headers;
|
|
107
|
+
/**
|
|
108
|
+
* Throws {@link StoreCredentialRefusedError} when a non-`2xx` answer is the
|
|
109
|
+
* Store refusing this deployment's credential: a `401` or `403` with a
|
|
110
|
+
* `Bearer` challenge, to a request that carried the token. Read before any
|
|
111
|
+
* other reading of the status — without it a token the Store does not
|
|
112
|
+
* accept is every login "no such user" and every link "refused", with
|
|
113
|
+
* nothing logged. Without a token sent, a challenge is not about one, and a
|
|
114
|
+
* Store whose stack challenges every refusal keeps the wire meaning it has
|
|
115
|
+
* always had.
|
|
116
|
+
*/
|
|
117
|
+
private assertCredentialAccepted;
|
|
40
118
|
authenticate(username: string, password: string): Promise<User | null>;
|
|
41
119
|
authenticateByToken(token: string): Promise<User | null>;
|
|
42
120
|
/**
|
|
@@ -46,6 +124,32 @@ export declare class HttpUserRepository implements UserRepository {
|
|
|
46
124
|
* provider, …); `409` says the identity is already someone else's.
|
|
47
125
|
*/
|
|
48
126
|
private linkViaHttp;
|
|
127
|
+
/** The declaration for a registration, if the operator made one. Exact on all three. */
|
|
128
|
+
private declared;
|
|
129
|
+
/**
|
|
130
|
+
* POST `{ provider, issuer, clientId, sub, claims }` to the Store's lookup
|
|
131
|
+
* (#613) and read one of the port's three answers. Answered locally, with
|
|
132
|
+
* no request, where the declaration already decides: a registration nobody
|
|
133
|
+
* declared is `registration_not_covered`, and a declared one arriving
|
|
134
|
+
* without a claim its strategy needs is `identity_not_resolvable`. Every
|
|
135
|
+
* claim the connection supplied is sent, not only the required ones: what
|
|
136
|
+
* the Store matches on is the Store's business.
|
|
137
|
+
*/
|
|
138
|
+
private lookupViaHttp;
|
|
139
|
+
/**
|
|
140
|
+
* The lookup's transport: the same deadline, cap and abort as {@link post},
|
|
141
|
+
* and like it never follows a redirect — the body carries a verified
|
|
142
|
+
* identity, and a `Location` is not a configured endpoint. None of
|
|
143
|
+
* {@link post}'s readings, though. A `401`/`403` is not "nobody", a `409` is
|
|
144
|
+
* not a conflict, a `404` is not an absence: only a `2xx` carrying one of the
|
|
145
|
+
* three answers is an answer, and everything else throws — as an outage,
|
|
146
|
+
* which is what a lookup that could not be made is — a `401` or `403` with a
|
|
147
|
+
* `Bearer` challenge, to a request that carried the token, as the refused
|
|
148
|
+
* credential it is. What is thrown names the endpoint by origin and path — and, for an answer
|
|
149
|
+
* with a status, the status; for a transport failure, at most its code — and
|
|
150
|
+
* never the body, the identity, a status text or an underlying cause.
|
|
151
|
+
*/
|
|
152
|
+
private postLookup;
|
|
49
153
|
private post;
|
|
50
154
|
}
|
|
51
155
|
//# sourceMappingURL=HttpUserRepository.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HttpUserRepository.d.mts","sourceRoot":"","sources":["../../src/repositories/HttpUserRepository.mts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"HttpUserRepository.d.mts","sourceRoot":"","sources":["../../src/repositories/HttpUserRepository.mts"],"names":[],"mappings":"AAgBA,OAAO,EAEN,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,6BAA6B,EAClC,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAGhC,KAAK,IAAI,EACT,KAAK,cAAc,EACnB,MAAM,0BAA0B,CAAC;AAQlC;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,QAAc,CAAC;AA8BtD;;;;;;;;GAQG;AACH,MAAM,WAAW,+BAA+B;IAC/C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C;AA4RD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,qBAAa,kBAAmB,YAAW,cAAc;;IAOxD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,sBAAsB,CAAS;IACvC,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,wBAAwB,CAAC,CAAS;IAC1C,OAAO,CAAC,iCAAiC,CAAC,CAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA6C;IACtE;;;;OAIG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,qBAAqB,KAC3B,OAAO,CAAC,2BAA2B,CAAC,CAAC;IAC1C;;;;;;OAMG;IACH,QAAQ,CAAC,+BAA+B,CAAC,EAAE,CAC1C,YAAY,EAAE,6BAA6B,EAC3C,cAAc,EAAE,SAAS,MAAM,EAAE,KAC7B,OAAO,CAAC;IACb,gGAAgG;IAChG,QAAQ,CAAC,8BAA8B,CAAC,EAAE,CACzC,QAAQ,EAAE,uBAAuB,KAC7B,OAAO,CAAC,6BAA6B,CAAC,CAAC;gBAEhC,EACX,eAAe,EACf,sBAAsB,EACtB,wBAAwB,EACxB,iCAAiC,EACjC,+BAA+B,EAC/B,WAAW,EACX,OAAO,EACP,gBAA6C,GAC7C,EAAE;QACF,eAAe,EAAE,MAAM,CAAC;QACxB,sBAAsB,EAAE,MAAM,CAAC;QAC/B,mFAAmF;QACnF,wBAAwB,CAAC,EAAE,MAAM,CAAC;QAClC,iGAAiG;QACjG,iCAAiC,CAAC,EAAE,MAAM,CAAC;QAC3C,4FAA4F;QAC5F,+BAA+B,CAAC,EAAE,SAAS,+BAA+B,EAAE,CAAC;QAC7E;;;;WAIG;QACH,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC1B;IAmDD,wFAAwF;IACxF,OAAO,CAAC,OAAO;IAMf;;;;;;;;;OASG;IACH,OAAO,CAAC,wBAAwB;IAU1B,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAKtE,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAI9D;;;;;OAKG;YACW,WAAW;IAWzB,wFAAwF;IACxF,OAAO,CAAC,QAAQ;IAWhB;;;;;;;;OAQG;YACW,aAAa;IAoB3B;;;;;;;;;;;;OAYG;YACW,UAAU;YA8EV,IAAI;CAiHlB"}
|