api-machine 1.3.0 → 2.0.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/CHANGELOG.md +1 -1
- package/LICENSE.md +20 -20
- package/README.md +275 -275
- package/authentication/authenticated-request.d.ts +5 -0
- package/authentication/authentication-scheme.d.ts +8 -1
- package/authentication/authentication-scheme.js +46 -4
- package/authentication/authentication-scheme.js.map +1 -1
- package/authentication/index.d.ts +2 -2
- package/authentication/index.js +2 -1
- package/authentication/index.js.map +1 -1
- package/authentication/schemes/bearer-authentication-scheme.d.ts +5 -4
- package/authentication/schemes/bearer-authentication-scheme.js +3 -1
- package/authentication/schemes/bearer-authentication-scheme.js.map +1 -1
- package/authentication/schemes/client-credentials-oauth2-scheme.d.ts +64 -0
- package/authentication/schemes/client-credentials-oauth2-scheme.js +99 -0
- package/authentication/schemes/client-credentials-oauth2-scheme.js.map +1 -0
- package/authorization/authorization.d.ts +16 -0
- package/authorization/authorization.js +3 -0
- package/authorization/authorization.js.map +1 -0
- package/authorization/index.d.ts +1 -0
- package/authorization/index.js +5 -0
- package/authorization/index.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/package.json +2 -1
- package/router/base.d.ts +10 -0
- package/router/base.js +32 -3
- package/router/base.js.map +1 -1
- package/router/endpoint.d.ts +3 -2
- package/router/endpoint.js +33 -0
- package/router/endpoint.js.map +1 -1
- package/router/endpoints/health-check-endpoint.js +2 -0
- package/router/endpoints/health-check-endpoint.js.map +1 -1
- package/router/index.d.ts +1 -0
- package/router/index.js +5 -1
- package/router/index.js.map +1 -1
- package/server/server-options.d.ts +7 -0
- package/server/server-options.js.map +1 -1
- package/server/server.d.ts +4 -0
- package/server/server.js +24 -0
- package/server/server.js.map +1 -1
- package/session/session.d.ts +2 -0
- package/di/container.d.ts +0 -31
- package/di/container.js +0 -57
- package/di/container.js.map +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SessionAuthenticationScheme = exports.InlineAuthenticationScheme = exports.AuthenticationScheme = void 0;
|
|
3
|
+
exports.SessionAuthenticationScheme = exports.InlineAuthenticationScheme = exports.throwIfAuthenticationBlocked = exports.AuthenticationScheme = void 0;
|
|
4
4
|
const router_1 = require("../router");
|
|
5
|
+
const error_1 = require("../error");
|
|
5
6
|
/**
|
|
6
7
|
* Abstract base class for authentication schemes
|
|
7
8
|
* Extend this class to create custom authentication schemes that integrate
|
|
@@ -21,6 +22,18 @@ class AuthenticationScheme {
|
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
24
|
exports.AuthenticationScheme = AuthenticationScheme;
|
|
25
|
+
function throwIfAuthenticationBlocked(result) {
|
|
26
|
+
if (result.allowed) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
throw new error_1.TooManyRequestsError('Authentication temporarily unavailable', {
|
|
30
|
+
retryAfter: typeof result.retryAfterSeconds === 'number' &&
|
|
31
|
+
result.retryAfterSeconds > 0
|
|
32
|
+
? result.retryAfterSeconds
|
|
33
|
+
: undefined,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
exports.throwIfAuthenticationBlocked = throwIfAuthenticationBlocked;
|
|
24
37
|
class InlineAuthenticationScheme extends AuthenticationScheme {
|
|
25
38
|
/**
|
|
26
39
|
* Generate the Express middleware that enforces this authentication
|
|
@@ -31,8 +44,11 @@ class InlineAuthenticationScheme extends AuthenticationScheme {
|
|
|
31
44
|
getMiddleware() {
|
|
32
45
|
return async (request, response, next) => {
|
|
33
46
|
const credentials = this.getCredentials(request);
|
|
34
|
-
await this.authenticate({ credentials, request });
|
|
47
|
+
const principal = await this.authenticate({ credentials, request });
|
|
35
48
|
request.authenticated = true;
|
|
49
|
+
if (principal) {
|
|
50
|
+
request.principal = principal;
|
|
51
|
+
}
|
|
36
52
|
return next();
|
|
37
53
|
};
|
|
38
54
|
}
|
|
@@ -71,14 +87,40 @@ class SessionAuthenticationScheme extends AuthenticationScheme {
|
|
|
71
87
|
}
|
|
72
88
|
getMiddleware() {
|
|
73
89
|
return async (request, response, next) => {
|
|
90
|
+
const sessionId = this.getSessionId(request);
|
|
74
91
|
await this.sessionDriver.checkSession({
|
|
75
|
-
|
|
76
|
-
sessionId: request.sessionId,
|
|
92
|
+
sessionId,
|
|
77
93
|
});
|
|
94
|
+
const session = await this.sessionDriver.getSession({ sessionId });
|
|
78
95
|
request.authenticated = true;
|
|
96
|
+
if (session.principal) {
|
|
97
|
+
request.principal = session.principal;
|
|
98
|
+
}
|
|
79
99
|
return next();
|
|
80
100
|
};
|
|
81
101
|
}
|
|
102
|
+
getSessionId(request) {
|
|
103
|
+
if (request.sessionId) {
|
|
104
|
+
return request.sessionId;
|
|
105
|
+
}
|
|
106
|
+
const cookieHeader = request.headers?.cookie;
|
|
107
|
+
if (!cookieHeader) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
const sessionCookie = cookieHeader
|
|
111
|
+
.split(';')
|
|
112
|
+
.map((cookie) => cookie.trim())
|
|
113
|
+
.find((cookie) => cookie.startsWith('sessionId='));
|
|
114
|
+
if (!sessionCookie) {
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
try {
|
|
118
|
+
return decodeURIComponent(sessionCookie.slice('sessionId='.length));
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
82
124
|
}
|
|
83
125
|
exports.SessionAuthenticationScheme = SessionAuthenticationScheme;
|
|
84
126
|
//# sourceMappingURL=authentication-scheme.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authentication-scheme.js","sourceRoot":"","sources":["../../../src/authentication/authentication-scheme.ts"],"names":[],"mappings":";;;AAKA,sCAKmB;
|
|
1
|
+
{"version":3,"file":"authentication-scheme.js","sourceRoot":"","sources":["../../../src/authentication/authentication-scheme.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { AuthenticatedRequest } from './authenticated-request';
|
|
2
|
-
export { AuthenticationScheme, InlineAuthenticationScheme, SessionAuthenticationScheme, } from './authentication-scheme';
|
|
1
|
+
export { AuthenticatedPrincipal, AuthenticatedRequest, } from './authenticated-request';
|
|
2
|
+
export { AuthenticationScheme, InlineAuthenticationScheme, SessionAuthenticationScheme, throwIfAuthenticationBlocked, AuthenticationProtectionResult, } from './authentication-scheme';
|
|
3
3
|
export { AuthFlow } from './auth-flow';
|
|
4
4
|
export * from './schemes';
|
package/authentication/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SessionAuthenticationScheme = exports.InlineAuthenticationScheme = exports.AuthenticationScheme = void 0;
|
|
3
|
+
exports.throwIfAuthenticationBlocked = exports.SessionAuthenticationScheme = exports.InlineAuthenticationScheme = exports.AuthenticationScheme = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
var authentication_scheme_1 = require("./authentication-scheme");
|
|
6
6
|
Object.defineProperty(exports, "AuthenticationScheme", { enumerable: true, get: function () { return authentication_scheme_1.AuthenticationScheme; } });
|
|
7
7
|
Object.defineProperty(exports, "InlineAuthenticationScheme", { enumerable: true, get: function () { return authentication_scheme_1.InlineAuthenticationScheme; } });
|
|
8
8
|
Object.defineProperty(exports, "SessionAuthenticationScheme", { enumerable: true, get: function () { return authentication_scheme_1.SessionAuthenticationScheme; } });
|
|
9
|
+
Object.defineProperty(exports, "throwIfAuthenticationBlocked", { enumerable: true, get: function () { return authentication_scheme_1.throwIfAuthenticationBlocked; } });
|
|
9
10
|
tslib_1.__exportStar(require("./schemes"), exports);
|
|
10
11
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/authentication/index.ts"],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/authentication/index.ts"],"names":[],"mappings":";;;;AAIA,iEAMiC;AALhC,6HAAA,oBAAoB,OAAA;AACpB,mIAAA,0BAA0B,OAAA;AAC1B,oIAAA,2BAA2B,OAAA;AAC3B,qIAAA,4BAA4B,OAAA;AAI7B,oDAA0B"}
|
|
@@ -2,7 +2,8 @@ import { AuthenticationSchemeOptions, InlineAuthenticationScheme } from '../auth
|
|
|
2
2
|
import { SecuritySchemeObject } from 'auto-oas/oas/v3.1';
|
|
3
3
|
import { LogInterface } from '../../log';
|
|
4
4
|
import { ApiRequest } from '../../router';
|
|
5
|
-
|
|
5
|
+
import { AuthenticatedPrincipal } from '../authenticated-request';
|
|
6
|
+
export type CheckTokenFunction = (token: string) => Promise<boolean | AuthenticatedPrincipal>;
|
|
6
7
|
export interface BearerAuthenticationSchemeOptions extends AuthenticationSchemeOptions {
|
|
7
8
|
/**
|
|
8
9
|
* The name of the security scheme in OpenAPI
|
|
@@ -21,8 +22,8 @@ export interface BearerAuthenticationSchemeOptions extends AuthenticationSchemeO
|
|
|
21
22
|
*/
|
|
22
23
|
description?: string;
|
|
23
24
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
25
|
+
* Validate a bearer token and optionally return the authenticated
|
|
26
|
+
* principal.
|
|
26
27
|
*/
|
|
27
28
|
checkToken: CheckTokenFunction;
|
|
28
29
|
/**
|
|
@@ -47,5 +48,5 @@ export declare class BearerAuthenticationScheme extends InlineAuthenticationSche
|
|
|
47
48
|
authenticate(options: {
|
|
48
49
|
credentials: string;
|
|
49
50
|
request: ApiRequest;
|
|
50
|
-
}): Promise<void>;
|
|
51
|
+
}): Promise<void | AuthenticatedPrincipal>;
|
|
51
52
|
}
|
|
@@ -67,7 +67,8 @@ class BearerAuthenticationScheme extends authentication_scheme_1.InlineAuthentic
|
|
|
67
67
|
details: validationResult.errors,
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
-
|
|
70
|
+
const tokenResult = await this.checkToken(validationResult.data);
|
|
71
|
+
if (!tokenResult) {
|
|
71
72
|
// eslint-disable-next-line max-len
|
|
72
73
|
const msg = 'Unauthorized access attempt from ' +
|
|
73
74
|
request.ip +
|
|
@@ -77,6 +78,7 @@ class BearerAuthenticationScheme extends authentication_scheme_1.InlineAuthentic
|
|
|
77
78
|
scheme: 'Bearer',
|
|
78
79
|
});
|
|
79
80
|
}
|
|
81
|
+
return typeof tokenResult === 'object' ? tokenResult : undefined;
|
|
80
82
|
}
|
|
81
83
|
}
|
|
82
84
|
exports.BearerAuthenticationScheme = BearerAuthenticationScheme;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bearer-authentication-scheme.js","sourceRoot":"","sources":["../../../../src/authentication/schemes/bearer-authentication-scheme.ts"],"names":[],"mappings":";;;AAAA,oEAGkC;AAElC,uCAAgD;AAChD,kDAAsD;
|
|
1
|
+
{"version":3,"file":"bearer-authentication-scheme.js","sourceRoot":"","sources":["../../../../src/authentication/schemes/bearer-authentication-scheme.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { AuthenticationSchemeOptions, InlineAuthenticationScheme } from '../authentication-scheme';
|
|
2
|
+
import { SecuritySchemeObject } from 'auto-oas/oas/v3.1';
|
|
3
|
+
import { LogInterface } from '../../log';
|
|
4
|
+
import { ApiRequest } from '../../router';
|
|
5
|
+
export type CheckTokenFunction = (token: string) => Promise<boolean>;
|
|
6
|
+
export interface ClientCredentialsOAuth2SchemeOptions extends AuthenticationSchemeOptions {
|
|
7
|
+
/**
|
|
8
|
+
* The name of the security scheme in OpenAPI
|
|
9
|
+
* @default 'OAuth2ClientCredentials'
|
|
10
|
+
*/
|
|
11
|
+
schemeName?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Description of the authentication scheme
|
|
14
|
+
* Appears in the OpenAPI documentation
|
|
15
|
+
*/
|
|
16
|
+
description?: string;
|
|
17
|
+
/**
|
|
18
|
+
* URL of the OAuth2 authorization server's token endpoint
|
|
19
|
+
* Used for OpenAPI documentation
|
|
20
|
+
* @default 'http://localhost:3000/oauth/token'
|
|
21
|
+
*/
|
|
22
|
+
tokenUrl?: string;
|
|
23
|
+
/**
|
|
24
|
+
* Function to validate the access token
|
|
25
|
+
* Should return true if the token is valid, false otherwise
|
|
26
|
+
*/
|
|
27
|
+
checkToken: CheckTokenFunction;
|
|
28
|
+
/**
|
|
29
|
+
* Optional logger for security events
|
|
30
|
+
*/
|
|
31
|
+
log?: LogInterface;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* OAuth2 Client Credentials authentication scheme
|
|
35
|
+
* Validates access tokens from the Authorization header using Bearer scheme
|
|
36
|
+
* Implements the OAuth2 Client Credentials flow for server-to-server authentication
|
|
37
|
+
* Automatically generates OpenAPI security scheme documentation
|
|
38
|
+
*
|
|
39
|
+
* Usage example:
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const oauth2 = new ClientCredentialsOAuth2Scheme({
|
|
42
|
+
* checkToken: async (token: string) => {
|
|
43
|
+
* // Validate against your token store or OAuth2 provider
|
|
44
|
+
* return validTokens.includes(token);
|
|
45
|
+
* },
|
|
46
|
+
* tokenUrl: 'https://auth-server.example.com/oauth/token',
|
|
47
|
+
* schemeName: 'OAuth2',
|
|
48
|
+
* });
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare class ClientCredentialsOAuth2Scheme extends InlineAuthenticationScheme {
|
|
52
|
+
readonly schemeName: string;
|
|
53
|
+
protected readonly description?: string;
|
|
54
|
+
protected readonly tokenUrl: string;
|
|
55
|
+
protected readonly checkToken: CheckTokenFunction;
|
|
56
|
+
protected readonly log?: LogInterface;
|
|
57
|
+
constructor(options: ClientCredentialsOAuth2SchemeOptions);
|
|
58
|
+
getSecurityScheme(): SecuritySchemeObject;
|
|
59
|
+
getCredentials(request: ApiRequest): unknown;
|
|
60
|
+
authenticate(options: {
|
|
61
|
+
credentials: string;
|
|
62
|
+
request: ApiRequest;
|
|
63
|
+
}): Promise<void>;
|
|
64
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClientCredentialsOAuth2Scheme = void 0;
|
|
4
|
+
const authentication_scheme_1 = require("../authentication-scheme");
|
|
5
|
+
const error_1 = require("../../error");
|
|
6
|
+
const primitives_1 = require("valsan/primitives");
|
|
7
|
+
/**
|
|
8
|
+
* OAuth2 Client Credentials authentication scheme
|
|
9
|
+
* Validates access tokens from the Authorization header using Bearer scheme
|
|
10
|
+
* Implements the OAuth2 Client Credentials flow for server-to-server authentication
|
|
11
|
+
* Automatically generates OpenAPI security scheme documentation
|
|
12
|
+
*
|
|
13
|
+
* Usage example:
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const oauth2 = new ClientCredentialsOAuth2Scheme({
|
|
16
|
+
* checkToken: async (token: string) => {
|
|
17
|
+
* // Validate against your token store or OAuth2 provider
|
|
18
|
+
* return validTokens.includes(token);
|
|
19
|
+
* },
|
|
20
|
+
* tokenUrl: 'https://auth-server.example.com/oauth/token',
|
|
21
|
+
* schemeName: 'OAuth2',
|
|
22
|
+
* });
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
class ClientCredentialsOAuth2Scheme extends authentication_scheme_1.InlineAuthenticationScheme {
|
|
26
|
+
schemeName;
|
|
27
|
+
description;
|
|
28
|
+
tokenUrl;
|
|
29
|
+
checkToken;
|
|
30
|
+
log;
|
|
31
|
+
constructor(options) {
|
|
32
|
+
super(options);
|
|
33
|
+
this.schemeName = options.schemeName || 'OAuth2ClientCredentials';
|
|
34
|
+
this.description = options.description;
|
|
35
|
+
this.tokenUrl = options.tokenUrl || 'http://localhost:3000/oauth/token';
|
|
36
|
+
this.checkToken = options.checkToken;
|
|
37
|
+
this.log = options.log;
|
|
38
|
+
}
|
|
39
|
+
getSecurityScheme() {
|
|
40
|
+
const scheme = {
|
|
41
|
+
type: 'oauth2',
|
|
42
|
+
flows: {
|
|
43
|
+
clientCredentials: {
|
|
44
|
+
tokenUrl: this.tokenUrl,
|
|
45
|
+
scopes: {},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
if (this.description) {
|
|
50
|
+
scheme.description = this.description;
|
|
51
|
+
}
|
|
52
|
+
return scheme;
|
|
53
|
+
}
|
|
54
|
+
getCredentials(request) {
|
|
55
|
+
const authHeader = request.headers['authorization'] ||
|
|
56
|
+
request.headers['Authorization'];
|
|
57
|
+
if (!authHeader) {
|
|
58
|
+
const msg = 'Unauthorized access attempt from ' +
|
|
59
|
+
request.ip +
|
|
60
|
+
' - No access token provided';
|
|
61
|
+
this.log?.warn(msg);
|
|
62
|
+
throw new error_1.UnauthorizedError('Authorization header is missing', {
|
|
63
|
+
scheme: 'Bearer',
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return authHeader;
|
|
67
|
+
}
|
|
68
|
+
async authenticate(options) {
|
|
69
|
+
const { credentials, request } = options;
|
|
70
|
+
if (!credentials) {
|
|
71
|
+
throw new error_1.UnauthorizedError('Authorization header is missing', {
|
|
72
|
+
scheme: 'Bearer',
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const validationResult = await new primitives_1.BearerTokenValSan().run(credentials);
|
|
76
|
+
if (!validationResult.success || !validationResult.data) {
|
|
77
|
+
const msg = 'Unauthorized access attempt from ' +
|
|
78
|
+
request.ip +
|
|
79
|
+
' - Invalid access token format';
|
|
80
|
+
const details = JSON.stringify(validationResult.errors, null, 2);
|
|
81
|
+
this.log?.warn(msg, details);
|
|
82
|
+
throw new error_1.UnauthorizedError('Access token is empty or invalid', {
|
|
83
|
+
scheme: 'Bearer',
|
|
84
|
+
details: validationResult.errors,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (!(await this.checkToken(validationResult.data))) {
|
|
88
|
+
const msg = 'Unauthorized access attempt from ' +
|
|
89
|
+
request.ip +
|
|
90
|
+
' - Access token validation failed';
|
|
91
|
+
this.log?.warn(msg);
|
|
92
|
+
throw new error_1.UnauthorizedError('Access token validation failed', {
|
|
93
|
+
scheme: 'Bearer',
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.ClientCredentialsOAuth2Scheme = ClientCredentialsOAuth2Scheme;
|
|
99
|
+
//# sourceMappingURL=client-credentials-oauth2-scheme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-credentials-oauth2-scheme.js","sourceRoot":"","sources":["../../../../src/authentication/schemes/client-credentials-oauth2-scheme.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AuthenticatedPrincipal } from '../authentication/authenticated-request';
|
|
2
|
+
export interface AuthorizationRequirement {
|
|
3
|
+
action: string;
|
|
4
|
+
resource?: string | Record<string, unknown>;
|
|
5
|
+
metadata?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface AuthorizationContext extends AuthorizationRequirement {
|
|
8
|
+
principal: AuthenticatedPrincipal;
|
|
9
|
+
}
|
|
10
|
+
export interface AuthorizationResult {
|
|
11
|
+
allowed: boolean;
|
|
12
|
+
reason?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ApiAuthorizationService {
|
|
15
|
+
evaluate(context: AuthorizationContext): Promise<AuthorizationResult>;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization.js","sourceRoot":"","sources":["../../../src/authorization/authorization.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './authorization';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/authorization/index.ts"],"names":[],"mappings":";;;AAAA,0DAAgC"}
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -5,5 +5,6 @@ tslib_1.__exportStar(require("./router"), exports);
|
|
|
5
5
|
tslib_1.__exportStar(require("./server"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./error"), exports);
|
|
7
7
|
tslib_1.__exportStar(require("./authentication"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./authorization"), exports);
|
|
8
9
|
tslib_1.__exportStar(require("./session"), exports);
|
|
9
10
|
//# sourceMappingURL=index.js.map
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,mDAAyB;AACzB,mDAAyB;AACzB,kDAAwB;AACxB,2DAAiC;AACjC,oDAA0B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,mDAAyB;AACzB,mDAAyB;AACzB,kDAAwB;AACxB,2DAAiC;AACjC,0DAAgC;AAChC,oDAA0B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "api-machine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "api-machine",
|
|
5
5
|
"typescript-template": {
|
|
6
6
|
"base": "1.0.1",
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
"scripts": {},
|
|
11
11
|
"dependencies": {
|
|
12
|
+
"@types/express": "^5.0.5",
|
|
12
13
|
"auto-oas": "^1.3.0",
|
|
13
14
|
"cors": "^2.8.5",
|
|
14
15
|
"express": "^5.1.0",
|
package/router/base.d.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Router as ExpressRouter, RequestHandler } from 'express';
|
|
2
2
|
import { AuthenticationScheme } from '../authentication/authentication-scheme';
|
|
3
3
|
import { DependencyContainer } from 'hidi';
|
|
4
|
+
import { AuthenticatedRequest } from '../authentication/authenticated-request';
|
|
5
|
+
import { ApiAuthorizationService, AuthorizationRequirement } from '../authorization';
|
|
6
|
+
export declare const AUTHENTICATION_KEY = "api-machine.authn";
|
|
7
|
+
export declare const AUTHORIZATION_KEY = "api-machine.authz";
|
|
8
|
+
export declare const AUTHORIZATION_REQUIREMENT_KEY = "api-machine.authorization-requirement";
|
|
4
9
|
export declare abstract class BaseApiRoute {
|
|
5
10
|
path: string;
|
|
6
11
|
fullPath: string;
|
|
@@ -21,6 +26,8 @@ export declare abstract class BaseApiRoute {
|
|
|
21
26
|
* If undefined, inherits from parent router or server
|
|
22
27
|
*/
|
|
23
28
|
authentication?: AuthenticationScheme | null;
|
|
29
|
+
authorizer?: ApiAuthorizationService | null;
|
|
30
|
+
authorization?: AuthorizationRequirement | null;
|
|
24
31
|
/**
|
|
25
32
|
* Parent route in the hierarchy (used for authentication cascading)
|
|
26
33
|
* @internal
|
|
@@ -36,5 +43,8 @@ export declare abstract class BaseApiRoute {
|
|
|
36
43
|
* @returns The authentication scheme to use, or undefined if public
|
|
37
44
|
*/
|
|
38
45
|
getEffectiveAuthentication(): AuthenticationScheme | undefined | null;
|
|
46
|
+
getEffectiveAuthorizationService(): ApiAuthorizationService | undefined | null;
|
|
47
|
+
getEffectiveAuthorizationRequirement(): AuthorizationRequirement | undefined | null;
|
|
48
|
+
logAuthorization(level: 'info' | 'warn' | 'error', event: string, request: AuthenticatedRequest, context?: Record<string, unknown>): void;
|
|
39
49
|
}
|
|
40
50
|
export type ApiRoute = new (...params: ConstructorParameters<typeof BaseApiRoute>) => BaseApiRoute;
|
package/router/base.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.BaseApiRoute = void 0;
|
|
3
|
+
exports.BaseApiRoute = exports.AUTHORIZATION_REQUIREMENT_KEY = exports.AUTHORIZATION_KEY = exports.AUTHENTICATION_KEY = void 0;
|
|
4
4
|
const hidi_1 = require("hidi");
|
|
5
|
+
exports.AUTHENTICATION_KEY = 'api-machine.authn';
|
|
6
|
+
exports.AUTHORIZATION_KEY = 'api-machine.authz';
|
|
7
|
+
exports.AUTHORIZATION_REQUIREMENT_KEY = 'api-machine.authorization-requirement';
|
|
5
8
|
class BaseApiRoute {
|
|
6
9
|
path;
|
|
7
10
|
fullPath;
|
|
@@ -22,6 +25,8 @@ class BaseApiRoute {
|
|
|
22
25
|
* If undefined, inherits from parent router or server
|
|
23
26
|
*/
|
|
24
27
|
authentication;
|
|
28
|
+
authorizer;
|
|
29
|
+
authorization;
|
|
25
30
|
/**
|
|
26
31
|
* Parent route in the hierarchy (used for authentication cascading)
|
|
27
32
|
* @internal
|
|
@@ -30,7 +35,13 @@ class BaseApiRoute {
|
|
|
30
35
|
parentRoute;
|
|
31
36
|
async register(_parentRouter, _parentPath) {
|
|
32
37
|
if (this.authentication !== undefined) {
|
|
33
|
-
this.container.register(
|
|
38
|
+
this.container.register(exports.AUTHENTICATION_KEY, this.authentication);
|
|
39
|
+
}
|
|
40
|
+
if (this.authorizer !== undefined) {
|
|
41
|
+
this.container.register(exports.AUTHORIZATION_KEY, this.authorizer);
|
|
42
|
+
}
|
|
43
|
+
if (this.authorization !== undefined) {
|
|
44
|
+
this.container.register(exports.AUTHORIZATION_REQUIREMENT_KEY, this.authorization);
|
|
34
45
|
}
|
|
35
46
|
this.inject();
|
|
36
47
|
}
|
|
@@ -58,7 +69,25 @@ class BaseApiRoute {
|
|
|
58
69
|
* @returns The authentication scheme to use, or undefined if public
|
|
59
70
|
*/
|
|
60
71
|
getEffectiveAuthentication() {
|
|
61
|
-
return this.container.get(
|
|
72
|
+
return this.container.get(exports.AUTHENTICATION_KEY);
|
|
73
|
+
}
|
|
74
|
+
getEffectiveAuthorizationService() {
|
|
75
|
+
return this.container.get(exports.AUTHORIZATION_KEY);
|
|
76
|
+
}
|
|
77
|
+
getEffectiveAuthorizationRequirement() {
|
|
78
|
+
return this.container.get(exports.AUTHORIZATION_REQUIREMENT_KEY);
|
|
79
|
+
}
|
|
80
|
+
logAuthorization(level, event, request, context = {}) {
|
|
81
|
+
const logger = this.container.get('log');
|
|
82
|
+
if (logger) {
|
|
83
|
+
logger[level](event, {
|
|
84
|
+
...context,
|
|
85
|
+
principalId: request.principal?.id,
|
|
86
|
+
method: request.method,
|
|
87
|
+
path: request.originalUrl,
|
|
88
|
+
requestId: request.headers?.['x-request-id'],
|
|
89
|
+
});
|
|
90
|
+
}
|
|
62
91
|
}
|
|
63
92
|
}
|
|
64
93
|
exports.BaseApiRoute = BaseApiRoute;
|
package/router/base.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/router/base.ts"],"names":[],"mappings":";;;AAEA,+BAA2C;
|
|
1
|
+
{"version":3,"file":"base.js","sourceRoot":"","sources":["../../../src/router/base.ts"],"names":[],"mappings":"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"}
|
package/router/endpoint.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { Router as ExpressRouter,
|
|
1
|
+
import { Router as ExpressRouter, Response as ExpressResponse, NextFunction as ExpressNextFunction } from 'express';
|
|
2
2
|
import { ObjectSanitizer } from 'valsan/object-sanitizer';
|
|
3
3
|
import { BaseApiRoute } from './base';
|
|
4
4
|
import { HTTPError } from '../error';
|
|
5
5
|
import { ArrayValSan, ObjectValSan } from 'valsan';
|
|
6
|
-
|
|
6
|
+
import { AuthenticatedRequest } from '../authentication/authenticated-request';
|
|
7
|
+
export type ApiRequest = AuthenticatedRequest;
|
|
7
8
|
export type ApiResponse = ExpressResponse;
|
|
8
9
|
export type ApiNextFunction = ExpressNextFunction;
|
|
9
10
|
export type ApiResponseData = {
|
package/router/endpoint.js
CHANGED
|
@@ -57,6 +57,39 @@ class BaseApiEndpoint extends base_1.BaseApiRoute {
|
|
|
57
57
|
if (effectiveAuth) {
|
|
58
58
|
endpointMiddleware.push(effectiveAuth.getMiddleware());
|
|
59
59
|
}
|
|
60
|
+
const authorization = this.getEffectiveAuthorizationRequirement();
|
|
61
|
+
if (authorization) {
|
|
62
|
+
const authorizer = this.getEffectiveAuthorizationService();
|
|
63
|
+
if (!authorizer) {
|
|
64
|
+
throw new Error('Authorization is configured but no authorizer is available');
|
|
65
|
+
}
|
|
66
|
+
endpointMiddleware.push(async (request, _response, next) => {
|
|
67
|
+
const principal = request.principal;
|
|
68
|
+
if (!principal) {
|
|
69
|
+
this.logAuthorization('warn', 'authorization.missing-principal', request);
|
|
70
|
+
throw new error_1.UnauthorizedError('An authenticated principal is required');
|
|
71
|
+
}
|
|
72
|
+
let result;
|
|
73
|
+
try {
|
|
74
|
+
result = await authorizer.evaluate({
|
|
75
|
+
...authorization,
|
|
76
|
+
principal,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
this.logAuthorization('error', 'authorization.error', request, { ...authorization, error });
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
if (!result.allowed) {
|
|
84
|
+
this.logAuthorization('warn', 'authorization.denied', request, { ...authorization, reason: result.reason });
|
|
85
|
+
throw new error_1.ForbiddenError(result.reason || 'Authorization denied');
|
|
86
|
+
}
|
|
87
|
+
this.logAuthorization('info', 'authorization.allowed', request, {
|
|
88
|
+
...authorization,
|
|
89
|
+
});
|
|
90
|
+
return next();
|
|
91
|
+
});
|
|
92
|
+
}
|
|
60
93
|
// Register with middleware (if any) before the handler
|
|
61
94
|
if (endpointMiddleware.length > 0) {
|
|
62
95
|
parentRouter[this.method](this.path, ...endpointMiddleware, this.handleWrapper.bind(this));
|
package/router/endpoint.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../../src/router/endpoint.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../../../src/router/endpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,8 @@ const valsan_1 = require("valsan");
|
|
|
5
5
|
const get_endpoint_1 = require("./get-endpoint");
|
|
6
6
|
class HealthCheckEndpoint extends get_endpoint_1.GetEndpoint {
|
|
7
7
|
path = '/health';
|
|
8
|
+
// override authentication = null;
|
|
9
|
+
// override authorization = null;
|
|
8
10
|
responseExample = {
|
|
9
11
|
status: 'ok',
|
|
10
12
|
timestamp: new Date().toISOString(),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"health-check-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/health-check-endpoint.ts"],"names":[],"mappings":";;;AAAA,mCAKgB;AAChB,iDAA6C;AAE7C,MAAa,mBAAoB,SAAQ,0BAAW;IAC1C,IAAI,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"health-check-endpoint.js","sourceRoot":"","sources":["../../../../src/router/endpoints/health-check-endpoint.ts"],"names":[],"mappings":";;;AAAA,mCAKgB;AAChB,iDAA6C;AAE7C,MAAa,mBAAoB,SAAQ,0BAAW;IAC1C,IAAI,GAAG,SAAS,CAAC;IAC1B,kCAAkC;IAClC,iCAAiC;IAExB,eAAe,GAAG;QAC1B,MAAM,EAAE,IAAI;QACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,KAAK;QACb,WAAW,EAAE,aAAa;KAC1B,CAAC;IAEO,QAAQ,GAAG,IAAI,qBAAY,CAAC;QACpC,MAAM,EAAE;YACP,MAAM,EAAE,IAAI,2BAAkB,EAAE;YAChC,SAAS,EAAE,IAAI,+BAAsB,EAAE;YACvC,MAAM,EAAE,IAAI,6BAAoB,EAAE;YAClC,WAAW,EAAE,IAAI,2BAAkB,EAAE;SACrC;KACD,CAAC,CAAC;IAEH,KAAK,CAAC,MAAM;QACX,OAAO;YACN,MAAM,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE;YAC9B,SAAS,EAAE,MAAM,IAAI,CAAC,YAAY,EAAE;YACpC,MAAM,EAAE,MAAM,IAAI,CAAC,SAAS,EAAE;YAC9B,WAAW,EAAE,MAAM,IAAI,CAAC,cAAc,EAAE;SACxC,CAAC;IACH,CAAC;IAEM,KAAK,CAAC,SAAS;QACrB,OAAO,IAAI,CAAC;IACb,CAAC;IAEM,KAAK,CAAC,YAAY;QACxB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACjC,CAAC;IAEM,KAAK,CAAC,SAAS;QACrB,OAAO,OAAO,CAAC,MAAM,EAAE,CAAC;IACzB,CAAC;IAEM,KAAK,CAAC,cAAc;QAC1B,OAAO,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,aAAa,CAAC;IACjD,CAAC;CACD;AA7CD,kDA6CC"}
|
package/router/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { ApiEndpoint, ApiRequest, ApiResponse, ApiNextFunction, BaseApiEndpoint, } from './endpoint';
|
|
2
2
|
export { ApiRouter, BaseApiRouter } from './router';
|
|
3
|
+
export { AUTHENTICATION_KEY, AUTHORIZATION_KEY, AUTHORIZATION_REQUIREMENT_KEY, } from './base';
|
|
3
4
|
export { GetEndpoint, PostEndpoint, PutEndpoint, DeleteEndpoint, PatchEndpoint, HealthCheckEndpoint, } from './endpoints';
|