@universis/janitor 1.10.0 → 1.11.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/dist/index.d.ts CHANGED
@@ -1,11 +1,13 @@
1
1
  import * as _themost_common from '@themost/common';
2
- import { ApplicationService, ApplicationBase, ConfigurationStrategy, ConfigurationBase } from '@themost/common';
2
+ import { ApplicationService, ApplicationBase, ConfigurationStrategy, ConfigurationBase, HttpForbiddenError, HttpError } from '@themost/common';
3
3
  import { Router, Application, Handler, Request as Request$1 } from 'express';
4
4
  import { Store, Options } from 'express-rate-limit';
5
5
  import { BehaviorSubject } from 'rxjs';
6
6
  import { Store as Store$1, Options as Options$1 } from 'express-slow-down';
7
7
  import RedisStore from 'rate-limit-redis';
8
8
  import { DataContext } from '@themost/data';
9
+ import BearerStrategy from 'passport-http-bearer';
10
+ import { Authenticator } from 'passport';
9
11
 
10
12
  declare type RateLimitStoreConstructor = new (...arg: unknown[]) => Store;
11
13
 
@@ -250,5 +252,133 @@ declare class AppSpeedLimitService extends SpeedLimitService {
250
252
  constructor(app: _themost_common.ApplicationBase);
251
253
  }
252
254
 
253
- export { AppRateLimitService, AppSpeedLimitService, DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, OAuth2ClientService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
255
+ declare class HttpBearerTokenRequired extends HttpError {
256
+ constructor() {
257
+ super(499, 'A token is required to fulfill the request.');
258
+ this.code = 'E_TOKEN_REQUIRED';
259
+ this.title = 'Token Required';
260
+ }
261
+ }
262
+
263
+ declare class HttpBearerTokenNotFound extends HttpError {
264
+ constructor() {
265
+ super(498, 'Token was not found.');
266
+ this.code = 'E_TOKEN_NOT_FOUND';
267
+ this.title = 'Invalid token';
268
+ }
269
+ }
270
+
271
+ declare class HttpBearerTokenExpired extends HttpError {
272
+ constructor() {
273
+ super(498, 'Token was expired or is in invalid state.');
274
+ this.code = 'E_TOKEN_EXPIRED';
275
+ this.title = 'Invalid token';
276
+ }
277
+ }
278
+
279
+ declare class HttpAccountDisabled extends HttpForbiddenError {
280
+ constructor() {
281
+ super('Access is denied. User account is disabled.');
282
+ this.code = 'E_ACCOUNT_DISABLED';
283
+ this.statusCode = 403.2;
284
+ this.title = 'Disabled account';
285
+ }
286
+ }
287
+
288
+ declare class HttpBearerStrategy extends BearerStrategy {
289
+ constructor() {
290
+ super({
291
+ passReqToCallback: true
292
+ },
293
+ /**
294
+ * @param {Request} req
295
+ * @param {string} token
296
+ * @param {Function} done
297
+ */
298
+ function(req, token, done) {
299
+ /**
300
+ * Gets OAuth2 client services
301
+ * @type {import('./OAuth2ClientService').OAuth2ClientService}
302
+ */
303
+ let client = req.context.getApplication().getStrategy(function OAuth2ClientService() {});
304
+ // if client cannot be found
305
+ if (client == null) {
306
+ // throw configuration error
307
+ return done(new Error('Invalid application configuration. OAuth2 client service cannot be found.'))
308
+ }
309
+ if (token == null) {
310
+ // throw 499 Token Required error
311
+ return done(new HttpBearerTokenRequired());
312
+ }
313
+ // get token info
314
+ client.getTokenInfo(req.context, token).then(info => {
315
+ if (info == null) {
316
+ // the specified token cannot be found - 498 invalid token with specific code
317
+ return done(new HttpBearerTokenNotFound());
318
+ }
319
+ // if the given token is not active throw token expired - 498 invalid token with specific code
320
+ if (!info.active) {
321
+ return done(new HttpBearerTokenExpired());
322
+ }
323
+ // find user from token info
324
+ return (function () {
325
+ /**
326
+ * @type {import('./services/user-provisioning-mapper-service').UserProvisioningMapperService}
327
+ */
328
+ const mapper = req.context.getApplication().getService(function UserProvisioningMapperService() {});
329
+ if (mapper == null) {
330
+ return req.context.model('User').where('name').equal(info.username).silent().getItem();
331
+ }
332
+ return mapper.getUser(req.context, info);
333
+ })().then((user) => {
334
+ // check if userProvisioning service is installed and try to find related user only if user not found
335
+ if (user == null) {
336
+ /**
337
+ * @type {import('./services/user-provisioning-service').UserProvisioningService}
338
+ */
339
+ const service = req.context.getApplication().getService(function UserProvisioningService() {});
340
+ if (service == null) {
341
+ return user;
342
+ }
343
+ return service.validateUser(req.context, info);
344
+ }
345
+ return user;
346
+ }).then( user => {
347
+ // user cannot be found and of course cannot be authenticated (throw forbidden error)
348
+ if (user == null) {
349
+ // write access log for forbidden
350
+ return done(new HttpForbiddenError());
351
+ }
352
+ // check if user has enabled attribute
353
+ if (Object.prototype.hasOwnProperty.call(user, 'enabled') && !user.enabled) {
354
+ //if user.enabled is off throw forbidden error
355
+ return done(new HttpAccountDisabled('Access is denied. User account is disabled.'));
356
+ }
357
+ // otherwise return user data
358
+ return done(null, {
359
+ 'name': user.name,
360
+ 'authenticationProviderKey': user.id,
361
+ 'authenticationType':'Bearer',
362
+ 'authenticationToken': token,
363
+ 'authenticationScope': info.scope
364
+ });
365
+ });
366
+ }).catch(err => {
367
+ // end log token info request with error
368
+ if (err && err.statusCode === 404) {
369
+ // revert 404 not found returned by auth server to 498 invalid token
370
+ return done(new HttpBearerTokenNotFound());
371
+ }
372
+ // otherwise continue with error
373
+ return done(err);
374
+ });
375
+ });
376
+ }
377
+ }
378
+
379
+ declare class PassportService extends ApplicationService {
380
+ getInstance(): Authenticator
381
+ }
382
+
383
+ export { AppRateLimitService, AppSpeedLimitService, DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, HttpAccountDisabled, HttpBearerStrategy, HttpBearerTokenExpired, HttpBearerTokenNotFound, HttpBearerTokenRequired, OAuth2ClientService, PassportService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
254
384
  export type { GenericUser, OAuth2AuthorizeUser, OAuth2MethodOptions, OAuth2ServiceSettings, OAuth2User, OAuth2UserProfile, RateLimitServiceConfiguration, RateLimitStoreConstructor, ScopeAccessConfigurationElement, ScopeAccessConfigurationSection, SpeedLimitServiceConfiguration, SpeedLimitStoreConstructor, UniversisConfigurationSection };
package/dist/index.esm.js CHANGED
@@ -11,6 +11,8 @@ import '@themost/promise-sequence';
11
11
  import url, { URL } from 'url';
12
12
  import { Request } from 'superagent';
13
13
  import jwt from 'jsonwebtoken';
14
+ import BearerStrategy from 'passport-http-bearer';
15
+ import passport from 'passport';
14
16
 
15
17
  class RateLimitService extends ApplicationService {
16
18
  /**
@@ -1182,5 +1184,150 @@ class AppSpeedLimitService extends SpeedLimitService {
1182
1184
  }
1183
1185
  }
1184
1186
 
1185
- export { AppRateLimitService, AppSpeedLimitService, DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, HttpRemoteAddrForbiddenError, OAuth2ClientService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
1187
+ class HttpBearerTokenRequired extends HttpError {
1188
+ constructor() {
1189
+ super(499, 'A token is required to fulfill the request.');
1190
+ this.code = 'E_TOKEN_REQUIRED';
1191
+ this.title = 'Token Required';
1192
+ }
1193
+ }
1194
+
1195
+ class HttpBearerTokenNotFound extends HttpError {
1196
+ constructor() {
1197
+ super(498, 'Token was not found.');
1198
+ this.code = 'E_TOKEN_NOT_FOUND';
1199
+ this.title = 'Invalid token';
1200
+ }
1201
+ }
1202
+
1203
+ class HttpBearerTokenExpired extends HttpError {
1204
+ constructor() {
1205
+ super(498, 'Token was expired or is in invalid state.');
1206
+ this.code = 'E_TOKEN_EXPIRED';
1207
+ this.title = 'Invalid token';
1208
+ }
1209
+ }
1210
+
1211
+ class HttpAccountDisabled extends HttpForbiddenError {
1212
+ constructor() {
1213
+ super('Access is denied. User account is disabled.');
1214
+ this.code = 'E_ACCOUNT_DISABLED';
1215
+ this.statusCode = 403.2;
1216
+ this.title = 'Disabled account';
1217
+ }
1218
+ }
1219
+
1220
+ class HttpBearerStrategy extends BearerStrategy {
1221
+ constructor() {
1222
+ super({
1223
+ passReqToCallback: true
1224
+ },
1225
+ /**
1226
+ * @param {Request} req
1227
+ * @param {string} token
1228
+ * @param {Function} done
1229
+ */
1230
+ function (req, token, done) {
1231
+ /**
1232
+ * Gets OAuth2 client services
1233
+ * @type {import('./OAuth2ClientService').OAuth2ClientService}
1234
+ */
1235
+ let client = req.context.getApplication().getStrategy(function OAuth2ClientService() {});
1236
+ // if client cannot be found
1237
+ if (client == null) {
1238
+ // throw configuration error
1239
+ return done(new Error('Invalid application configuration. OAuth2 client service cannot be found.'));
1240
+ }
1241
+ if (token == null) {
1242
+ // throw 499 Token Required error
1243
+ return done(new HttpBearerTokenRequired());
1244
+ }
1245
+ // get token info
1246
+ client.getTokenInfo(req.context, token).then((info) => {
1247
+ if (info == null) {
1248
+ // the specified token cannot be found - 498 invalid token with specific code
1249
+ return done(new HttpBearerTokenNotFound());
1250
+ }
1251
+ // if the given token is not active throw token expired - 498 invalid token with specific code
1252
+ if (!info.active) {
1253
+ return done(new HttpBearerTokenExpired());
1254
+ }
1255
+ // find user from token info
1256
+ return function () {
1257
+ /**
1258
+ * @type {import('./services/user-provisioning-mapper-service').UserProvisioningMapperService}
1259
+ */
1260
+ const mapper = req.context.getApplication().getService(function UserProvisioningMapperService() {});
1261
+ if (mapper == null) {
1262
+ return req.context.model('User').where('name').equal(info.username).silent().getItem();
1263
+ }
1264
+ return mapper.getUser(req.context, info);
1265
+ }().then((user) => {
1266
+ // check if userProvisioning service is installed and try to find related user only if user not found
1267
+ if (user == null) {
1268
+ /**
1269
+ * @type {import('./services/user-provisioning-service').UserProvisioningService}
1270
+ */
1271
+ const service = req.context.getApplication().getService(function UserProvisioningService() {});
1272
+ if (service == null) {
1273
+ return user;
1274
+ }
1275
+ return service.validateUser(req.context, info);
1276
+ }
1277
+ return user;
1278
+ }).then((user) => {
1279
+ // user cannot be found and of course cannot be authenticated (throw forbidden error)
1280
+ if (user == null) {
1281
+ // write access log for forbidden
1282
+ return done(new HttpForbiddenError());
1283
+ }
1284
+ // check if user has enabled attribute
1285
+ if (Object.prototype.hasOwnProperty.call(user, 'enabled') && !user.enabled) {
1286
+ //if user.enabled is off throw forbidden error
1287
+ return done(new HttpAccountDisabled('Access is denied. User account is disabled.'));
1288
+ }
1289
+ // otherwise return user data
1290
+ return done(null, {
1291
+ 'name': user.name,
1292
+ 'authenticationProviderKey': user.id,
1293
+ 'authenticationType': 'Bearer',
1294
+ 'authenticationToken': token,
1295
+ 'authenticationScope': info.scope
1296
+ });
1297
+ });
1298
+ }).catch((err) => {
1299
+ // end log token info request with error
1300
+ if (err && err.statusCode === 404) {
1301
+ // revert 404 not found returned by auth server to 498 invalid token
1302
+ return done(new HttpBearerTokenNotFound());
1303
+ }
1304
+ // otherwise continue with error
1305
+ return done(err);
1306
+ });
1307
+ });
1308
+ }
1309
+ }
1310
+
1311
+ class PassportService extends ApplicationService {
1312
+ constructor(app) {
1313
+ super(app);
1314
+ const authenticator = new passport.Authenticator();
1315
+ Object.defineProperty(this, 'authenticator', {
1316
+ configurable: true,
1317
+ enumerable: false,
1318
+ writable: false,
1319
+ value: authenticator
1320
+ });
1321
+ }
1322
+
1323
+ /**
1324
+ * @returns {import('passport').Authenticator}
1325
+ */
1326
+ getInstance() {
1327
+ return this.authenticator;
1328
+ }
1329
+
1330
+ }
1331
+
1332
+ export { AppRateLimitService, AppSpeedLimitService, DefaultScopeAccessConfiguration, EnableScopeAccessConfiguration, ExtendScopeAccessConfiguration, HttpAccountDisabled, HttpBearerStrategy, HttpBearerTokenExpired, HttpBearerTokenNotFound, HttpBearerTokenRequired, HttpRemoteAddrForbiddenError, OAuth2ClientService, PassportService, RateLimitService, RedisClientStore, RemoteAddressValidator, ScopeAccessConfiguration, ScopeString, SpeedLimitService, validateScope };
1186
1333
  //# sourceMappingURL=index.esm.js.map