@commercetools/connect-payments-sdk 0.0.3 → 0.0.4
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 +6 -0
- package/dist/api/handlers/config.handler.d.ts +1 -1
- package/dist/api/handlers/status.handler.d.ts +9 -1
- package/dist/api/handlers/types/handler.type.d.ts +2 -2
- package/dist/api/hooks/jwt-auth.hook.d.ts +16 -0
- package/dist/api/hooks/jwt-auth.hook.js +22 -0
- package/dist/api/hooks/oauth2-auth.hook.d.ts +16 -0
- package/dist/api/hooks/oauth2-auth.hook.js +22 -0
- package/dist/api/hooks/types/hook.type.d.ts +3 -0
- package/dist/api/index.d.ts +2 -0
- package/dist/api/index.js +2 -0
- package/dist/errorx/errorx.d.ts +1 -1
- package/dist/errorx/errorx.js +3 -3
- package/dist/index.d.ts +6 -2
- package/dist/index.js +25 -1
- package/dist/security/authn/authns.d.ts +26 -1
- package/dist/security/authn/authns.js +64 -1
- package/dist/security/authn/bearer-utils.d.ts +1 -0
- package/dist/security/authn/bearer-utils.js +19 -0
- package/dist/security/authn/jwt-authn-manager.d.ts +12 -0
- package/dist/security/authn/jwt-authn-manager.js +33 -0
- package/dist/security/authn/oauth2-authn-manager.d.ts +17 -0
- package/dist/security/authn/oauth2-authn-manager.js +65 -0
- package/dist/security/authn/session-authn-manager.js +1 -1
- package/dist/security/authn/types/authn.type.d.ts +11 -2
- package/dist/security/index.d.ts +5 -1
- package/dist/security/index.js +5 -1
- package/dist/security/services/jwt.service.d.ts +10 -0
- package/dist/security/services/jwt.service.js +40 -0
- package/dist/security/services/oauth2.service.d.ts +9 -0
- package/dist/security/services/oauth2.service.js +40 -0
- package/dist/security/services/types/jwt.type.d.ts +5 -0
- package/dist/security/services/types/jwt.type.js +2 -0
- package/dist/security/services/types/oauth2.type.d.ts +14 -0
- package/dist/security/services/types/oauth2.type.js +2 -0
- package/package.json +4 -2
- package/.github/workflows/ci.yml +0 -34
- package/.github/workflows/release.yml +0 -46
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { CommercetoolsAuthorizationService } from '../../commercetools';
|
|
2
2
|
import { HandlerResponse } from './types/handler.type';
|
|
3
|
+
type HealthCheckStatus = {
|
|
4
|
+
status: 'OK' | 'Partially Available' | 'Unavailable';
|
|
5
|
+
timestamp: string;
|
|
6
|
+
checks: HealthCheckResult[];
|
|
7
|
+
version: string;
|
|
8
|
+
metadata?: object;
|
|
9
|
+
};
|
|
3
10
|
export type HealthCheckResult = {
|
|
4
11
|
name: string;
|
|
5
12
|
status: 'UP' | 'DOWN';
|
|
@@ -10,7 +17,7 @@ export declare const statusHandler: (options: {
|
|
|
10
17
|
timeout: number;
|
|
11
18
|
checks: HealthCheck[];
|
|
12
19
|
metadataFn?: () => Promise<object> | object;
|
|
13
|
-
}) => () => Promise<HandlerResponse
|
|
20
|
+
}) => () => Promise<HandlerResponse<HealthCheckStatus>>;
|
|
14
21
|
/**
|
|
15
22
|
* Check if CoCo permissions are available
|
|
16
23
|
* @param opts
|
|
@@ -21,3 +28,4 @@ export declare const healthCheckCommercetoolsPermissions: (opts: {
|
|
|
21
28
|
projectKey: string;
|
|
22
29
|
requiredPermissions: string[];
|
|
23
30
|
}) => () => Promise<HealthCheckResult>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingHttpHeaders } from 'node:http';
|
|
3
|
+
import { JWTAuthenticationManager } from '../../security/authn/jwt-authn-manager';
|
|
4
|
+
import { ContextProvider, RequestContextData } from '../context/types/request-context.type';
|
|
5
|
+
import { AuthenticationHook } from './types/hook.type';
|
|
6
|
+
export declare class JWTAuthenticationHook implements AuthenticationHook {
|
|
7
|
+
private authenticationManager;
|
|
8
|
+
private contextProvider;
|
|
9
|
+
constructor(opts: {
|
|
10
|
+
authenticationManager: JWTAuthenticationManager;
|
|
11
|
+
contextProvider: ContextProvider<RequestContextData>;
|
|
12
|
+
});
|
|
13
|
+
authenticate(): (request: {
|
|
14
|
+
headers: IncomingHttpHeaders;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JWTAuthenticationHook = void 0;
|
|
4
|
+
const security_1 = require("../../security");
|
|
5
|
+
class JWTAuthenticationHook {
|
|
6
|
+
authenticationManager;
|
|
7
|
+
contextProvider;
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
this.authenticationManager = opts.authenticationManager;
|
|
10
|
+
this.contextProvider = opts.contextProvider;
|
|
11
|
+
}
|
|
12
|
+
authenticate() {
|
|
13
|
+
return async (request) => {
|
|
14
|
+
const authorizationHeader = new security_1.HeaderBasedAuthentication(request.headers['authorization']);
|
|
15
|
+
const authn = await this.authenticationManager.authenticate(authorizationHeader);
|
|
16
|
+
this.contextProvider.updateContextData({
|
|
17
|
+
authentication: authn,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.JWTAuthenticationHook = JWTAuthenticationHook;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { IncomingHttpHeaders } from 'node:http';
|
|
3
|
+
import { Oauth2AuthenticationManager } from '../../security/authn/oauth2-authn-manager';
|
|
4
|
+
import { ContextProvider, RequestContextData } from '../context/types/request-context.type';
|
|
5
|
+
import { AuthenticationHook } from './types/hook.type';
|
|
6
|
+
export declare class Oauth2AuthenticationHook implements AuthenticationHook {
|
|
7
|
+
private authenticationManager;
|
|
8
|
+
private contextProvider;
|
|
9
|
+
constructor(opts: {
|
|
10
|
+
authenticationManager: Oauth2AuthenticationManager;
|
|
11
|
+
contextProvider: ContextProvider<RequestContextData>;
|
|
12
|
+
});
|
|
13
|
+
authenticate(): (request: {
|
|
14
|
+
headers: IncomingHttpHeaders;
|
|
15
|
+
}) => Promise<void>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Oauth2AuthenticationHook = void 0;
|
|
4
|
+
const security_1 = require("../../security");
|
|
5
|
+
class Oauth2AuthenticationHook {
|
|
6
|
+
authenticationManager;
|
|
7
|
+
contextProvider;
|
|
8
|
+
constructor(opts) {
|
|
9
|
+
this.authenticationManager = opts.authenticationManager;
|
|
10
|
+
this.contextProvider = opts.contextProvider;
|
|
11
|
+
}
|
|
12
|
+
authenticate() {
|
|
13
|
+
return async (request) => {
|
|
14
|
+
const authorizationHeader = new security_1.HeaderBasedAuthentication(request.headers['authorization']);
|
|
15
|
+
const authn = await this.authenticationManager.authenticate(authorizationHeader);
|
|
16
|
+
this.contextProvider.updateContextData({
|
|
17
|
+
authentication: authn,
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
exports.Oauth2AuthenticationHook = Oauth2AuthenticationHook;
|
package/dist/api/index.d.ts
CHANGED
|
@@ -2,5 +2,7 @@ export * from './context/request-context.provider';
|
|
|
2
2
|
export * from './context/types/request-context.type';
|
|
3
3
|
export * from './handlers/config.handler';
|
|
4
4
|
export * from './handlers/status.handler';
|
|
5
|
+
export * from './hooks/jwt-auth.hook';
|
|
6
|
+
export * from './hooks/oauth2-auth.hook';
|
|
5
7
|
export * from './hooks/session-auth.hook';
|
|
6
8
|
export * from './hooks/types/hook.type';
|
package/dist/api/index.js
CHANGED
|
@@ -18,5 +18,7 @@ __exportStar(require("./context/request-context.provider"), exports);
|
|
|
18
18
|
__exportStar(require("./context/types/request-context.type"), exports);
|
|
19
19
|
__exportStar(require("./handlers/config.handler"), exports);
|
|
20
20
|
__exportStar(require("./handlers/status.handler"), exports);
|
|
21
|
+
__exportStar(require("./hooks/jwt-auth.hook"), exports);
|
|
22
|
+
__exportStar(require("./hooks/oauth2-auth.hook"), exports);
|
|
21
23
|
__exportStar(require("./hooks/session-auth.hook"), exports);
|
|
22
24
|
__exportStar(require("./hooks/types/hook.type"), exports);
|
package/dist/errorx/errorx.d.ts
CHANGED
|
@@ -44,7 +44,7 @@ export declare class MultiErrorx extends Error {
|
|
|
44
44
|
* }
|
|
45
45
|
*/
|
|
46
46
|
export declare class ErrorAuthErrorResponse extends Errorx {
|
|
47
|
-
constructor(additionalOpts?: ErrorxAdditionalOpts);
|
|
47
|
+
constructor(message?: string, additionalOpts?: ErrorxAdditionalOpts, code?: string);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* General (https://docs.commercetools.com/api/errors#general)
|
package/dist/errorx/errorx.js
CHANGED
|
@@ -59,11 +59,11 @@ exports.MultiErrorx = MultiErrorx;
|
|
|
59
59
|
* }
|
|
60
60
|
*/
|
|
61
61
|
class ErrorAuthErrorResponse extends Errorx {
|
|
62
|
-
constructor(additionalOpts) {
|
|
62
|
+
constructor(message, additionalOpts, code) {
|
|
63
63
|
super({
|
|
64
|
-
code: '
|
|
64
|
+
code: code || 'invalid_token',
|
|
65
65
|
httpErrorStatus: 401,
|
|
66
|
-
message: 'Authentication error.',
|
|
66
|
+
message: message || 'Authentication error.',
|
|
67
67
|
...additionalOpts,
|
|
68
68
|
});
|
|
69
69
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { RequestContextData, RequestContextProvider, SessionAuthenticationHook } from './api';
|
|
1
|
+
import { JWTAuthenticationHook, Oauth2AuthenticationHook, RequestContextData, RequestContextProvider, SessionAuthenticationHook } from './api';
|
|
2
2
|
import { DefaultCommercetoolsAPI } from './commercetools/api/root-api';
|
|
3
|
+
import { DefaultAuthorizationService } from './commercetools/services/ct-authorization.service';
|
|
3
4
|
import { DefaultCartService } from './commercetools/services/ct-cart.service';
|
|
4
5
|
import { DefaultPaymentService } from './commercetools/services/ct-payment.service';
|
|
5
|
-
import { DefaultAuthorizationService } from './commercetools/services/ct-authorization.service';
|
|
6
6
|
import { Logger } from './logger';
|
|
7
7
|
export * from './api';
|
|
8
8
|
export * from './commercetools';
|
|
@@ -13,9 +13,11 @@ export declare const setupPaymentSDK: (opts: {
|
|
|
13
13
|
authUrl: string;
|
|
14
14
|
apiUrl: string;
|
|
15
15
|
sessionUrl: string;
|
|
16
|
+
jwksUrl: string;
|
|
16
17
|
clientId: string;
|
|
17
18
|
clientSecret: string;
|
|
18
19
|
projectKey: string;
|
|
20
|
+
jwtIssuer: string;
|
|
19
21
|
getContextFn: () => RequestContextData;
|
|
20
22
|
updateContextFn: (ctx: Partial<RequestContextData>) => void;
|
|
21
23
|
logger?: Logger | undefined;
|
|
@@ -26,4 +28,6 @@ export declare const setupPaymentSDK: (opts: {
|
|
|
26
28
|
ctAuthorizationService: DefaultAuthorizationService;
|
|
27
29
|
contextProvider: RequestContextProvider;
|
|
28
30
|
sessionAuthHookFn: SessionAuthenticationHook;
|
|
31
|
+
jwtAuthHookFn: JWTAuthenticationHook;
|
|
32
|
+
oauth2AuthHookFn: Oauth2AuthenticationHook;
|
|
29
33
|
};
|
package/dist/index.js
CHANGED
|
@@ -17,9 +17,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.setupPaymentSDK = void 0;
|
|
18
18
|
const api_1 = require("./api");
|
|
19
19
|
const root_api_1 = require("./commercetools/api/root-api");
|
|
20
|
+
const ct_authorization_service_1 = require("./commercetools/services/ct-authorization.service");
|
|
20
21
|
const ct_cart_service_1 = require("./commercetools/services/ct-cart.service");
|
|
21
22
|
const ct_payment_service_1 = require("./commercetools/services/ct-payment.service");
|
|
22
|
-
const ct_authorization_service_1 = require("./commercetools/services/ct-authorization.service");
|
|
23
23
|
const ct_session_service_1 = require("./commercetools/services/ct-session.service");
|
|
24
24
|
const base_decorator_1 = require("./fetch/decorators/base.decorator");
|
|
25
25
|
const monitoring_decorator_1 = require("./fetch/decorators/monitoring.decorator");
|
|
@@ -57,13 +57,35 @@ const setupPaymentSDK = (opts) => {
|
|
|
57
57
|
sessionUrl: opts.sessionUrl,
|
|
58
58
|
projectKey: opts.projectKey,
|
|
59
59
|
});
|
|
60
|
+
const oauth2Service = new security_1.DefaultOauth2Service();
|
|
61
|
+
const jwtService = new security_1.DefaultJWTService({
|
|
62
|
+
jwksUrl: opts.jwksUrl,
|
|
63
|
+
});
|
|
60
64
|
const sessionAuthenticationManager = new security_1.SessionAuthenticationManager({
|
|
61
65
|
sessionService,
|
|
62
66
|
});
|
|
67
|
+
const oauth2AuthenticationManager = new security_1.Oauth2AuthenticationManager({
|
|
68
|
+
oauth2Service,
|
|
69
|
+
clientId: opts.clientId,
|
|
70
|
+
clientSecret: opts.clientSecret,
|
|
71
|
+
authUrl: opts.authUrl,
|
|
72
|
+
});
|
|
73
|
+
const jwtAuthenticationManager = new security_1.JWTAuthenticationManager({
|
|
74
|
+
jwtService,
|
|
75
|
+
iss: opts.jwtIssuer,
|
|
76
|
+
});
|
|
63
77
|
const sessionAuthHookFn = new api_1.SessionAuthenticationHook({
|
|
64
78
|
authenticationManager: sessionAuthenticationManager,
|
|
65
79
|
contextProvider,
|
|
66
80
|
});
|
|
81
|
+
const jwtAuthHookFn = new api_1.JWTAuthenticationHook({
|
|
82
|
+
authenticationManager: jwtAuthenticationManager,
|
|
83
|
+
contextProvider,
|
|
84
|
+
});
|
|
85
|
+
const oauth2AuthHookFn = new api_1.Oauth2AuthenticationHook({
|
|
86
|
+
authenticationManager: oauth2AuthenticationManager,
|
|
87
|
+
contextProvider,
|
|
88
|
+
});
|
|
67
89
|
return {
|
|
68
90
|
ctAPI,
|
|
69
91
|
ctCartService,
|
|
@@ -71,6 +93,8 @@ const setupPaymentSDK = (opts) => {
|
|
|
71
93
|
ctAuthorizationService,
|
|
72
94
|
contextProvider,
|
|
73
95
|
sessionAuthHookFn,
|
|
96
|
+
jwtAuthHookFn,
|
|
97
|
+
oauth2AuthHookFn,
|
|
74
98
|
};
|
|
75
99
|
};
|
|
76
100
|
exports.setupPaymentSDK = setupPaymentSDK;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Authentication, HeaderPrincipal, SessionPrincipal } from './types/authn.type';
|
|
1
|
+
import { Authentication, HeaderPrincipal, JWTPrincipal, Oauth2Principal, SessionPrincipal } from './types/authn.type';
|
|
2
2
|
export declare class SessionAuthentication implements Authentication<SessionPrincipal, string> {
|
|
3
3
|
private principal;
|
|
4
4
|
private authorities;
|
|
@@ -22,3 +22,28 @@ export declare class HeaderBasedAuthentication implements Authentication<HeaderP
|
|
|
22
22
|
getPrincipal(): HeaderPrincipal;
|
|
23
23
|
isAuthenticated(): boolean;
|
|
24
24
|
}
|
|
25
|
+
export declare class Oauth2Authentication implements Authentication<Oauth2Principal, string> {
|
|
26
|
+
private principal;
|
|
27
|
+
private authorities;
|
|
28
|
+
private authenticated;
|
|
29
|
+
private accessToken;
|
|
30
|
+
constructor(accessToken: string, principal: Oauth2Principal);
|
|
31
|
+
hasPrincipal(): boolean;
|
|
32
|
+
getAuthorities(): string[];
|
|
33
|
+
hasCredentials(): boolean;
|
|
34
|
+
getPrincipal(): Oauth2Principal;
|
|
35
|
+
getCredentials(): string;
|
|
36
|
+
isAuthenticated(): boolean;
|
|
37
|
+
}
|
|
38
|
+
export declare class JWTAuthentication implements Authentication<JWTPrincipal, string> {
|
|
39
|
+
private principal;
|
|
40
|
+
private authenticated;
|
|
41
|
+
private jwt;
|
|
42
|
+
constructor(jwt: string, principal: JWTPrincipal);
|
|
43
|
+
hasPrincipal(): boolean;
|
|
44
|
+
getAuthorities(): string[];
|
|
45
|
+
hasCredentials(): boolean;
|
|
46
|
+
getPrincipal(): JWTPrincipal;
|
|
47
|
+
getCredentials(): string;
|
|
48
|
+
isAuthenticated(): boolean;
|
|
49
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HeaderBasedAuthentication = exports.SessionAuthentication = void 0;
|
|
3
|
+
exports.JWTAuthentication = exports.Oauth2Authentication = exports.HeaderBasedAuthentication = exports.SessionAuthentication = void 0;
|
|
4
4
|
class SessionAuthentication {
|
|
5
5
|
principal;
|
|
6
6
|
authorities;
|
|
@@ -58,3 +58,66 @@ class HeaderBasedAuthentication {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
exports.HeaderBasedAuthentication = HeaderBasedAuthentication;
|
|
61
|
+
class Oauth2Authentication {
|
|
62
|
+
principal;
|
|
63
|
+
authorities;
|
|
64
|
+
authenticated;
|
|
65
|
+
accessToken;
|
|
66
|
+
constructor(accessToken, principal) {
|
|
67
|
+
this.principal = principal;
|
|
68
|
+
this.authorities = principal.scope
|
|
69
|
+
.split(' ')
|
|
70
|
+
.map((scope) => scope.split(':')[0])
|
|
71
|
+
.filter((scope) => scope !== '');
|
|
72
|
+
this.authenticated = true;
|
|
73
|
+
this.accessToken = accessToken;
|
|
74
|
+
}
|
|
75
|
+
hasPrincipal() {
|
|
76
|
+
return this.getPrincipal() !== undefined;
|
|
77
|
+
}
|
|
78
|
+
getAuthorities() {
|
|
79
|
+
return this.authorities;
|
|
80
|
+
}
|
|
81
|
+
hasCredentials() {
|
|
82
|
+
return this.getCredentials() !== undefined;
|
|
83
|
+
}
|
|
84
|
+
getPrincipal() {
|
|
85
|
+
return this.principal;
|
|
86
|
+
}
|
|
87
|
+
getCredentials() {
|
|
88
|
+
return this.accessToken;
|
|
89
|
+
}
|
|
90
|
+
isAuthenticated() {
|
|
91
|
+
return this.authenticated;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.Oauth2Authentication = Oauth2Authentication;
|
|
95
|
+
class JWTAuthentication {
|
|
96
|
+
principal;
|
|
97
|
+
authenticated;
|
|
98
|
+
jwt;
|
|
99
|
+
constructor(jwt, principal) {
|
|
100
|
+
this.principal = principal;
|
|
101
|
+
this.authenticated = true;
|
|
102
|
+
this.jwt = jwt;
|
|
103
|
+
}
|
|
104
|
+
hasPrincipal() {
|
|
105
|
+
return this.getPrincipal() !== undefined;
|
|
106
|
+
}
|
|
107
|
+
getAuthorities() {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
hasCredentials() {
|
|
111
|
+
return this.getCredentials() !== undefined;
|
|
112
|
+
}
|
|
113
|
+
getPrincipal() {
|
|
114
|
+
return this.principal;
|
|
115
|
+
}
|
|
116
|
+
getCredentials() {
|
|
117
|
+
return this.jwt;
|
|
118
|
+
}
|
|
119
|
+
isAuthenticated() {
|
|
120
|
+
return this.authenticated;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
exports.JWTAuthentication = JWTAuthentication;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const validateBearerAuthorization: (authorization: string | undefined) => string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateBearerAuthorization = void 0;
|
|
4
|
+
const errorx_1 = require("../../errorx");
|
|
5
|
+
const validateBearerAuthorization = (authorization) => {
|
|
6
|
+
if (!authorization) {
|
|
7
|
+
throw new errorx_1.ErrorAuthErrorResponse('This endpoint requires the authorization header.', {
|
|
8
|
+
skipLog: true,
|
|
9
|
+
}, 'access_denied');
|
|
10
|
+
}
|
|
11
|
+
const authorizationParts = authorization.split(' ');
|
|
12
|
+
if (authorizationParts.length !== 2 || authorizationParts[0] !== 'Bearer') {
|
|
13
|
+
throw new errorx_1.ErrorAuthErrorResponse(`Authorization header must have the format 'Bearer <token>'`, {
|
|
14
|
+
skipLog: true,
|
|
15
|
+
}, 'invalid_request');
|
|
16
|
+
}
|
|
17
|
+
return authorizationParts[1];
|
|
18
|
+
};
|
|
19
|
+
exports.validateBearerAuthorization = validateBearerAuthorization;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { JWTService } from '../services/types/jwt.type';
|
|
2
|
+
import { HeaderBasedAuthentication, JWTAuthentication } from './authns';
|
|
3
|
+
import { AuthenticationManager } from './types/authn.type';
|
|
4
|
+
export declare class JWTAuthenticationManager implements AuthenticationManager {
|
|
5
|
+
private jwtService;
|
|
6
|
+
private iss;
|
|
7
|
+
constructor(opts: {
|
|
8
|
+
jwtService: JWTService;
|
|
9
|
+
iss: string;
|
|
10
|
+
});
|
|
11
|
+
authenticate(authentication: HeaderBasedAuthentication): Promise<JWTAuthentication>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.JWTAuthenticationManager = void 0;
|
|
4
|
+
const errorx_1 = require("../../errorx");
|
|
5
|
+
const authns_1 = require("./authns");
|
|
6
|
+
const bearer_utils_1 = require("./bearer-utils");
|
|
7
|
+
class JWTAuthenticationManager {
|
|
8
|
+
jwtService;
|
|
9
|
+
iss;
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.jwtService = opts.jwtService;
|
|
12
|
+
this.iss = opts.iss;
|
|
13
|
+
}
|
|
14
|
+
async authenticate(authentication) {
|
|
15
|
+
const principal = authentication.getPrincipal();
|
|
16
|
+
const token = (0, bearer_utils_1.validateBearerAuthorization)(principal.authHeader);
|
|
17
|
+
const decodedToken = (await this.jwtService.verify({
|
|
18
|
+
token,
|
|
19
|
+
}));
|
|
20
|
+
if (decodedToken.iss !== this.iss) {
|
|
21
|
+
throw new errorx_1.ErrorAuthErrorResponse('Issuer in the token does not match the expected issuer', {
|
|
22
|
+
privateFields: {
|
|
23
|
+
expectedIssuer: this.iss,
|
|
24
|
+
actualIssuer: decodedToken['iss'],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
return new authns_1.JWTAuthentication(token, {
|
|
29
|
+
mcCustomerId: decodedToken['sub'],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
exports.JWTAuthenticationManager = JWTAuthenticationManager;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Oauth2Service } from '../services/types/oauth2.type';
|
|
2
|
+
import { HeaderBasedAuthentication, Oauth2Authentication } from './authns';
|
|
3
|
+
import { AuthenticationManager } from './types/authn.type';
|
|
4
|
+
export declare class Oauth2AuthenticationManager implements AuthenticationManager {
|
|
5
|
+
private oauth2Service;
|
|
6
|
+
private clientId;
|
|
7
|
+
private clientSecret;
|
|
8
|
+
private authUrl;
|
|
9
|
+
constructor(opts: {
|
|
10
|
+
oauth2Service: Oauth2Service;
|
|
11
|
+
clientId: string;
|
|
12
|
+
clientSecret: string;
|
|
13
|
+
authUrl: string;
|
|
14
|
+
});
|
|
15
|
+
authenticate(authentication: HeaderBasedAuthentication): Promise<Oauth2Authentication>;
|
|
16
|
+
private searchPermission;
|
|
17
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Oauth2AuthenticationManager = void 0;
|
|
4
|
+
const errorx_1 = require("../../errorx");
|
|
5
|
+
const authns_1 = require("./authns");
|
|
6
|
+
const bearer_utils_1 = require("./bearer-utils");
|
|
7
|
+
class Oauth2AuthenticationManager {
|
|
8
|
+
oauth2Service;
|
|
9
|
+
clientId;
|
|
10
|
+
clientSecret;
|
|
11
|
+
authUrl;
|
|
12
|
+
constructor(opts) {
|
|
13
|
+
this.oauth2Service = opts.oauth2Service;
|
|
14
|
+
this.clientId = opts.clientId;
|
|
15
|
+
this.clientSecret = opts.clientSecret;
|
|
16
|
+
this.authUrl = opts.authUrl;
|
|
17
|
+
}
|
|
18
|
+
async authenticate(authentication) {
|
|
19
|
+
const principal = authentication.getPrincipal();
|
|
20
|
+
const authorizationHeader = principal.authHeader;
|
|
21
|
+
const token = (0, bearer_utils_1.validateBearerAuthorization)(authorizationHeader);
|
|
22
|
+
const tokenIntrospectionResponseData = await this.oauth2Service.introspectToken({
|
|
23
|
+
url: `${this.authUrl}/oauth/introspect`,
|
|
24
|
+
clientId: this.clientId,
|
|
25
|
+
clientSecret: this.clientSecret,
|
|
26
|
+
token,
|
|
27
|
+
});
|
|
28
|
+
if (!tokenIntrospectionResponseData.active) {
|
|
29
|
+
throw new errorx_1.ErrorAuthErrorResponse('invalid_token', {
|
|
30
|
+
skipLog: true,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
const scopes = tokenIntrospectionResponseData.scope?.split(' ') ?? null;
|
|
34
|
+
if (!scopes) {
|
|
35
|
+
throw new errorx_1.ErrorAuthErrorResponse('Token has no scopes.', {
|
|
36
|
+
skipLog: true,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Search for customer_id:<customer> scope
|
|
40
|
+
const customerPermission = this.searchPermission(scopes, 'customer_id');
|
|
41
|
+
// Search for anonymous_id:<anonymous> scope
|
|
42
|
+
const anonymousPermission = this.searchPermission(scopes, 'anonymous_id');
|
|
43
|
+
return new authns_1.Oauth2Authentication(token, {
|
|
44
|
+
scope: tokenIntrospectionResponseData.scope,
|
|
45
|
+
clientId: tokenIntrospectionResponseData.client_id,
|
|
46
|
+
customerId: customerPermission?.principal,
|
|
47
|
+
anonymousId: anonymousPermission?.principal,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
searchPermission(scopes, ...permissions) {
|
|
51
|
+
for (const permission of permissions) {
|
|
52
|
+
// Search for customer_id:<customer> scope
|
|
53
|
+
const permissionIndex = scopes.findIndex((element) => element.startsWith(`${permission}`));
|
|
54
|
+
if (permissionIndex >= 0) {
|
|
55
|
+
const splitPermission = scopes[permissionIndex].split(':');
|
|
56
|
+
return {
|
|
57
|
+
permission: splitPermission[0],
|
|
58
|
+
principal: splitPermission[1],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.Oauth2AuthenticationManager = Oauth2AuthenticationManager;
|
|
@@ -9,10 +9,19 @@ export interface Authentication<Principal = unknown, Credentials = unknown> {
|
|
|
9
9
|
getCredentials(): Credentials;
|
|
10
10
|
isAuthenticated(): boolean;
|
|
11
11
|
}
|
|
12
|
+
export type HeaderPrincipal = {
|
|
13
|
+
authHeader: string;
|
|
14
|
+
};
|
|
12
15
|
export type SessionPrincipal = {
|
|
13
16
|
cartId: string;
|
|
14
17
|
allowedPaymentMethods: string[];
|
|
15
18
|
};
|
|
16
|
-
export type
|
|
17
|
-
|
|
19
|
+
export type Oauth2Principal = {
|
|
20
|
+
clientId: string;
|
|
21
|
+
scope: string;
|
|
22
|
+
customerId?: string;
|
|
23
|
+
anonymousId?: string;
|
|
24
|
+
};
|
|
25
|
+
export type JWTPrincipal = {
|
|
26
|
+
mcCustomerId?: string;
|
|
18
27
|
};
|
package/dist/security/index.d.ts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
-
export * from './authn/types/authn.type';
|
|
2
1
|
export * from './authn/authns';
|
|
2
|
+
export * from './authn/jwt-authn-manager';
|
|
3
|
+
export * from './authn/oauth2-authn-manager';
|
|
3
4
|
export * from './authn/session-authn-manager';
|
|
5
|
+
export * from './authn/types/authn.type';
|
|
6
|
+
export * from './services/jwt.service';
|
|
7
|
+
export * from './services/oauth2.service';
|
package/dist/security/index.js
CHANGED
|
@@ -14,6 +14,10 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
__exportStar(require("./authn/types/authn.type"), exports);
|
|
18
17
|
__exportStar(require("./authn/authns"), exports);
|
|
18
|
+
__exportStar(require("./authn/jwt-authn-manager"), exports);
|
|
19
|
+
__exportStar(require("./authn/oauth2-authn-manager"), exports);
|
|
19
20
|
__exportStar(require("./authn/session-authn-manager"), exports);
|
|
21
|
+
__exportStar(require("./authn/types/authn.type"), exports);
|
|
22
|
+
__exportStar(require("./services/jwt.service"), exports);
|
|
23
|
+
__exportStar(require("./services/oauth2.service"), exports);
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.DefaultJWTService = void 0;
|
|
7
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
const jwks_rsa_1 = __importDefault(require("jwks-rsa"));
|
|
9
|
+
const errorx_1 = require("../../errorx");
|
|
10
|
+
class DefaultJWTService {
|
|
11
|
+
client;
|
|
12
|
+
constructor(opts) {
|
|
13
|
+
this.client = (0, jwks_rsa_1.default)({
|
|
14
|
+
jwksUri: opts.jwksUrl,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async verify(opts) {
|
|
18
|
+
const getKey = (header, callback) => {
|
|
19
|
+
this.client.getSigningKey(header.kid, function (err, key) {
|
|
20
|
+
if (err) {
|
|
21
|
+
return callback(err);
|
|
22
|
+
}
|
|
23
|
+
const signingKey = key.getPublicKey();
|
|
24
|
+
callback(null, signingKey);
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
if (!opts.token) {
|
|
29
|
+
throw new errorx_1.ErrorAuthErrorResponse('Token is missing');
|
|
30
|
+
}
|
|
31
|
+
jsonwebtoken_1.default.verify(opts.token, getKey, {}, function (err, decoded) {
|
|
32
|
+
if (err) {
|
|
33
|
+
return reject(new errorx_1.ErrorAuthErrorResponse(err.message, { privateMessage: err.message, cause: err }));
|
|
34
|
+
}
|
|
35
|
+
return resolve(decoded);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.DefaultJWTService = DefaultJWTService;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Oauth2Service, TokenInfo } from './types/oauth2.type';
|
|
2
|
+
export declare class DefaultOauth2Service implements Oauth2Service {
|
|
3
|
+
introspectToken(opts: {
|
|
4
|
+
url: string;
|
|
5
|
+
clientId: string;
|
|
6
|
+
clientSecret: string;
|
|
7
|
+
token: string;
|
|
8
|
+
}): Promise<TokenInfo>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefaultOauth2Service = void 0;
|
|
4
|
+
const errorx_1 = require("../../errorx");
|
|
5
|
+
class DefaultOauth2Service {
|
|
6
|
+
async introspectToken(opts) {
|
|
7
|
+
const urlencoded = new URLSearchParams();
|
|
8
|
+
urlencoded.append('token', opts.token);
|
|
9
|
+
const tokenResponse = await fetch(opts.url, {
|
|
10
|
+
method: 'POST',
|
|
11
|
+
headers: {
|
|
12
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
13
|
+
Authorization: `Basic ${btoa(opts.clientId + ':' + opts.clientSecret)}`,
|
|
14
|
+
},
|
|
15
|
+
body: urlencoded,
|
|
16
|
+
});
|
|
17
|
+
if (tokenResponse.status > 299) {
|
|
18
|
+
if (tokenResponse.status === 401) {
|
|
19
|
+
const tokenResponseJson = (await tokenResponse.json());
|
|
20
|
+
throw new errorx_1.ErrorAuthErrorResponse(tokenResponseJson.message, {
|
|
21
|
+
privateFields: {
|
|
22
|
+
clientId: opts.clientId,
|
|
23
|
+
status: tokenResponse.status,
|
|
24
|
+
},
|
|
25
|
+
skipLog: true,
|
|
26
|
+
}, tokenResponseJson.error);
|
|
27
|
+
}
|
|
28
|
+
throw new errorx_1.ErrorGeneral('Failed to authorize request.', {
|
|
29
|
+
privateMessage: 'some error happened while requesting token from coco',
|
|
30
|
+
privateFields: {
|
|
31
|
+
clientId: opts.clientId,
|
|
32
|
+
status: tokenResponse.status,
|
|
33
|
+
},
|
|
34
|
+
skipLog: true,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return (await tokenResponse.json());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.DefaultOauth2Service = DefaultOauth2Service;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type TokenInfo = {
|
|
2
|
+
active: boolean;
|
|
3
|
+
scope: string;
|
|
4
|
+
exp: number;
|
|
5
|
+
client_id: string;
|
|
6
|
+
};
|
|
7
|
+
export interface Oauth2Service {
|
|
8
|
+
introspectToken(opts: {
|
|
9
|
+
url: string;
|
|
10
|
+
clientId: string;
|
|
11
|
+
clientSecret: string;
|
|
12
|
+
token: string;
|
|
13
|
+
}): Promise<TokenInfo>;
|
|
14
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools/connect-payments-sdk",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "Payment SDK for commercetools payment connectors",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"license": "ISC",
|
|
17
17
|
"dependencies": {
|
|
18
18
|
"@commercetools/platform-sdk": "7.2.0-alpha.4",
|
|
19
|
-
"@commercetools/sdk-client-v2": "2.3.0"
|
|
19
|
+
"@commercetools/sdk-client-v2": "2.3.0",
|
|
20
|
+
"jsonwebtoken": "9.0.2",
|
|
21
|
+
"jwks-rsa": "3.1.0"
|
|
20
22
|
}
|
|
21
23
|
}
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [ main ]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
ci:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- name: Checkout Repo
|
|
12
|
-
uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- name: Install Node.js
|
|
15
|
-
uses: actions/setup-node@v3
|
|
16
|
-
with:
|
|
17
|
-
node-version: 20
|
|
18
|
-
|
|
19
|
-
- name: Install dependencies
|
|
20
|
-
uses: pnpm/action-setup@v2
|
|
21
|
-
with:
|
|
22
|
-
version: 8
|
|
23
|
-
run_install: |
|
|
24
|
-
- recursive: true
|
|
25
|
-
args: [--frozen-lockfile, --strict-peer-dependencies]
|
|
26
|
-
|
|
27
|
-
- name: Build
|
|
28
|
-
run: pnpm run build
|
|
29
|
-
|
|
30
|
-
- name: Static code analysis
|
|
31
|
-
run: pnpm run lint
|
|
32
|
-
|
|
33
|
-
- name: Tests
|
|
34
|
-
run: pnpm run test
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ main ]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
publish-gpr:
|
|
9
|
-
runs-on: ubuntu-latest
|
|
10
|
-
steps:
|
|
11
|
-
- name: Checkout Repo
|
|
12
|
-
uses: actions/checkout@v4
|
|
13
|
-
|
|
14
|
-
- name: Install Node.js
|
|
15
|
-
uses: actions/setup-node@v3
|
|
16
|
-
with:
|
|
17
|
-
node-version: 20
|
|
18
|
-
|
|
19
|
-
- name: Install dependencies
|
|
20
|
-
uses: pnpm/action-setup@v2
|
|
21
|
-
with:
|
|
22
|
-
version: 8
|
|
23
|
-
run_install: |
|
|
24
|
-
- recursive: true
|
|
25
|
-
args: [--frozen-lockfile, --strict-peer-dependencies]
|
|
26
|
-
|
|
27
|
-
- name: Static code analysis
|
|
28
|
-
run: pnpm run lint
|
|
29
|
-
|
|
30
|
-
- name: Tests
|
|
31
|
-
run: pnpm run test
|
|
32
|
-
|
|
33
|
-
- name: Create Release Pull Request or Publish to npm
|
|
34
|
-
id: changesets
|
|
35
|
-
uses: changesets/action@v1
|
|
36
|
-
with:
|
|
37
|
-
# This expects you to have a script called release which does a build for your packages and calls changeset publish
|
|
38
|
-
publish: pnpm run release
|
|
39
|
-
env:
|
|
40
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
42
|
-
|
|
43
|
-
- name: Create release
|
|
44
|
-
if: steps.changesets.outputs.published == 'true'
|
|
45
|
-
# You can do something when a publish happens.
|
|
46
|
-
run: VERSION=$(jq '.version' package.json -r);gh release create "$VERSION" --title "$VERSION [@commercetools/connect-payments-sdk]" --notes 'Check CHANGELOG.md file.'
|