@microsoft/teamsfx 0.2.8-alpha.9ef5081b.0 → 0.2.8-alpha.b4c7969d.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.js CHANGED
@@ -3,14 +3,15 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var tslib = require('tslib');
6
- var identity = require('@azure/identity');
7
6
  var jwt_decode = require('jwt-decode');
7
+ var crypto = require('crypto');
8
8
  var coreHttp = require('@azure/core-http');
9
9
  var msalNode = require('@azure/msal-node');
10
10
  var botbuilder = require('botbuilder');
11
11
  var botbuilderDialogs = require('botbuilder-dialogs');
12
12
  var uuid = require('uuid');
13
13
  var microsoftGraphClient = require('@microsoft/microsoft-graph-client');
14
+ var identity = require('@azure/identity');
14
15
 
15
16
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
16
17
 
@@ -32,6 +33,10 @@ exports.ErrorCode = void 0;
32
33
  * Invalid configuration error.
33
34
  */
34
35
  ErrorCode["InvalidConfiguration"] = "InvalidConfiguration";
36
+ /**
37
+ * Invalid certificate error.
38
+ */
39
+ ErrorCode["InvalidCertificate"] = "InvalidCertificate";
35
40
  /**
36
41
  * Internal error.
37
42
  */
@@ -330,6 +335,43 @@ function validateScopesType(value) {
330
335
  internalLogger.error(errorMsg);
331
336
  throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidParameter);
332
337
  }
338
+ /**
339
+ * @internal
340
+ */
341
+ function getScopesArray(scopes) {
342
+ const scopesArray = typeof scopes === "string" ? scopes.split(" ") : scopes;
343
+ return scopesArray.filter((x) => x !== null && x !== "");
344
+ }
345
+ /**
346
+ * @internal
347
+ */
348
+ function getAuthority(authorityHost, tenantId) {
349
+ const normalizedAuthorityHost = authorityHost.replace(/\/+$/g, "");
350
+ return normalizedAuthorityHost + "/" + tenantId;
351
+ }
352
+ /**
353
+ * @internal
354
+ */
355
+ function parseCertificate(certificateContent) {
356
+ if (!certificateContent) {
357
+ return undefined;
358
+ }
359
+ const certificatePattern = /(-+BEGIN CERTIFICATE-+)(\n\r?|\r\n?)([A-Za-z0-9+/\n\r]+=*)(\n\r?|\r\n?)(-+END CERTIFICATE-+)/;
360
+ const match = certificatePattern.exec(certificateContent);
361
+ if (!match) {
362
+ const errorMsg = "The certificate content does not contain a PEM-encoded certificate.";
363
+ internalLogger.error(errorMsg);
364
+ throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidCertificate);
365
+ }
366
+ const thumbprint = crypto.createHash("sha1")
367
+ .update(Buffer.from(match[3], "base64"))
368
+ .digest("hex")
369
+ .toUpperCase();
370
+ return {
371
+ thumbprint: thumbprint,
372
+ privateKey: certificateContent,
373
+ };
374
+ }
333
375
 
334
376
  // Copyright (c) Microsoft Corporation.
335
377
  // Licensed under the MIT license.
@@ -469,6 +511,27 @@ function getAuthenticationConfiguration() {
469
511
  throw new ErrorWithCode(formatString(ErrorMessage.ConfigurationNotExists, errorMsg), exports.ErrorCode.InvalidConfiguration);
470
512
  }
471
513
 
514
+ /**
515
+ * @internal
516
+ */
517
+ function createConfidentialClientApplication(authentication) {
518
+ const authority = getAuthority(authentication.authorityHost, authentication.tenantId);
519
+ const clientCertificate = parseCertificate(authentication.certificateContent);
520
+ const auth = {
521
+ clientId: authentication.clientId,
522
+ authority: authority,
523
+ };
524
+ if (clientCertificate) {
525
+ auth.clientCertificate = clientCertificate;
526
+ }
527
+ else {
528
+ auth.clientSecret = authentication.clientSecret;
529
+ }
530
+ return new msalNode.ConfidentialClientApplication({
531
+ auth,
532
+ });
533
+ }
534
+
472
535
  // Copyright (c) Microsoft Corporation.
473
536
  /**
474
537
  * Represent Microsoft 365 tenant identity, and it is usually used when user is not involved like time-triggered automation job.
@@ -499,10 +562,7 @@ class M365TenantCredential {
499
562
  constructor() {
500
563
  internalLogger.info("Create M365 tenant credential");
501
564
  const config = this.loadAndValidateConfig();
502
- const tokenCredentialOptions = {
503
- authorityHost: config.authorityHost,
504
- };
505
- this.clientSecretCredential = new identity.ClientSecretCredential(config.tenantId, config.clientId, config.clientSecret, tokenCredentialOptions);
565
+ this.msalClient = createConfidentialClientApplication(config);
506
566
  }
507
567
  /**
508
568
  * Get access token for credential.
@@ -537,20 +597,21 @@ class M365TenantCredential {
537
597
  const scopesStr = typeof scopes === "string" ? scopes : scopes.join(" ");
538
598
  internalLogger.info("Get access token with scopes: " + scopesStr);
539
599
  try {
540
- accessToken = yield this.clientSecretCredential.getToken(scopes);
600
+ const scopesArray = getScopesArray(scopes);
601
+ const authenticationResult = yield this.msalClient.acquireTokenByClientCredential({
602
+ scopes: scopesArray,
603
+ });
604
+ if (authenticationResult) {
605
+ accessToken = {
606
+ token: authenticationResult.accessToken,
607
+ expiresOnTimestamp: authenticationResult.expiresOn.getTime(),
608
+ };
609
+ }
541
610
  }
542
611
  catch (err) {
543
- if (err instanceof identity.AuthenticationError) {
544
- const authError = err;
545
- const errorMsg = `Get M365 tenant credential with authentication error: status code ${authError.statusCode}, error messages: ${authError.message}`;
546
- internalLogger.error(errorMsg);
547
- throw new ErrorWithCode(errorMsg, exports.ErrorCode.ServiceError);
548
- }
549
- else {
550
- const errorMsg = "Get M365 tenant credential failed with error: " + err.message;
551
- internalLogger.error(errorMsg);
552
- throw new ErrorWithCode(errorMsg, exports.ErrorCode.InternalError);
553
- }
612
+ const errorMsg = "Get M365 tenant credential failed with error: " + err.message;
613
+ internalLogger.error(errorMsg);
614
+ throw new ErrorWithCode(errorMsg, exports.ErrorCode.ServiceError);
554
615
  }
555
616
  if (!accessToken) {
556
617
  const errorMsg = "Get M365 tenant credential access token failed with empty access token";
@@ -571,15 +632,15 @@ class M365TenantCredential {
571
632
  internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);
572
633
  throw new ErrorWithCode(ErrorMessage.AuthenticationConfigurationNotExists, exports.ErrorCode.InvalidConfiguration);
573
634
  }
574
- if (config.clientId && config.clientSecret && config.tenantId) {
635
+ if (config.clientId && (config.clientSecret || config.certificateContent) && config.tenantId) {
575
636
  return config;
576
637
  }
577
638
  const missingValues = [];
578
639
  if (!config.clientId) {
579
640
  missingValues.push("clientId");
580
641
  }
581
- if (!config.clientSecret) {
582
- missingValues.push("clientSecret");
642
+ if (!config.clientSecret && !config.certificateContent) {
643
+ missingValues.push("clientSecret or certificateContent");
583
644
  }
584
645
  if (!config.tenantId) {
585
646
  missingValues.push("tenantId");
@@ -614,7 +675,7 @@ class OnBehalfOfUserCredential {
614
675
  *
615
676
  * @param {string} ssoToken - User token provided by Teams SSO feature.
616
677
  *
617
- * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, authority host or tenant id is not found in config.
678
+ * @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config.
618
679
  * @throws {@link ErrorCode|InternalError} when SSO token is not valid.
619
680
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
620
681
  *
@@ -630,10 +691,10 @@ class OnBehalfOfUserCredential {
630
691
  if (!((_b = config === null || config === void 0 ? void 0 : config.authentication) === null || _b === void 0 ? void 0 : _b.authorityHost)) {
631
692
  missingConfigurations.push("authorityHost");
632
693
  }
633
- if (!((_c = config === null || config === void 0 ? void 0 : config.authentication) === null || _c === void 0 ? void 0 : _c.clientSecret)) {
634
- missingConfigurations.push("clientSecret");
694
+ if (!((_c = config === null || config === void 0 ? void 0 : config.authentication) === null || _c === void 0 ? void 0 : _c.clientSecret) && !((_d = config === null || config === void 0 ? void 0 : config.authentication) === null || _d === void 0 ? void 0 : _d.certificateContent)) {
695
+ missingConfigurations.push("clientSecret or certificateContent");
635
696
  }
636
- if (!((_d = config === null || config === void 0 ? void 0 : config.authentication) === null || _d === void 0 ? void 0 : _d.tenantId)) {
697
+ if (!((_e = config === null || config === void 0 ? void 0 : config.authentication) === null || _e === void 0 ? void 0 : _e.tenantId)) {
637
698
  missingConfigurations.push("tenantId");
638
699
  }
639
700
  if (missingConfigurations.length != 0) {
@@ -641,15 +702,7 @@ class OnBehalfOfUserCredential {
641
702
  internalLogger.error(errorMsg);
642
703
  throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
643
704
  }
644
- const normalizedAuthorityHost = config.authentication.authorityHost.replace(/\/+$/g, "");
645
- const authority = normalizedAuthorityHost + "/" + ((_e = config.authentication) === null || _e === void 0 ? void 0 : _e.tenantId);
646
- this.msalClient = new msalNode.ConfidentialClientApplication({
647
- auth: {
648
- clientId: config.authentication.clientId,
649
- authority: authority,
650
- clientSecret: config.authentication.clientSecret,
651
- },
652
- });
705
+ this.msalClient = createConfidentialClientApplication(config.authentication);
653
706
  const decodedSsoToken = parseJwt(ssoToken);
654
707
  this.ssoToken = {
655
708
  token: ssoToken,
@@ -694,8 +747,7 @@ class OnBehalfOfUserCredential {
694
747
  getToken(scopes, options) {
695
748
  return tslib.__awaiter(this, void 0, void 0, function* () {
696
749
  validateScopesType(scopes);
697
- let scopesArray = typeof scopes === "string" ? scopes.split(" ") : scopes;
698
- scopesArray = scopesArray.filter((x) => x !== null && x !== "");
750
+ const scopesArray = getScopesArray(scopes);
699
751
  let result;
700
752
  if (!scopesArray.length) {
701
753
  internalLogger.info("Get SSO token.");