@blazedpath/commons 0.0.4 → 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.
@@ -103,7 +103,7 @@ class HapiServerAzureAd {
103
103
  // To refresh the tokens, Azure uses a silent re authentication
104
104
  const silentRereshTokenResponse = await me.authServerConfig.authServer.msalClient.acquireTokenSilent({
105
105
  account: tokenInfo.account, // If token exists in yar. Account should always exist
106
- scopes: me.authServerConfig.authServer.scope.split(" ")?? ["user.read"],
106
+ scopes: me.authServerConfig.authServer.scope.split(" ") ?? ["user.read"],
107
107
  });
108
108
  const obtainedTokens = {};
109
109
  // Check if the silent refresh token was successful
@@ -166,7 +166,7 @@ class HapiServerAzureAd {
166
166
  });
167
167
 
168
168
  let userRelog = request.yar.get('userRelog');
169
- request.yar.set('pkv',pkce.verifier)
169
+ request.yar.set('pkv', pkce.verifier)
170
170
  request.yar.commit(h);
171
171
  if (userRelog && request.path !== '/') {
172
172
  return h.redirect('/');
@@ -193,7 +193,7 @@ class HapiServerAzureAd {
193
193
  const tokenResponse = await me.authServerConfig.authServer.msalClient.acquireTokenByCode({
194
194
  code: authCode,
195
195
  redirectUri: me.getRedirectUri(request, 'auth/callback'),
196
- scopes: me.authServerConfig.authServer.scope.split(" ")?? ["user.read"],
196
+ scopes: me.authServerConfig.authServer.scope.split(" ") ?? ["user.read"],
197
197
  codeVerifier: pkceverifier,
198
198
  });
199
199
  let obtainedTokens = {
@@ -253,7 +253,7 @@ class HapiServerAzureAd {
253
253
  const tokenResponse = await me.authServerConfig.authServer.msalClient.acquireTokenByCode({
254
254
  code: authCode,
255
255
  redirectUri: me.getRedirectUri(request, 'auth/callback'),
256
- scopes: me.authServerConfig.authServer.scope.split(" ")?? ["user.read"],
256
+ scopes: me.authServerConfig.authServer.scope.split(" ") ?? ["user.read"],
257
257
  codeVerifier: pkceverifier,
258
258
  responseMode: 'form_post'
259
259
  });
@@ -352,6 +352,45 @@ class HapiServerAzureAd {
352
352
  }
353
353
  }
354
354
  })
355
+
356
+ hapiServer.route({
357
+ method: 'GET',
358
+ path: '/check-authorize',
359
+ handler: async (request, h) => {
360
+ try {
361
+ const resourcePath = request.query.path;
362
+ const action = request.query.action;
363
+ const roles = request.query.roles;
364
+ const domains = request.query.domains;
365
+ let parsedRoles;
366
+ if (Array.isArray(roles)) {
367
+ parsedRoles = roles;
368
+ } else if (typeof roles === 'string') {
369
+ parsedRoles = roles.split(',').map(r => r.trim());
370
+ } else {
371
+ parsedRoles = [];
372
+ }
373
+ let parsedDomains;
374
+ if (Array.isArray(domains)) {
375
+ parsedDomains = domains;
376
+ } else if (typeof domains === 'string') {
377
+ parsedDomains = domains.split(',').map(d => d.trim());
378
+ } else {
379
+ parsedDomains = [];
380
+ }
381
+ const result = await securityService.checkAuthorize(
382
+ resourcePath,
383
+ action,
384
+ parsedRoles,
385
+ parsedDomains
386
+ );
387
+ return h.response(JSON.stringify(result)).takeover()
388
+ } catch (err) {
389
+ return errorResponse(h, err, 401)
390
+ }
391
+ }
392
+ })
393
+
355
394
  // /get-user-info
356
395
  hapiServer.route({
357
396
  method: 'GET',
@@ -406,7 +445,7 @@ class HapiServerAzureAd {
406
445
  checkSessionUrl: me.getBaseUrl(request) + 'check-session'
407
446
  })
408
447
  return h.response(content)
409
- .header('Content-Type', 'text/html')
448
+ .header('Content-Type', 'text/html')
410
449
  } catch (err) {
411
450
  return errorResponse(h, err, 500)
412
451
  }
@@ -426,7 +465,7 @@ class HapiServerAzureAd {
426
465
  // check if token is about to be expired
427
466
  tokenIsExpired.expired = await me.tokenAboutToExpire(tokenInfo.token, 0.5);
428
467
  if (tokenIsExpired.expired) {
429
- let params = {
468
+ let params = {
430
469
  redirectUri: me.getRedirectUri(request, 'auth/callback'),
431
470
  scopes: me.authServerConfig.authServer.scope.split(" "),
432
471
  }
@@ -101,8 +101,7 @@ class HapiServerKeycloak {
101
101
  if (!authServer.scope || !authServer.scope.split(' ').some((reg) => reg === 'openid')) {
102
102
  authServer.scope = `openid ${authServer.scope || ''}`
103
103
  authServer.scope.trim();
104
- }
105
- this.authServerConfig.authServer.scope ? this.authServerConfig.authServer.scope.trim().replace(/\s+/g, '%20') : 'openid';
104
+ }
106
105
  if (authServer.tokenEndpoint && !authServer.tokenEndpoint.match(/https.*/)) {
107
106
  hapiServer.states.cookies[this.COOKIE_NAMES.SID].isSecure = false
108
107
  hapiServer.states.cookies[this.COOKIE_NAMES.SESSION_STATE].isSecure = false
@@ -349,6 +348,45 @@ class HapiServerKeycloak {
349
348
  }
350
349
  }
351
350
  })
351
+
352
+ hapiServer.route({
353
+ method: 'GET',
354
+ path: '/check-authorize',
355
+ handler: async (request, h) => {
356
+ try {
357
+ const resourcePath = request.query.path;
358
+ const action = request.query.action;
359
+ const roles = request.query.roles;
360
+ const domains = request.query.domains;
361
+ let parsedRoles;
362
+ if (Array.isArray(roles)) {
363
+ parsedRoles = roles;
364
+ } else if (typeof roles === 'string') {
365
+ parsedRoles = roles.split(',').map(r => r.trim());
366
+ } else {
367
+ parsedRoles = [];
368
+ }
369
+ let parsedDomains;
370
+ if (Array.isArray(domains)) {
371
+ parsedDomains = domains;
372
+ } else if (typeof domains === 'string') {
373
+ parsedDomains = domains.split(',').map(d => d.trim());
374
+ } else {
375
+ parsedDomains = [];
376
+ }
377
+ const result = await securityService.checkAuthorize(
378
+ resourcePath,
379
+ action,
380
+ parsedRoles,
381
+ parsedDomains
382
+ );
383
+ return h.response(JSON.stringify(result)).takeover()
384
+ } catch (err) {
385
+ return errorResponse(h, err, 401)
386
+ }
387
+ }
388
+ })
389
+
352
390
  // /get-user-info
353
391
  hapiServer.route({
354
392
  method: 'GET',
@@ -123,6 +123,45 @@ class HapiServerSimToken {
123
123
  .code(200)
124
124
  }
125
125
  })
126
+
127
+ hapiServer.route({
128
+ method: 'GET',
129
+ path: '/check-authorize',
130
+ handler: async (request, h) => {
131
+ try {
132
+ const resourcePath = request.query.path;
133
+ const action = request.query.action;
134
+ const roles = request.query.roles;
135
+ const domains = request.query.domains;
136
+ let parsedRoles;
137
+ if (Array.isArray(roles)) {
138
+ parsedRoles = roles;
139
+ } else if (typeof roles === 'string') {
140
+ parsedRoles = roles.split(',').map(r => r.trim());
141
+ } else {
142
+ parsedRoles = [];
143
+ }
144
+ let parsedDomains;
145
+ if (Array.isArray(domains)) {
146
+ parsedDomains = domains;
147
+ } else if (typeof domains === 'string') {
148
+ parsedDomains = domains.split(',').map(d => d.trim());
149
+ } else {
150
+ parsedDomains = [];
151
+ }
152
+ const result = await securityService.checkAuthorize(
153
+ resourcePath,
154
+ action,
155
+ parsedRoles,
156
+ parsedDomains
157
+ );
158
+ return h.response(JSON.stringify(result)).takeover()
159
+ } catch (err) {
160
+ return errorResponse(h, err, 401)
161
+ }
162
+ }
163
+ })
164
+
126
165
  // /get-user-info
127
166
  hapiServer.route({
128
167
  path: '/get-user-info',
@@ -267,6 +267,46 @@ class Hapi {
267
267
  }
268
268
  })
269
269
 
270
+ context.route({
271
+ method: 'GET',
272
+ path: '/check-authorize',
273
+ handler: async (request, h) => {
274
+ try {
275
+ const resourcePath = request.query.path;
276
+ const action = request.query.action;
277
+ const roles = request.query.roles;
278
+ const domains = request.query.domains;
279
+ let parsedRoles;
280
+ if (Array.isArray(roles)) {
281
+ parsedRoles = roles;
282
+ } else if (typeof roles === 'string') {
283
+ parsedRoles = roles.split(',').map(r => r.trim());
284
+ } else {
285
+ parsedRoles = [];
286
+ }
287
+ let parsedDomains;
288
+ if (Array.isArray(domains)) {
289
+ parsedDomains = domains;
290
+ } else if (typeof domains === 'string') {
291
+ parsedDomains = domains.split(',').map(d => d.trim());
292
+ } else {
293
+ parsedDomains = [];
294
+ }
295
+ const result = await securityService.checkAuthorize(
296
+ resourcePath,
297
+ action,
298
+ parsedRoles,
299
+ parsedDomains
300
+ );
301
+ return h.response(JSON.stringify(result)).takeover()
302
+ } catch (err) {
303
+ return errorResponse(h, err, 401)
304
+ }
305
+ }
306
+ })
307
+
308
+
309
+
270
310
  context.route({
271
311
  method: 'GET',
272
312
  path: '/get-user-info',
@@ -205,13 +205,7 @@ class HapiServer {
205
205
  // By this point, token refresh was already attempted in onPreAuth event, so it redirects to login on unauthorized
206
206
  if (response.isBoom && response.output.statusCode === 401 && !request.path.startsWith('/auth/callback') && !authError) {
207
207
  if (this.authServerConfig.authServer.provider=== 'ad-azure') {
208
- return h.redirect('/login').takeover();
209
- const authUrl = await this.authServerConfig.authServer.msalClient.getAuthCodeUrl({
210
- redirectUri: me.getBaseUrl(request) + 'auth/callback',
211
- scopes: ['user.read'],
212
- });
213
-
214
- return h.redirect(authUrl);
208
+ return h.redirect('/login').takeover();
215
209
  }
216
210
  // Create the url query string parameters. with a random code verifier, store in yar and get the codeChallenge
217
211
  const codeVerifier = crypto.randomBytes(32).toString('base64url');
@@ -312,7 +306,7 @@ class HapiServer {
312
306
  },
313
307
  }
314
308
  );
315
- if (!tokenResponse.statusText ==='OK') {
309
+ if (!tokenResponse.statusText =='OK') {
316
310
  throw new Error('Failed to exchange code for tokens');
317
311
  }
318
312
  obtainedTokens.tokenType = 'Bearer';
@@ -396,6 +390,45 @@ class HapiServer {
396
390
  }
397
391
  }
398
392
  })
393
+
394
+ context.route({
395
+ method: 'GET',
396
+ path: '/check-authorize',
397
+ handler: async (request, h) => {
398
+ try {
399
+ const resourcePath = request.query.path;
400
+ const action = request.query.action;
401
+ const roles = request.query.roles;
402
+ const domains = request.query.domains;
403
+ let parsedRoles;
404
+ if (Array.isArray(roles)) {
405
+ parsedRoles = roles;
406
+ } else if (typeof roles === 'string') {
407
+ parsedRoles = roles.split(',').map(r => r.trim());
408
+ } else {
409
+ parsedRoles = [];
410
+ }
411
+ let parsedDomains;
412
+ if (Array.isArray(domains)) {
413
+ parsedDomains = domains;
414
+ } else if (typeof domains === 'string') {
415
+ parsedDomains = domains.split(',').map(d => d.trim());
416
+ } else {
417
+ parsedDomains = [];
418
+ }
419
+ const result = await securityService.checkAuthorize(
420
+ resourcePath,
421
+ action,
422
+ parsedRoles,
423
+ parsedDomains
424
+ );
425
+ return h.response(JSON.stringify(result)).takeover()
426
+ } catch (err) {
427
+ return errorResponse(h, err, 401)
428
+ }
429
+ }
430
+ })
431
+
399
432
  // /get-user-info
400
433
  hapiServer.route({
401
434
  method: 'GET',
@@ -9,8 +9,8 @@ module.exports = class SecureUrlService {
9
9
  validate(url, token, _session_key, timeoutMs) {
10
10
  const path = decodeURIComponent(url.split('?')[0]);
11
11
  if (!token) {
12
- this.logger.error(`Token parameter 'tt' is missing in the URL. path:${path}`)
13
- throw new Exception("Token parameter 'tt' is missing in the URL.", 'SecureUrlError', 404);
12
+ this.logger.error(`Token parameter 'sut' is missing in the URL. path:${path}`)
13
+ throw new Exception("Token parameter 'sut' is missing in the URL.", 'SecureUrlError', 404);
14
14
  }
15
15
  const session_key = isBase64(_session_key)?atob(_session_key):_session_key
16
16
  const key = `${session_key}${btoa(path)}`;
@@ -26,13 +26,19 @@ module.exports = class SecureUrlService {
26
26
  } catch (e) {
27
27
  this.logger.error(`Malformed token content. path:${path} error: ${e.message}`)
28
28
  throw new Exception("Malformed token content.", 'SecureUrlError', 400);
29
- }
30
- const timeout = requestTime + timeoutMs
31
- const time = Date.now()
32
- const isValid = time < timeout && requestTime < time;
29
+ }
30
+ const now = Date.now();
31
+ const diff = Math.abs(now - requestTime);
32
+ const limit = parseInt(timeoutMs, 10);
33
+ const isValid = diff <= limit;
33
34
  if (!isValid) {
35
+ <<<<<<< HEAD:blazedpath-commons/blz-security/secureUrlService.js
34
36
  this.logger.error(`The token has expired. path:${path} timeout:${timeout} time: ${time}`)
35
37
  throw new Exception("The token has expired.", 'SecureUrlError', 408);
38
+ =======
39
+ this.logger.error(`The token has expired. path:${path} requestTime:${requestTime} now: ${now} limit:${limit} diff:${diff}`)
40
+ throw new Exception("The token has expired.", 'SecureUrlError', 410);
41
+ >>>>>>> develop:blz-commons/private-sources/blz-security/secureUrlService.js
36
42
  }
37
43
  }
38
44
 
@@ -406,4 +406,8 @@ module.exports = class SecurityService {
406
406
  logUnProtected() {
407
407
  this.logger.info('unprotected: ' + JSON.stringify(this.unProtected))
408
408
  }
409
+
410
+ async checkAuthorize (path, action, roles, domains) {
411
+ return this.authorizationService.checkAuthorize(path, action, roles, domains)
412
+ }
409
413
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blazedpath/commons",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "commos library for blazedpath applications",
5
5
  "main": "index.js",
6
6
  "types": "dist/index.d.ts",