@commercetools/checkout-payments-processor-sdk 0.0.6
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 +15 -0
- package/README.md +42 -0
- package/biome.json +38 -0
- package/package.json +48 -0
- package/src/api/context/request-context.helper.test.ts +98 -0
- package/src/api/context/request-context.helper.ts +89 -0
- package/src/api/context/request-context.provider.ts +27 -0
- package/src/api/context/types/request-context.type.ts +18 -0
- package/src/api/handlers/payment-components.handler.test.ts +378 -0
- package/src/api/handlers/payment-components.handler.ts +80 -0
- package/src/api/handlers/payment-intents.handler.test.ts +475 -0
- package/src/api/handlers/payment-intents.handler.ts +169 -0
- package/src/api/handlers/status.handler.test.ts +551 -0
- package/src/api/handlers/status.handler.ts +216 -0
- package/src/api/handlers/transaction.handler.ts +86 -0
- package/src/api/handlers/types/handler.type.ts +49 -0
- package/src/api/hooks/authorize.hook.test.ts +62 -0
- package/src/api/hooks/authorize.hook.ts +51 -0
- package/src/api/hooks/jwt-auth.hook.test.ts +54 -0
- package/src/api/hooks/jwt-auth.hook.ts +56 -0
- package/src/api/hooks/oauth2-auth.hook.test.ts +173 -0
- package/src/api/hooks/oauth2-auth.hook.ts +46 -0
- package/src/api/hooks/session-header-auth.hook.ts +47 -0
- package/src/api/hooks/session-query-param-auth.hook.ts +46 -0
- package/src/api/hooks/types/hook.type.ts +12 -0
- package/src/api/index.ts +11 -0
- package/src/api/types.ts +3 -0
- package/src/commercetools/api/base-api.ts +28 -0
- package/src/commercetools/api/cart-api.test.ts +95 -0
- package/src/commercetools/api/cart-api.ts +55 -0
- package/src/commercetools/api/custom-type-api.ts +39 -0
- package/src/commercetools/api/order-api.ts +22 -0
- package/src/commercetools/api/payment-api.ts +64 -0
- package/src/commercetools/api/payment-method-api.ts +118 -0
- package/src/commercetools/api/root-api.ts +109 -0
- package/src/commercetools/errors/ct-api.error.ts +27 -0
- package/src/commercetools/helpers/currency.converter.test.ts +121 -0
- package/src/commercetools/helpers/currency.converter.test_data.json +2379 -0
- package/src/commercetools/helpers/currency.converter.ts +102 -0
- package/src/commercetools/helpers/taxrate.converter.test.ts +48 -0
- package/src/commercetools/helpers/taxrate.converter.ts +39 -0
- package/src/commercetools/index.ts +22 -0
- package/src/commercetools/services/ct-cart.service.test.ts +1616 -0
- package/src/commercetools/services/ct-cart.service.ts +316 -0
- package/src/commercetools/services/ct-custom-type.service.ts +62 -0
- package/src/commercetools/services/ct-order.service.test.ts +136 -0
- package/src/commercetools/services/ct-order.service.ts +47 -0
- package/src/commercetools/services/ct-payment-method.service.test.ts +878 -0
- package/src/commercetools/services/ct-payment-method.service.ts +223 -0
- package/src/commercetools/services/ct-payment.service.test.ts +1123 -0
- package/src/commercetools/services/ct-payment.service.ts +574 -0
- package/src/commercetools/types/api.type.ts +162 -0
- package/src/commercetools/types/cart.type.ts +83 -0
- package/src/commercetools/types/custom-type.type.ts +21 -0
- package/src/commercetools/types/order.type.ts +19 -0
- package/src/commercetools/types/payment-method.type.ts +130 -0
- package/src/commercetools/types/payment.type.ts +74 -0
- package/src/commercetools/types/predefined-custom-types.type.ts +240 -0
- package/src/commercetools/types.ts +7 -0
- package/src/errorx/errorx.ts +625 -0
- package/src/errorx/index.ts +1 -0
- package/src/errorx/types.ts +5 -0
- package/src/fetch/decorators/base.decorator.ts +13 -0
- package/src/fetch/decorators/monitoring.decorator.ts +41 -0
- package/src/fetch/fetch.test.ts +57 -0
- package/src/fetch/index.ts +3 -0
- package/src/fetch/types/fetch.type.ts +11 -0
- package/src/fetch/types.ts +1 -0
- package/src/index.ts +15 -0
- package/src/logger/commercetools-logger.ts +69 -0
- package/src/logger/index.ts +1 -0
- package/src/logger/types/logger.type.ts +6 -0
- package/src/logger/types.ts +1 -0
- package/src/mocks/auth.mock.ts +6 -0
- package/src/mocks/cart.mock.ts +239 -0
- package/src/mocks/ct-api-error.mock.ts +23 -0
- package/src/mocks/index.ts +4 -0
- package/src/mocks/payment.mock.ts +35 -0
- package/src/payment-processor.ts +317 -0
- package/src/security/authn/authns.ts +219 -0
- package/src/security/authn/bearer-utils.test.ts +35 -0
- package/src/security/authn/bearer-utils.ts +28 -0
- package/src/security/authn/jwt-authn-manager.ts +69 -0
- package/src/security/authn/oauth2-authn-manager.ts +105 -0
- package/src/security/authn/session-header-authn-manager.ts +58 -0
- package/src/security/authn/session-query-param-authn-manager.ts +53 -0
- package/src/security/authn/types/authn.type.ts +50 -0
- package/src/security/authz/authorization-manager.ts +39 -0
- package/src/security/authz/types/authz.type.ts +13 -0
- package/src/security/index.ts +13 -0
- package/src/security/services/authorization.service.ts +54 -0
- package/src/security/services/jwt.service.test.ts +27 -0
- package/src/security/services/jwt.service.ts +45 -0
- package/src/security/services/oauth2.service.ts +60 -0
- package/src/security/services/session.service.ts +141 -0
- package/src/security/services/types/authorization.type.ts +10 -0
- package/src/security/services/types/jwt.type.ts +3 -0
- package/src/security/services/types/oauth2.type.ts +15 -0
- package/src/security/services/types/session.type.ts +38 -0
- package/src/security/types.ts +6 -0
- package/tsconfig.json +28 -0
- package/tsconfig.prod.json +9 -0
- package/typedoc.json +6 -0
- package/vitest.config.ts +15 -0
- package/wiki/getting-started.md +13 -0
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AuthorityAuthorizationHook,
|
|
3
|
+
JWTAuthenticationHook,
|
|
4
|
+
Oauth2AuthenticationHook,
|
|
5
|
+
RequestContextProvider,
|
|
6
|
+
SessionHeaderAuthenticationHook,
|
|
7
|
+
SessionQueryParamAuthenticationHook,
|
|
8
|
+
} from '@api';
|
|
9
|
+
import type { RequestContextData } from '@api-types';
|
|
10
|
+
import { CommercetoolsLogger } from '@logger';
|
|
11
|
+
import type { Logger } from '@logger-types';
|
|
12
|
+
import {
|
|
13
|
+
AuthorityAuthorizationManager,
|
|
14
|
+
DefaultAuthorizationService,
|
|
15
|
+
DefaultJWTService,
|
|
16
|
+
DefaultOauth2Service,
|
|
17
|
+
DefaultSessionService,
|
|
18
|
+
JWTAuthenticationManager,
|
|
19
|
+
Oauth2AuthenticationManager,
|
|
20
|
+
SessionHeaderAuthenticationManager,
|
|
21
|
+
SessionQueryParamAuthenticationManager,
|
|
22
|
+
} from '@security';
|
|
23
|
+
import type {
|
|
24
|
+
AuthorizationService,
|
|
25
|
+
JWTService,
|
|
26
|
+
Oauth2Service,
|
|
27
|
+
SessionService,
|
|
28
|
+
} from '@security-types';
|
|
29
|
+
import { DefaultOrderService } from '@/commercetools/services/ct-order.service.js';
|
|
30
|
+
import { DefaultPaymentService } from '@/commercetools/services/ct-payment.service.js';
|
|
31
|
+
import { DefaultPaymentMethodService } from '@/commercetools/services/ct-payment-method.service.js';
|
|
32
|
+
import type { CartService } from '@/commercetools/types/cart.type.js';
|
|
33
|
+
import type { OrderService } from '@/commercetools/types/order.type.js';
|
|
34
|
+
import type { PaymentService } from '@/commercetools/types/payment.type.js';
|
|
35
|
+
import type { PaymentMethodService } from '@/commercetools/types/payment-method.type.js';
|
|
36
|
+
import type { CommercetoolsAPI } from '@/commercetools/types.js';
|
|
37
|
+
import { DefaultCommercetoolsAPI } from './commercetools/api/root-api.js';
|
|
38
|
+
import { DefaultCartService } from './commercetools/services/ct-cart.service.js';
|
|
39
|
+
import { DefaultCustomTypeService } from './commercetools/services/ct-custom-type.service.js';
|
|
40
|
+
import type { CustomTypeService } from './commercetools/types/custom-type.type.js';
|
|
41
|
+
import { BasicFetcher } from './fetch/decorators/base.decorator.js';
|
|
42
|
+
import { MonitoringFetcherDecorator } from './fetch/decorators/monitoring.decorator.js';
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Checkout Payments Processor SDK
|
|
46
|
+
* @description This class is used to process payments for checkout.
|
|
47
|
+
* @param opts - The options for the processor.
|
|
48
|
+
* @param opts.authUrl - The URL for the authentication service.
|
|
49
|
+
* @param opts.apiUrl - The URL for the API service.
|
|
50
|
+
* @param opts.sessionUrl - The URL for the session service.
|
|
51
|
+
* @param opts.jwksUrl - The URL for the JWT service.
|
|
52
|
+
* @param opts.clientId - The client ID for the authentication service.
|
|
53
|
+
* @param opts.clientSecret - The client secret for the authentication service.
|
|
54
|
+
* @param opts.projectKey - The project key for the API service.
|
|
55
|
+
* @param opts.jwtIssuer - The issuer for the JWT service.
|
|
56
|
+
* @param opts.getContextFn - The function to get the context.
|
|
57
|
+
* @param opts.updateContextFn - The function to update the context.
|
|
58
|
+
* @param opts.logger - The logger for the processor.
|
|
59
|
+
* @returns The CheckoutPaymentsProcessor instance.
|
|
60
|
+
*/
|
|
61
|
+
export class CheckoutPaymentsProcessor {
|
|
62
|
+
private readonly authUrl: string;
|
|
63
|
+
private readonly apiUrl: string;
|
|
64
|
+
private readonly sessionUrl: string;
|
|
65
|
+
private readonly jwksUrl: string;
|
|
66
|
+
private readonly clientId: string;
|
|
67
|
+
private readonly clientSecret: string;
|
|
68
|
+
private readonly projectKey: string;
|
|
69
|
+
private readonly jwtIssuer: string;
|
|
70
|
+
private readonly getContextFn: () => RequestContextData;
|
|
71
|
+
private readonly updateContextFn: (ctx: Partial<RequestContextData>) => void;
|
|
72
|
+
private readonly logger: Logger;
|
|
73
|
+
private readonly ctAPI: CommercetoolsAPI;
|
|
74
|
+
private readonly authorizationService: AuthorizationService;
|
|
75
|
+
private readonly sessionService: SessionService;
|
|
76
|
+
private readonly cartService: CartService;
|
|
77
|
+
private readonly orderService: OrderService;
|
|
78
|
+
private readonly paymentService: PaymentService;
|
|
79
|
+
private readonly paymentMethodService: PaymentMethodService;
|
|
80
|
+
private readonly customTypeService: CustomTypeService;
|
|
81
|
+
private readonly oauth2Service: Oauth2Service;
|
|
82
|
+
private readonly jwtService: JWTService;
|
|
83
|
+
private readonly sessionHeaderAuthenticationManager: SessionHeaderAuthenticationManager;
|
|
84
|
+
private readonly sessionQueryParamAuthenticationManager: SessionQueryParamAuthenticationManager;
|
|
85
|
+
private readonly jwtAuthenticationManager: JWTAuthenticationManager;
|
|
86
|
+
private readonly oauth2AuthenticationManager: Oauth2AuthenticationManager;
|
|
87
|
+
private readonly authorityAuthorizationManager: AuthorityAuthorizationManager;
|
|
88
|
+
private readonly sessionHeaderAuthHookFn: SessionHeaderAuthenticationHook;
|
|
89
|
+
private readonly sessionQueryParamAuthHookFn: SessionQueryParamAuthenticationHook;
|
|
90
|
+
private readonly jwtAuthHookFn: JWTAuthenticationHook;
|
|
91
|
+
private readonly oauth2AuthHookFn: Oauth2AuthenticationHook;
|
|
92
|
+
private readonly authorityAuthorizationHookFn: AuthorityAuthorizationHook;
|
|
93
|
+
|
|
94
|
+
constructor(opts: {
|
|
95
|
+
authUrl: string;
|
|
96
|
+
apiUrl: string;
|
|
97
|
+
sessionUrl: string;
|
|
98
|
+
jwksUrl: string;
|
|
99
|
+
clientId: string;
|
|
100
|
+
clientSecret: string;
|
|
101
|
+
projectKey: string;
|
|
102
|
+
jwtIssuer: string;
|
|
103
|
+
getContextFn: () => RequestContextData;
|
|
104
|
+
updateContextFn: (ctx: Partial<RequestContextData>) => void;
|
|
105
|
+
logger?: Logger;
|
|
106
|
+
}) {
|
|
107
|
+
this.authUrl = opts.authUrl;
|
|
108
|
+
this.apiUrl = opts.apiUrl;
|
|
109
|
+
this.sessionUrl = opts.sessionUrl;
|
|
110
|
+
this.jwksUrl = opts.jwksUrl;
|
|
111
|
+
this.clientId = opts.clientId;
|
|
112
|
+
this.clientSecret = opts.clientSecret;
|
|
113
|
+
this.projectKey = opts.projectKey;
|
|
114
|
+
this.jwtIssuer = opts.jwtIssuer;
|
|
115
|
+
this.getContextFn = opts.getContextFn;
|
|
116
|
+
this.updateContextFn = opts.updateContextFn;
|
|
117
|
+
|
|
118
|
+
const contextProvider = new RequestContextProvider({
|
|
119
|
+
getContextFn: this.getContextFn,
|
|
120
|
+
updateContextFn: this.updateContextFn,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
this.logger =
|
|
124
|
+
opts.logger ||
|
|
125
|
+
new CommercetoolsLogger({ contextProvider, projectKey: opts.projectKey });
|
|
126
|
+
|
|
127
|
+
const fetcher = new MonitoringFetcherDecorator(
|
|
128
|
+
new BasicFetcher(),
|
|
129
|
+
contextProvider,
|
|
130
|
+
);
|
|
131
|
+
const decoratedFetch = fetcher.run.bind(fetcher);
|
|
132
|
+
|
|
133
|
+
this.ctAPI = new DefaultCommercetoolsAPI({
|
|
134
|
+
apiUrl: this.apiUrl,
|
|
135
|
+
authUrl: this.authUrl,
|
|
136
|
+
clientId: this.clientId,
|
|
137
|
+
clientSecret: this.clientSecret,
|
|
138
|
+
projectKey: this.projectKey,
|
|
139
|
+
contextProvider,
|
|
140
|
+
logger: this.logger,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
this.authorizationService = new DefaultAuthorizationService({
|
|
144
|
+
authUrl: this.authUrl,
|
|
145
|
+
clientId: this.clientId,
|
|
146
|
+
clientSecret: this.clientSecret,
|
|
147
|
+
fetch: decoratedFetch,
|
|
148
|
+
logger: this.logger,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
this.sessionService = new DefaultSessionService({
|
|
152
|
+
authorizationService: this.authorizationService,
|
|
153
|
+
sessionUrl: this.sessionUrl,
|
|
154
|
+
projectKey: this.projectKey,
|
|
155
|
+
logger: this.logger,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
this.cartService = new DefaultCartService({
|
|
159
|
+
ctAPI: this.ctAPI,
|
|
160
|
+
logger: this.logger,
|
|
161
|
+
contextProvider,
|
|
162
|
+
});
|
|
163
|
+
this.orderService = new DefaultOrderService({
|
|
164
|
+
ctAPI: this.ctAPI,
|
|
165
|
+
logger: this.logger,
|
|
166
|
+
});
|
|
167
|
+
this.paymentService = new DefaultPaymentService({
|
|
168
|
+
ctAPI: this.ctAPI,
|
|
169
|
+
logger: this.logger,
|
|
170
|
+
});
|
|
171
|
+
this.paymentMethodService = new DefaultPaymentMethodService({
|
|
172
|
+
ctAPI: this.ctAPI,
|
|
173
|
+
logger: this.logger,
|
|
174
|
+
});
|
|
175
|
+
this.customTypeService = new DefaultCustomTypeService({
|
|
176
|
+
ctAPI: this.ctAPI,
|
|
177
|
+
logger: this.logger,
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
this.oauth2Service = new DefaultOauth2Service({ logger: this.logger });
|
|
181
|
+
|
|
182
|
+
this.jwtService = new DefaultJWTService({
|
|
183
|
+
jwksUrl: this.jwksUrl,
|
|
184
|
+
logger: this.logger,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
this.sessionHeaderAuthenticationManager =
|
|
188
|
+
new SessionHeaderAuthenticationManager({
|
|
189
|
+
sessionService: this.sessionService,
|
|
190
|
+
logger: this.logger,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
this.sessionQueryParamAuthenticationManager =
|
|
194
|
+
new SessionQueryParamAuthenticationManager({
|
|
195
|
+
sessionService: this.sessionService,
|
|
196
|
+
logger: this.logger,
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
this.oauth2AuthenticationManager = new Oauth2AuthenticationManager({
|
|
200
|
+
oauth2Service: this.oauth2Service,
|
|
201
|
+
clientId: this.clientId,
|
|
202
|
+
clientSecret: this.clientSecret,
|
|
203
|
+
authUrl: this.authUrl,
|
|
204
|
+
logger: this.logger,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
this.authorityAuthorizationManager = new AuthorityAuthorizationManager({
|
|
208
|
+
logger: this.logger,
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
this.jwtAuthenticationManager = new JWTAuthenticationManager({
|
|
212
|
+
jwtService: this.jwtService,
|
|
213
|
+
iss: this.jwtIssuer,
|
|
214
|
+
projectKey: this.projectKey,
|
|
215
|
+
logger: this.logger,
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
this.sessionHeaderAuthHookFn = new SessionHeaderAuthenticationHook({
|
|
219
|
+
authenticationManager: this.sessionHeaderAuthenticationManager,
|
|
220
|
+
contextProvider,
|
|
221
|
+
logger: this.logger,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
this.sessionQueryParamAuthHookFn = new SessionQueryParamAuthenticationHook({
|
|
225
|
+
authenticationManager: this.sessionQueryParamAuthenticationManager,
|
|
226
|
+
contextProvider,
|
|
227
|
+
logger: this.logger,
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
this.jwtAuthHookFn = new JWTAuthenticationHook({
|
|
231
|
+
authenticationManager: this.jwtAuthenticationManager,
|
|
232
|
+
contextProvider,
|
|
233
|
+
logger: this.logger,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
this.oauth2AuthHookFn = new Oauth2AuthenticationHook({
|
|
237
|
+
authenticationManager: this.oauth2AuthenticationManager,
|
|
238
|
+
contextProvider,
|
|
239
|
+
logger: this.logger,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
this.authorityAuthorizationHookFn = new AuthorityAuthorizationHook({
|
|
243
|
+
authorizationManager: this.authorityAuthorizationManager,
|
|
244
|
+
contextProvider,
|
|
245
|
+
logger: this.logger,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
this.customTypeService = new DefaultCustomTypeService({
|
|
249
|
+
ctAPI: this.ctAPI,
|
|
250
|
+
logger: this.logger,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
public getLogger(): Logger {
|
|
255
|
+
return this.logger;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
public getCtApi(): CommercetoolsAPI {
|
|
259
|
+
return this.ctAPI;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
public getAuthorizationService(): AuthorizationService {
|
|
263
|
+
return this.authorizationService;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
public getSessionService(): SessionService {
|
|
267
|
+
return this.sessionService;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public getCartService(): CartService {
|
|
271
|
+
return this.cartService;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
public getOrderService(): OrderService {
|
|
275
|
+
return this.orderService;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
public getPaymentService(): PaymentService {
|
|
279
|
+
return this.paymentService;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
public getPaymentMethodService(): PaymentMethodService {
|
|
283
|
+
return this.paymentMethodService;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
public getOauth2Service(): Oauth2Service {
|
|
287
|
+
return this.oauth2Service;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
public getJwtService(): JWTService {
|
|
291
|
+
return this.jwtService;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
public getSessionHeaderAuthHookFn(): SessionHeaderAuthenticationHook {
|
|
295
|
+
return this.sessionHeaderAuthHookFn;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
public getSessionQueryParamAuthHookFn(): SessionQueryParamAuthenticationHook {
|
|
299
|
+
return this.sessionQueryParamAuthHookFn;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
public getJwtAuthHookFn(): JWTAuthenticationHook {
|
|
303
|
+
return this.jwtAuthHookFn;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
public getOauth2AuthHookFn(): Oauth2AuthenticationHook {
|
|
307
|
+
return this.oauth2AuthHookFn;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public getAuthorityAuthorizationHookFn(): AuthorityAuthorizationHook {
|
|
311
|
+
return this.authorityAuthorizationHookFn;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
public getCustomTypeService(): CustomTypeService {
|
|
315
|
+
return this.customTypeService;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Authentication,
|
|
3
|
+
HeaderPrincipal,
|
|
4
|
+
JWTPrincipal,
|
|
5
|
+
Oauth2Principal,
|
|
6
|
+
QueryParamPrincipal,
|
|
7
|
+
SessionPrincipal,
|
|
8
|
+
} from '@security-types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* SessionAuthentication is an authentication class that implements the Authentication interface.
|
|
12
|
+
* It is used to authenticate via a session id.
|
|
13
|
+
* @param sessionId - The session id to authenticate via.
|
|
14
|
+
* @param principal - The principal to authenticate via.
|
|
15
|
+
* @returns A SessionAuthentication instance.
|
|
16
|
+
*/
|
|
17
|
+
export class SessionAuthentication
|
|
18
|
+
implements Authentication<SessionPrincipal, string>
|
|
19
|
+
{
|
|
20
|
+
private principal: SessionPrincipal;
|
|
21
|
+
private authorities: string[] = [];
|
|
22
|
+
private sessionId: string;
|
|
23
|
+
private authenticated: boolean;
|
|
24
|
+
|
|
25
|
+
constructor(sessionId: string, principal: SessionPrincipal) {
|
|
26
|
+
this.principal = principal;
|
|
27
|
+
this.sessionId = sessionId;
|
|
28
|
+
this.authenticated = true;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
hasPrincipal(): boolean {
|
|
32
|
+
return this.getPrincipal() !== undefined;
|
|
33
|
+
}
|
|
34
|
+
getAuthorities(): string[] {
|
|
35
|
+
return this.authorities;
|
|
36
|
+
}
|
|
37
|
+
hasCredentials(): boolean {
|
|
38
|
+
return this.getCredentials() !== undefined;
|
|
39
|
+
}
|
|
40
|
+
getPrincipal() {
|
|
41
|
+
return this.principal;
|
|
42
|
+
}
|
|
43
|
+
getCredentials() {
|
|
44
|
+
return this.sessionId;
|
|
45
|
+
}
|
|
46
|
+
isAuthenticated(): boolean {
|
|
47
|
+
return this.authenticated;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* HeaderBasedAuthentication is an authentication class that implements the Authentication interface.
|
|
53
|
+
* It is used to authenticate via a specific header.
|
|
54
|
+
* @param authHeader - The header name that is used to authenticate.
|
|
55
|
+
* @returns A HeaderBasedAuthentication instance.
|
|
56
|
+
*/
|
|
57
|
+
export class HeaderBasedAuthentication
|
|
58
|
+
implements Authentication<HeaderPrincipal, string>
|
|
59
|
+
{
|
|
60
|
+
private authHeader: string;
|
|
61
|
+
|
|
62
|
+
constructor(authHeader: string) {
|
|
63
|
+
this.authHeader = authHeader;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
hasPrincipal(): boolean {
|
|
67
|
+
return this.getPrincipal() !== undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
getAuthorities(): string[] {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
hasCredentials(): boolean {
|
|
75
|
+
return this.getCredentials() !== undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getCredentials(): string {
|
|
79
|
+
return this.authHeader;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
getPrincipal(): HeaderPrincipal {
|
|
83
|
+
return {
|
|
84
|
+
authHeader: this.authHeader,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
isAuthenticated(): boolean {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* QueryParamBasedAuthentication is an authentication class that implements the Authentication interface.
|
|
95
|
+
* It is used to authenticate via a query param.
|
|
96
|
+
* @param authQueryParam - The query param name that is used to authenticate. It is usually called 'ctsid'.
|
|
97
|
+
* @returns A QueryParamBasedAuthentication instance.
|
|
98
|
+
*/
|
|
99
|
+
export class QueryParamBasedAuthentication
|
|
100
|
+
implements Authentication<QueryParamPrincipal, string>
|
|
101
|
+
{
|
|
102
|
+
private authQueryParam: string;
|
|
103
|
+
|
|
104
|
+
constructor(authQueryParam: string) {
|
|
105
|
+
this.authQueryParam = authQueryParam;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
hasPrincipal(): boolean {
|
|
109
|
+
return this.getPrincipal() !== undefined;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
getAuthorities(): string[] {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
hasCredentials(): boolean {
|
|
117
|
+
return this.getCredentials() !== undefined;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getCredentials(): string {
|
|
121
|
+
return this.authQueryParam;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
getPrincipal(): QueryParamPrincipal {
|
|
125
|
+
return {
|
|
126
|
+
authQueryParam: this.authQueryParam,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
isAuthenticated(): boolean {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Oauth2Authentication is an authentication class that implements the Authentication interface.
|
|
137
|
+
* It is used to authenticate via a specific OAuth2 token.
|
|
138
|
+
* @param accessToken - The OAuth2 token to authenticate via.
|
|
139
|
+
* @param principal - The principal to authenticate via.
|
|
140
|
+
* @returns A Oauth2Authentication instance.
|
|
141
|
+
*/
|
|
142
|
+
export class Oauth2Authentication
|
|
143
|
+
implements Authentication<Oauth2Principal, string>
|
|
144
|
+
{
|
|
145
|
+
private principal: Oauth2Principal;
|
|
146
|
+
private authorities: string[];
|
|
147
|
+
|
|
148
|
+
private authenticated: boolean;
|
|
149
|
+
private accessToken: string;
|
|
150
|
+
|
|
151
|
+
constructor(accessToken: string, principal: Oauth2Principal) {
|
|
152
|
+
this.principal = principal;
|
|
153
|
+
this.authorities = principal.scope
|
|
154
|
+
.split(' ')
|
|
155
|
+
.map((scope) => scope.split(':')[0])
|
|
156
|
+
.filter((scope) => scope !== '');
|
|
157
|
+
this.authenticated = true;
|
|
158
|
+
this.accessToken = accessToken;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
hasPrincipal(): boolean {
|
|
162
|
+
return this.getPrincipal() !== undefined;
|
|
163
|
+
}
|
|
164
|
+
getAuthorities(): string[] {
|
|
165
|
+
return this.authorities;
|
|
166
|
+
}
|
|
167
|
+
hasCredentials(): boolean {
|
|
168
|
+
return this.getCredentials() !== undefined;
|
|
169
|
+
}
|
|
170
|
+
getPrincipal() {
|
|
171
|
+
return this.principal;
|
|
172
|
+
}
|
|
173
|
+
getCredentials() {
|
|
174
|
+
return this.accessToken;
|
|
175
|
+
}
|
|
176
|
+
isAuthenticated(): boolean {
|
|
177
|
+
return this.authenticated;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* JWTAuthentication is an authentication class that implements the Authentication interface.
|
|
183
|
+
* It is used to authenticate via a specific JWT token.
|
|
184
|
+
* @param jwt - The JWT token to authenticate via.
|
|
185
|
+
* @param principal - The principal to authenticate via.
|
|
186
|
+
* @returns A JWTAuthentication instance.
|
|
187
|
+
*/
|
|
188
|
+
export class JWTAuthentication implements Authentication<JWTPrincipal, string> {
|
|
189
|
+
private principal: JWTPrincipal;
|
|
190
|
+
|
|
191
|
+
private authenticated: boolean;
|
|
192
|
+
private jwt: string;
|
|
193
|
+
|
|
194
|
+
constructor(jwt: string, principal: JWTPrincipal) {
|
|
195
|
+
this.principal = principal;
|
|
196
|
+
|
|
197
|
+
this.authenticated = true;
|
|
198
|
+
this.jwt = jwt;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
hasPrincipal(): boolean {
|
|
202
|
+
return this.getPrincipal() !== undefined;
|
|
203
|
+
}
|
|
204
|
+
getAuthorities(): string[] {
|
|
205
|
+
return ['manage_project', 'manage_checkout_application'];
|
|
206
|
+
}
|
|
207
|
+
hasCredentials(): boolean {
|
|
208
|
+
return this.getCredentials() !== undefined;
|
|
209
|
+
}
|
|
210
|
+
getPrincipal() {
|
|
211
|
+
return this.principal;
|
|
212
|
+
}
|
|
213
|
+
getCredentials() {
|
|
214
|
+
return this.jwt;
|
|
215
|
+
}
|
|
216
|
+
isAuthenticated(): boolean {
|
|
217
|
+
return this.authenticated;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ErrorAuthErrorResponse } from '@errorx';
|
|
2
|
+
import { validateBearerAuthorization } from '@/security/authn/bearer-utils.js';
|
|
3
|
+
|
|
4
|
+
describe('validateBearerAuthorization', () => {
|
|
5
|
+
test('should return the token when authorization header is valid', () => {
|
|
6
|
+
// Arrange
|
|
7
|
+
const authorization = 'Bearer token';
|
|
8
|
+
|
|
9
|
+
// Act
|
|
10
|
+
const result = validateBearerAuthorization(authorization);
|
|
11
|
+
|
|
12
|
+
// Assert
|
|
13
|
+
expect(result).toBe('token');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('should throw an error when authorization header is missing', () => {
|
|
17
|
+
// Arrange
|
|
18
|
+
const authorization = undefined;
|
|
19
|
+
|
|
20
|
+
// Act & Assert
|
|
21
|
+
expect(() => validateBearerAuthorization(authorization)).toThrow(
|
|
22
|
+
ErrorAuthErrorResponse,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('should throw an error when authorization header format is invalid', () => {
|
|
27
|
+
// Arrange
|
|
28
|
+
const authorization = 'InvalidFormat';
|
|
29
|
+
|
|
30
|
+
// Act & Assert
|
|
31
|
+
expect(() => validateBearerAuthorization(authorization)).toThrow(
|
|
32
|
+
ErrorAuthErrorResponse,
|
|
33
|
+
);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { ErrorAuthErrorResponse } from '@errorx';
|
|
2
|
+
|
|
3
|
+
export const validateBearerAuthorization = (
|
|
4
|
+
authorization: string | undefined,
|
|
5
|
+
): string => {
|
|
6
|
+
if (!authorization) {
|
|
7
|
+
throw new ErrorAuthErrorResponse(
|
|
8
|
+
'This endpoint requires the authorization header.',
|
|
9
|
+
{
|
|
10
|
+
skipLog: true,
|
|
11
|
+
},
|
|
12
|
+
'access_denied',
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const authorizationParts = authorization.split(' ');
|
|
17
|
+
if (authorizationParts.length !== 2 || authorizationParts[0] !== 'Bearer') {
|
|
18
|
+
throw new ErrorAuthErrorResponse(
|
|
19
|
+
`Authorization header must have the format 'Bearer <token>'`,
|
|
20
|
+
{
|
|
21
|
+
skipLog: true,
|
|
22
|
+
},
|
|
23
|
+
'invalid_request',
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return authorizationParts[1];
|
|
28
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ErrorAuthErrorResponse } from '@errorx';
|
|
2
|
+
import type { Logger } from '@logger-types';
|
|
3
|
+
import type { AuthenticationManager, JWTService } from '@security-types';
|
|
4
|
+
import {
|
|
5
|
+
type HeaderBasedAuthentication,
|
|
6
|
+
JWTAuthentication,
|
|
7
|
+
} from '@/security/authn/authns.js';
|
|
8
|
+
import { validateBearerAuthorization } from '@/security/authn/bearer-utils.js';
|
|
9
|
+
|
|
10
|
+
export class JWTAuthenticationManager implements AuthenticationManager {
|
|
11
|
+
private jwtService: JWTService;
|
|
12
|
+
private iss: string;
|
|
13
|
+
private projectKey: string;
|
|
14
|
+
private logger: Logger;
|
|
15
|
+
|
|
16
|
+
constructor(opts: {
|
|
17
|
+
jwtService: JWTService;
|
|
18
|
+
iss: string;
|
|
19
|
+
projectKey: string;
|
|
20
|
+
logger: Logger;
|
|
21
|
+
}) {
|
|
22
|
+
this.jwtService = opts.jwtService;
|
|
23
|
+
this.iss = opts.iss;
|
|
24
|
+
this.projectKey = opts.projectKey;
|
|
25
|
+
this.logger = opts.logger;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async authenticate(
|
|
29
|
+
authentication: HeaderBasedAuthentication,
|
|
30
|
+
): Promise<JWTAuthentication> {
|
|
31
|
+
const principal = authentication.getPrincipal();
|
|
32
|
+
|
|
33
|
+
const token = validateBearerAuthorization(principal.authHeader);
|
|
34
|
+
|
|
35
|
+
const decodedToken = (await this.jwtService.verify({
|
|
36
|
+
token,
|
|
37
|
+
})) as {
|
|
38
|
+
iss: string;
|
|
39
|
+
[key: string]: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (decodedToken.iss !== this.iss) {
|
|
43
|
+
throw new ErrorAuthErrorResponse(
|
|
44
|
+
'Issuer in the token does not match the expected issuer.',
|
|
45
|
+
{
|
|
46
|
+
privateFields: {
|
|
47
|
+
expectedIssuer: this.iss,
|
|
48
|
+
actualIssuer: decodedToken.iss,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const projectKey = decodedToken[`${this.iss}/claims/project_key`];
|
|
55
|
+
if (projectKey !== this.projectKey) {
|
|
56
|
+
throw new ErrorAuthErrorResponse('Project key does not match.', {
|
|
57
|
+
privateFields: {
|
|
58
|
+
expectedIssuer: this.iss,
|
|
59
|
+
actualIssuer: decodedToken.iss,
|
|
60
|
+
projectKey,
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return new JWTAuthentication(token, {
|
|
66
|
+
mcCustomerId: decodedToken.sub,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|