@microsoft/teamsfx 0.5.2-alpha.313131ea.0 → 0.5.2-alpha.e7b82d5e0.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/README.md +151 -83
- package/dist/index.esm2017.js +152 -185
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm2017.mjs +403 -344
- package/dist/index.esm2017.mjs.map +1 -1
- package/dist/index.esm5.js +159 -187
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +421 -360
- package/dist/index.node.cjs.js.map +1 -1
- package/package.json +3 -5
- package/types/teamsfx.d.ts +285 -231
package/dist/index.node.cjs.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var jwt_decode = require('jwt-decode');
|
|
6
5
|
var tslib = require('tslib');
|
|
6
|
+
var jwt_decode = require('jwt-decode');
|
|
7
7
|
var msalNode = require('@azure/msal-node');
|
|
8
8
|
var crypto = require('crypto');
|
|
9
9
|
var microsoftGraphClient = require('@microsoft/microsoft-graph-client');
|
|
@@ -72,6 +72,10 @@ exports.ErrorCode = void 0;
|
|
|
72
72
|
* Invalid response error.
|
|
73
73
|
*/
|
|
74
74
|
ErrorCode["InvalidResponse"] = "InvalidResponse";
|
|
75
|
+
/**
|
|
76
|
+
* Identity type error.
|
|
77
|
+
*/
|
|
78
|
+
ErrorCode["IdentityTypeNotSupported"] = "IdentityTypeNotSupported";
|
|
75
79
|
})(exports.ErrorCode || (exports.ErrorCode = {}));
|
|
76
80
|
/**
|
|
77
81
|
* @internal
|
|
@@ -91,6 +95,8 @@ ErrorMessage.NodejsRuntimeNotSupported = "{0} is not supported in Node.";
|
|
|
91
95
|
ErrorMessage.FailToAcquireTokenOnBehalfOfUser = "Failed to acquire access token on behalf of user: {0}";
|
|
92
96
|
// ChannelNotSupported Error
|
|
93
97
|
ErrorMessage.OnlyMSTeamsChannelSupported = "{0} is only supported in MS Teams Channel";
|
|
98
|
+
// IdentityTypeNotSupported Error
|
|
99
|
+
ErrorMessage.IdentityTypeNotSupported = "{0} identity is not supported in {1}";
|
|
94
100
|
/**
|
|
95
101
|
* Error class with code and message thrown by the SDK.
|
|
96
102
|
*
|
|
@@ -117,26 +123,6 @@ class ErrorWithCode extends Error {
|
|
|
117
123
|
}
|
|
118
124
|
}
|
|
119
125
|
|
|
120
|
-
// Copyright (c) Microsoft Corporation.
|
|
121
|
-
// Licensed under the MIT license.
|
|
122
|
-
/**
|
|
123
|
-
* Available resource type.
|
|
124
|
-
* @beta
|
|
125
|
-
*/
|
|
126
|
-
exports.ResourceType = void 0;
|
|
127
|
-
(function (ResourceType) {
|
|
128
|
-
/**
|
|
129
|
-
* SQL database.
|
|
130
|
-
*
|
|
131
|
-
*/
|
|
132
|
-
ResourceType[ResourceType["SQL"] = 0] = "SQL";
|
|
133
|
-
/**
|
|
134
|
-
* Rest API.
|
|
135
|
-
*
|
|
136
|
-
*/
|
|
137
|
-
ResourceType[ResourceType["API"] = 1] = "API";
|
|
138
|
-
})(exports.ResourceType || (exports.ResourceType = {}));
|
|
139
|
-
|
|
140
126
|
// Copyright (c) Microsoft Corporation.
|
|
141
127
|
// Licensed under the MIT license.
|
|
142
128
|
/**
|
|
@@ -379,131 +365,6 @@ function getScopesArray(scopes) {
|
|
|
379
365
|
function getAuthority(authorityHost, tenantId) {
|
|
380
366
|
const normalizedAuthorityHost = authorityHost.replace(/\/+$/g, "");
|
|
381
367
|
return normalizedAuthorityHost + "/" + tenantId;
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* @internal
|
|
385
|
-
*/
|
|
386
|
-
const isNode = typeof process !== "undefined" &&
|
|
387
|
-
!!process.version &&
|
|
388
|
-
!!process.versions &&
|
|
389
|
-
!!process.versions.node;
|
|
390
|
-
|
|
391
|
-
// Copyright (c) Microsoft Corporation.
|
|
392
|
-
/**
|
|
393
|
-
* Global configuration instance
|
|
394
|
-
*
|
|
395
|
-
*/
|
|
396
|
-
let config;
|
|
397
|
-
/**
|
|
398
|
-
* Initialize configuration from environment variables or configuration object and set the global instance
|
|
399
|
-
*
|
|
400
|
-
* @param {Configuration} configuration - Optional configuration that overrides the default configuration values. The override depth is 1.
|
|
401
|
-
*
|
|
402
|
-
* @throws {@link ErrorCode|InvalidParameter} when configuration is not passed in browser environment
|
|
403
|
-
*
|
|
404
|
-
* @beta
|
|
405
|
-
*/
|
|
406
|
-
function loadConfiguration(configuration) {
|
|
407
|
-
internalLogger.info("load configuration");
|
|
408
|
-
// browser environment
|
|
409
|
-
if (!isNode) {
|
|
410
|
-
if (!configuration) {
|
|
411
|
-
const errorMsg = "You are running the code in browser. Configuration must be passed in.";
|
|
412
|
-
internalLogger.error(errorMsg);
|
|
413
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidParameter);
|
|
414
|
-
}
|
|
415
|
-
config = configuration;
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
// node environment
|
|
419
|
-
let newAuthentication;
|
|
420
|
-
let newResources = [];
|
|
421
|
-
const defaultResourceName = "default";
|
|
422
|
-
if (configuration === null || configuration === void 0 ? void 0 : configuration.authentication) {
|
|
423
|
-
newAuthentication = configuration.authentication;
|
|
424
|
-
}
|
|
425
|
-
else {
|
|
426
|
-
newAuthentication = {
|
|
427
|
-
authorityHost: process.env.M365_AUTHORITY_HOST,
|
|
428
|
-
tenantId: process.env.M365_TENANT_ID,
|
|
429
|
-
clientId: process.env.M365_CLIENT_ID,
|
|
430
|
-
clientSecret: process.env.M365_CLIENT_SECRET,
|
|
431
|
-
simpleAuthEndpoint: process.env.SIMPLE_AUTH_ENDPOINT,
|
|
432
|
-
initiateLoginEndpoint: process.env.INITIATE_LOGIN_ENDPOINT,
|
|
433
|
-
applicationIdUri: process.env.M365_APPLICATION_ID_URI,
|
|
434
|
-
};
|
|
435
|
-
}
|
|
436
|
-
if (configuration === null || configuration === void 0 ? void 0 : configuration.resources) {
|
|
437
|
-
newResources = configuration.resources;
|
|
438
|
-
}
|
|
439
|
-
else {
|
|
440
|
-
newResources = [
|
|
441
|
-
{
|
|
442
|
-
// SQL resource
|
|
443
|
-
type: exports.ResourceType.SQL,
|
|
444
|
-
name: defaultResourceName,
|
|
445
|
-
properties: {
|
|
446
|
-
sqlServerEndpoint: process.env.SQL_ENDPOINT,
|
|
447
|
-
sqlUsername: process.env.SQL_USER_NAME,
|
|
448
|
-
sqlPassword: process.env.SQL_PASSWORD,
|
|
449
|
-
sqlDatabaseName: process.env.SQL_DATABASE_NAME,
|
|
450
|
-
sqlIdentityId: process.env.IDENTITY_ID,
|
|
451
|
-
},
|
|
452
|
-
},
|
|
453
|
-
{
|
|
454
|
-
// API resource
|
|
455
|
-
type: exports.ResourceType.API,
|
|
456
|
-
name: defaultResourceName,
|
|
457
|
-
properties: {
|
|
458
|
-
endpoint: process.env.API_ENDPOINT,
|
|
459
|
-
},
|
|
460
|
-
},
|
|
461
|
-
];
|
|
462
|
-
}
|
|
463
|
-
config = {
|
|
464
|
-
authentication: newAuthentication,
|
|
465
|
-
resources: newResources,
|
|
466
|
-
};
|
|
467
|
-
}
|
|
468
|
-
/**
|
|
469
|
-
* Get configuration for a specific resource.
|
|
470
|
-
* @param {ResourceType} resourceType - The type of resource
|
|
471
|
-
* @param {string} resourceName - The name of resource, default value is "default".
|
|
472
|
-
*
|
|
473
|
-
* @returns Resource configuration for target resource from global configuration instance.
|
|
474
|
-
*
|
|
475
|
-
* @throws {@link ErrorCode|InvalidConfiguration} when resource configuration with the specific type and name is not found
|
|
476
|
-
*
|
|
477
|
-
* @beta
|
|
478
|
-
*/
|
|
479
|
-
function getResourceConfiguration(resourceType, resourceName = "default") {
|
|
480
|
-
var _a;
|
|
481
|
-
internalLogger.info(`Get resource configuration of ${exports.ResourceType[resourceType]} from ${resourceName}`);
|
|
482
|
-
const result = (_a = config.resources) === null || _a === void 0 ? void 0 : _a.find((item) => item.type === resourceType && item.name === resourceName);
|
|
483
|
-
if (result) {
|
|
484
|
-
return result.properties;
|
|
485
|
-
}
|
|
486
|
-
const errorMsg = formatString(ErrorMessage.MissingResourceConfiguration, exports.ResourceType[resourceType], resourceName);
|
|
487
|
-
internalLogger.error(errorMsg);
|
|
488
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Get configuration for authentication.
|
|
492
|
-
*
|
|
493
|
-
* @returns Authentication configuration from global configuration instance, the value may be undefined if no authentication config exists in current environment.
|
|
494
|
-
*
|
|
495
|
-
* @throws {@link ErrorCode|InvalidConfiguration} when global configuration does not exist
|
|
496
|
-
*
|
|
497
|
-
* @beta
|
|
498
|
-
*/
|
|
499
|
-
function getAuthenticationConfiguration() {
|
|
500
|
-
internalLogger.info("Get authentication configuration");
|
|
501
|
-
if (config) {
|
|
502
|
-
return config.authentication;
|
|
503
|
-
}
|
|
504
|
-
const errorMsg = "Please call loadConfiguration() first before calling getAuthenticationConfiguration().";
|
|
505
|
-
internalLogger.error(errorMsg);
|
|
506
|
-
throw new ErrorWithCode(formatString(ErrorMessage.ConfigurationNotExists, errorMsg), exports.ErrorCode.InvalidConfiguration);
|
|
507
368
|
}
|
|
508
369
|
|
|
509
370
|
/**
|
|
@@ -557,7 +418,7 @@ function parseCertificate(certificateContent) {
|
|
|
557
418
|
* @example
|
|
558
419
|
* ```typescript
|
|
559
420
|
* loadConfiguration(); // load configuration from environment variables
|
|
560
|
-
* const credential = new
|
|
421
|
+
* const credential = new AppCredential();
|
|
561
422
|
* ```
|
|
562
423
|
*
|
|
563
424
|
* @remarks
|
|
@@ -565,21 +426,23 @@ function parseCertificate(certificateContent) {
|
|
|
565
426
|
*
|
|
566
427
|
* @beta
|
|
567
428
|
*/
|
|
568
|
-
class
|
|
429
|
+
class AppCredential {
|
|
569
430
|
/**
|
|
570
|
-
* Constructor of
|
|
431
|
+
* Constructor of AppCredential.
|
|
571
432
|
*
|
|
572
433
|
* @remarks
|
|
573
434
|
* Only works in in server side.
|
|
574
435
|
*
|
|
436
|
+
* @param {AuthenticationConfiguration} authConfig - The authentication configuration. Use environment variables if not provided.
|
|
437
|
+
*
|
|
575
438
|
* @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret or tenant id is not found in config.
|
|
576
439
|
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
577
440
|
*
|
|
578
441
|
* @beta
|
|
579
442
|
*/
|
|
580
|
-
constructor() {
|
|
443
|
+
constructor(authConfig) {
|
|
581
444
|
internalLogger.info("Create M365 tenant credential");
|
|
582
|
-
const config = this.loadAndValidateConfig();
|
|
445
|
+
const config = this.loadAndValidateConfig(authConfig);
|
|
583
446
|
this.msalClient = createConfidentialClientApplication(config);
|
|
584
447
|
}
|
|
585
448
|
/**
|
|
@@ -641,15 +504,13 @@ class M365TenantCredential {
|
|
|
641
504
|
}
|
|
642
505
|
/**
|
|
643
506
|
* Load and validate authentication configuration
|
|
507
|
+
*
|
|
508
|
+
* @param {AuthenticationConfiguration} authConfig - The authentication configuration. Use environment variables if not provided.
|
|
509
|
+
*
|
|
644
510
|
* @returns Authentication configuration
|
|
645
511
|
*/
|
|
646
|
-
loadAndValidateConfig() {
|
|
512
|
+
loadAndValidateConfig(config) {
|
|
647
513
|
internalLogger.verbose("Validate authentication configuration");
|
|
648
|
-
const config = getAuthenticationConfiguration();
|
|
649
|
-
if (!config) {
|
|
650
|
-
internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);
|
|
651
|
-
throw new ErrorWithCode(ErrorMessage.AuthenticationConfigurationNotExists, exports.ErrorCode.InvalidConfiguration);
|
|
652
|
-
}
|
|
653
514
|
if (config.clientId && (config.clientSecret || config.certificateContent) && config.tenantId) {
|
|
654
515
|
return config;
|
|
655
516
|
}
|
|
@@ -675,7 +536,6 @@ class M365TenantCredential {
|
|
|
675
536
|
*
|
|
676
537
|
* @example
|
|
677
538
|
* ```typescript
|
|
678
|
-
* loadConfiguration(); // load configuration from environment variables
|
|
679
539
|
* const credential = new OnBehalfOfUserCredential(ssoToken);
|
|
680
540
|
* ```
|
|
681
541
|
*
|
|
@@ -692,6 +552,7 @@ class OnBehalfOfUserCredential {
|
|
|
692
552
|
* Only works in in server side.
|
|
693
553
|
*
|
|
694
554
|
* @param {string} ssoToken - User token provided by Teams SSO feature.
|
|
555
|
+
* @param {AuthenticationConfiguration} config - The authentication configuration. Use environment variables if not provided.
|
|
695
556
|
*
|
|
696
557
|
* @throws {@link ErrorCode|InvalidConfiguration} when client id, client secret, certificate content, authority host or tenant id is not found in config.
|
|
697
558
|
* @throws {@link ErrorCode|InternalError} when SSO token is not valid.
|
|
@@ -699,20 +560,19 @@ class OnBehalfOfUserCredential {
|
|
|
699
560
|
*
|
|
700
561
|
* @beta
|
|
701
562
|
*/
|
|
702
|
-
constructor(ssoToken) {
|
|
703
|
-
var _a, _b, _c, _d, _e;
|
|
563
|
+
constructor(ssoToken, config) {
|
|
704
564
|
internalLogger.info("Get on behalf of user credential");
|
|
705
565
|
const missingConfigurations = [];
|
|
706
|
-
if (!
|
|
566
|
+
if (!config.clientId) {
|
|
707
567
|
missingConfigurations.push("clientId");
|
|
708
568
|
}
|
|
709
|
-
if (!
|
|
569
|
+
if (!config.authorityHost) {
|
|
710
570
|
missingConfigurations.push("authorityHost");
|
|
711
571
|
}
|
|
712
|
-
if (!
|
|
572
|
+
if (!config.clientSecret && !config.certificateContent) {
|
|
713
573
|
missingConfigurations.push("clientSecret or certificateContent");
|
|
714
574
|
}
|
|
715
|
-
if (!
|
|
575
|
+
if (!config.tenantId) {
|
|
716
576
|
missingConfigurations.push("tenantId");
|
|
717
577
|
}
|
|
718
578
|
if (missingConfigurations.length != 0) {
|
|
@@ -720,7 +580,7 @@ class OnBehalfOfUserCredential {
|
|
|
720
580
|
internalLogger.error(errorMsg);
|
|
721
581
|
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
|
722
582
|
}
|
|
723
|
-
this.msalClient = createConfidentialClientApplication(config
|
|
583
|
+
this.msalClient = createConfidentialClientApplication(config);
|
|
724
584
|
const decodedSsoToken = parseJwt(ssoToken);
|
|
725
585
|
this.ssoToken = {
|
|
726
586
|
token: ssoToken,
|
|
@@ -856,7 +716,7 @@ class TeamsUserCredential {
|
|
|
856
716
|
* Can only be used within Teams.
|
|
857
717
|
* @beta
|
|
858
718
|
*/
|
|
859
|
-
constructor() {
|
|
719
|
+
constructor(authConfig) {
|
|
860
720
|
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "TeamsUserCredential"), exports.ErrorCode.RuntimeNotSupported);
|
|
861
721
|
}
|
|
862
722
|
/**
|
|
@@ -903,7 +763,7 @@ class MsGraphAuthProvider {
|
|
|
903
763
|
/**
|
|
904
764
|
* Constructor of MsGraphAuthProvider.
|
|
905
765
|
*
|
|
906
|
-
* @param {
|
|
766
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth.
|
|
907
767
|
* @param {string | string[]} scopes - The list of scopes for which the token will have access.
|
|
908
768
|
*
|
|
909
769
|
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
@@ -912,8 +772,8 @@ class MsGraphAuthProvider {
|
|
|
912
772
|
*
|
|
913
773
|
* @beta
|
|
914
774
|
*/
|
|
915
|
-
constructor(
|
|
916
|
-
this.
|
|
775
|
+
constructor(teamsfx, scopes) {
|
|
776
|
+
this.teamsfx = teamsfx;
|
|
917
777
|
let scopesStr = defaultScope;
|
|
918
778
|
if (scopes) {
|
|
919
779
|
validateScopesType(scopes);
|
|
@@ -940,7 +800,7 @@ class MsGraphAuthProvider {
|
|
|
940
800
|
getAccessToken() {
|
|
941
801
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
942
802
|
internalLogger.info(`Get Graph Access token with scopes: '${this.scopes}'`);
|
|
943
|
-
const accessToken = yield this.
|
|
803
|
+
const accessToken = yield this.teamsfx.getCredential().getToken(this.scopes);
|
|
944
804
|
return new Promise((resolve, reject) => {
|
|
945
805
|
if (accessToken) {
|
|
946
806
|
resolve(accessToken.token);
|
|
@@ -998,7 +858,7 @@ class MsGraphAuthProvider {
|
|
|
998
858
|
* }
|
|
999
859
|
* ```
|
|
1000
860
|
*
|
|
1001
|
-
* @param {
|
|
861
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth.
|
|
1002
862
|
* @param scopes - The array of Microsoft Token scope of access. Default value is `[.default]`.
|
|
1003
863
|
*
|
|
1004
864
|
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
@@ -1007,9 +867,9 @@ class MsGraphAuthProvider {
|
|
|
1007
867
|
*
|
|
1008
868
|
* @beta
|
|
1009
869
|
*/
|
|
1010
|
-
function createMicrosoftGraphClient(
|
|
870
|
+
function createMicrosoftGraphClient(teamsfx, scopes) {
|
|
1011
871
|
internalLogger.info("Create Microsoft Graph Client");
|
|
1012
|
-
const authProvider = new MsGraphAuthProvider(
|
|
872
|
+
const authProvider = new MsGraphAuthProvider(teamsfx, scopes);
|
|
1013
873
|
const graphClient = microsoftGraphClient.Client.initWithMiddleware({
|
|
1014
874
|
authProvider,
|
|
1015
875
|
});
|
|
@@ -1018,176 +878,165 @@ function createMicrosoftGraphClient(credential, scopes) {
|
|
|
1018
878
|
|
|
1019
879
|
// Copyright (c) Microsoft Corporation.
|
|
1020
880
|
/**
|
|
1021
|
-
*
|
|
1022
|
-
*
|
|
1023
|
-
|
|
881
|
+
* MSSQL default scope
|
|
882
|
+
* https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi
|
|
883
|
+
*/
|
|
884
|
+
const defaultSQLScope = "https://database.windows.net/";
|
|
885
|
+
/**
|
|
886
|
+
* Generate connection configuration consumed by tedious.
|
|
1024
887
|
*
|
|
1025
|
-
* @
|
|
888
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth
|
|
889
|
+
* @param { string? } databaseName - specify database name to override default one if there are multiple databases.
|
|
890
|
+
*
|
|
891
|
+
* @returns Connection configuration of tedious for the SQL.
|
|
1026
892
|
*
|
|
893
|
+
* @throws {@link ErrorCode|InvalidConfiguration} when SQL config resource configuration is invalid.
|
|
894
|
+
* @throws {@link ErrorCode|InternalError} when get user MSI token failed or MSI token is invalid.
|
|
895
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
896
|
+
*
|
|
897
|
+
* @beta
|
|
1027
898
|
*/
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
*/
|
|
1034
|
-
this.defaultSQLScope = "https://database.windows.net/";
|
|
1035
|
-
}
|
|
1036
|
-
/**
|
|
1037
|
-
* Generate connection configuration consumed by tedious.
|
|
1038
|
-
*
|
|
1039
|
-
* @param { string? } databaseName - specify database name to override default one if there are multiple databases.
|
|
1040
|
-
*
|
|
1041
|
-
* @returns Connection configuration of tedious for the SQL.
|
|
1042
|
-
*
|
|
1043
|
-
* @throws {@link ErrorCode|InvalidConfiguration} when SQL config resource configuration is invalid.
|
|
1044
|
-
* @throws {@link ErrorCode|InternalError} when get user MSI token failed or MSI token is invalid.
|
|
1045
|
-
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
|
|
1046
|
-
*
|
|
1047
|
-
* @beta
|
|
1048
|
-
*/
|
|
1049
|
-
getConfig(databaseName) {
|
|
1050
|
-
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1051
|
-
internalLogger.info("Get SQL configuration");
|
|
1052
|
-
const configuration = getResourceConfiguration(exports.ResourceType.SQL);
|
|
1053
|
-
if (!configuration) {
|
|
1054
|
-
const errMsg = "SQL resource configuration not exist";
|
|
1055
|
-
internalLogger.error(errMsg);
|
|
1056
|
-
throw new ErrorWithCode(errMsg, exports.ErrorCode.InvalidConfiguration);
|
|
1057
|
-
}
|
|
1058
|
-
try {
|
|
1059
|
-
this.isSQLConfigurationValid(configuration);
|
|
1060
|
-
}
|
|
1061
|
-
catch (err) {
|
|
1062
|
-
throw err;
|
|
1063
|
-
}
|
|
1064
|
-
if (!this.isMsiAuthentication()) {
|
|
1065
|
-
const configWithUPS = this.generateDefaultConfig(configuration, databaseName);
|
|
1066
|
-
internalLogger.verbose("SQL configuration with username and password generated");
|
|
1067
|
-
return configWithUPS;
|
|
1068
|
-
}
|
|
1069
|
-
try {
|
|
1070
|
-
const configWithToken = yield this.generateTokenConfig(configuration, databaseName);
|
|
1071
|
-
internalLogger.verbose("SQL configuration with MSI token generated");
|
|
1072
|
-
return configWithToken;
|
|
1073
|
-
}
|
|
1074
|
-
catch (error) {
|
|
1075
|
-
throw error;
|
|
1076
|
-
}
|
|
1077
|
-
});
|
|
1078
|
-
}
|
|
1079
|
-
/**
|
|
1080
|
-
* Check SQL use MSI identity or username and password.
|
|
1081
|
-
*
|
|
1082
|
-
* @returns false - login with SQL MSI identity, true - login with username and password.
|
|
1083
|
-
* @internal
|
|
1084
|
-
*/
|
|
1085
|
-
isMsiAuthentication() {
|
|
1086
|
-
internalLogger.verbose("Check connection config using MSI access token or username and password");
|
|
1087
|
-
const configuration = getResourceConfiguration(exports.ResourceType.SQL);
|
|
1088
|
-
if ((configuration === null || configuration === void 0 ? void 0 : configuration.sqlUsername) != null && (configuration === null || configuration === void 0 ? void 0 : configuration.sqlPassword) != null) {
|
|
1089
|
-
internalLogger.verbose("Login with username and password");
|
|
1090
|
-
return false;
|
|
899
|
+
function getTediousConnectionConfig(teamsfx, databaseName) {
|
|
900
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
901
|
+
internalLogger.info("Get SQL configuration");
|
|
902
|
+
try {
|
|
903
|
+
isSQLConfigurationValid(teamsfx);
|
|
1091
904
|
}
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
}
|
|
1095
|
-
/**
|
|
1096
|
-
* check configuration is an available configurations.
|
|
1097
|
-
* @param { SqlConfiguration } sqlConfig
|
|
1098
|
-
*
|
|
1099
|
-
* @returns true - SQL configuration has a valid SQL endpoints, SQL username with password or identity ID.
|
|
1100
|
-
* false - configuration is not valid.
|
|
1101
|
-
* @internal
|
|
1102
|
-
*/
|
|
1103
|
-
isSQLConfigurationValid(sqlConfig) {
|
|
1104
|
-
internalLogger.verbose("Check SQL configuration if valid");
|
|
1105
|
-
if (!sqlConfig.sqlServerEndpoint) {
|
|
1106
|
-
internalLogger.error("SQL configuration is not valid without SQL server endpoint exist");
|
|
1107
|
-
throw new ErrorWithCode("SQL configuration error without SQL server endpoint exist", exports.ErrorCode.InvalidConfiguration);
|
|
905
|
+
catch (err) {
|
|
906
|
+
throw err;
|
|
1108
907
|
}
|
|
1109
|
-
if (!(sqlConfig.sqlUsername && sqlConfig.sqlPassword) && !sqlConfig.sqlIdentityId) {
|
|
1110
|
-
const errMsg = `SQL configuration is not valid without ${sqlConfig.sqlIdentityId ? "" : "identity id "} ${sqlConfig.sqlUsername ? "" : "SQL username "} ${sqlConfig.sqlPassword ? "" : "SQL password"} exist`;
|
|
1111
|
-
internalLogger.error(errMsg);
|
|
1112
|
-
throw new ErrorWithCode(errMsg, exports.ErrorCode.InvalidConfiguration);
|
|
1113
|
-
}
|
|
1114
|
-
internalLogger.verbose("SQL configuration is valid");
|
|
1115
|
-
}
|
|
1116
|
-
/**
|
|
1117
|
-
* Generate tedious connection configuration with default authentication type.
|
|
1118
|
-
*
|
|
1119
|
-
* @param { SqlConfiguration } SQL configuration with username and password.
|
|
1120
|
-
*
|
|
1121
|
-
* @returns Tedious connection configuration with username and password.
|
|
1122
|
-
* @internal
|
|
1123
|
-
*/
|
|
1124
|
-
generateDefaultConfig(sqlConfig, databaseName) {
|
|
1125
908
|
if (databaseName === "") {
|
|
1126
909
|
internalLogger.warn(`SQL database name is empty string`);
|
|
1127
910
|
}
|
|
1128
|
-
const dbName = databaseName !== null && databaseName !== void 0 ? databaseName :
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
911
|
+
const dbName = databaseName !== null && databaseName !== void 0 ? databaseName : (teamsfx.hasConfig("sqlDatabaseName") ? teamsfx.getConfig("sqlDatabaseName") : undefined);
|
|
912
|
+
if (!isMsiAuthentication(teamsfx)) {
|
|
913
|
+
const configWithUPS = generateDefaultConfig(teamsfx, dbName);
|
|
914
|
+
internalLogger.verbose("SQL configuration with username and password generated");
|
|
915
|
+
return configWithUPS;
|
|
916
|
+
}
|
|
917
|
+
try {
|
|
918
|
+
const configWithToken = yield generateTokenConfig(teamsfx, dbName);
|
|
919
|
+
internalLogger.verbose("SQL configuration with MSI token generated");
|
|
920
|
+
return configWithToken;
|
|
921
|
+
}
|
|
922
|
+
catch (error) {
|
|
923
|
+
throw error;
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
}
|
|
927
|
+
/**
|
|
928
|
+
* check configuration is an available configurations.
|
|
929
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth
|
|
930
|
+
*
|
|
931
|
+
* @returns true - SQL configuration has a valid SQL endpoints, SQL username with password or identity ID.
|
|
932
|
+
* false - configuration is not valid.
|
|
933
|
+
* @internal
|
|
934
|
+
*/
|
|
935
|
+
function isSQLConfigurationValid(teamsfx) {
|
|
936
|
+
internalLogger.verbose("Check SQL configuration if valid");
|
|
937
|
+
if (!teamsfx.hasConfig("sqlServerEndpoint")) {
|
|
938
|
+
internalLogger.error("SQL configuration is not valid without SQL server endpoint exist");
|
|
939
|
+
throw new ErrorWithCode("SQL configuration error without SQL server endpoint exist", exports.ErrorCode.InvalidConfiguration);
|
|
940
|
+
}
|
|
941
|
+
if (!(teamsfx.hasConfig("sqlUsername") && teamsfx.hasConfig("sqlPassword")) &&
|
|
942
|
+
!teamsfx.hasConfig("sqlIdentityId")) {
|
|
943
|
+
const errMsg = `SQL configuration is not valid without ${teamsfx.hasConfig("sqlIdentityId") ? "" : "identity id "} ${teamsfx.hasConfig("sqlUsername") ? "" : "SQL username "} ${teamsfx.hasConfig("sqlPassword") ? "" : "SQL password"} exist`;
|
|
944
|
+
internalLogger.error(errMsg);
|
|
945
|
+
throw new ErrorWithCode(errMsg, exports.ErrorCode.InvalidConfiguration);
|
|
946
|
+
}
|
|
947
|
+
internalLogger.verbose("SQL configuration is valid");
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Check SQL use MSI identity or username and password.
|
|
951
|
+
*
|
|
952
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth
|
|
953
|
+
*
|
|
954
|
+
* @returns false - login with SQL MSI identity, true - login with username and password.
|
|
955
|
+
* @internal
|
|
956
|
+
*/
|
|
957
|
+
function isMsiAuthentication(teamsfx) {
|
|
958
|
+
internalLogger.verbose("Check connection config using MSI access token or username and password");
|
|
959
|
+
if (teamsfx.hasConfig("sqlUsername") && teamsfx.hasConfig("sqlPassword")) {
|
|
960
|
+
internalLogger.verbose("Login with username and password");
|
|
961
|
+
return false;
|
|
962
|
+
}
|
|
963
|
+
internalLogger.verbose("Login with MSI identity");
|
|
964
|
+
return true;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Generate tedious connection configuration with default authentication type.
|
|
968
|
+
*
|
|
969
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth
|
|
970
|
+
* @param { string? } databaseName - specify database name to override default one if there are multiple databases.
|
|
971
|
+
*
|
|
972
|
+
* @returns Tedious connection configuration with username and password.
|
|
973
|
+
* @internal
|
|
974
|
+
*/
|
|
975
|
+
function generateDefaultConfig(teamsfx, databaseName) {
|
|
976
|
+
internalLogger.verbose(`SQL server ${teamsfx.getConfig("sqlServerEndpoint")}
|
|
977
|
+
, user name ${teamsfx.getConfig("sqlUsername")}
|
|
978
|
+
, database name ${databaseName}`);
|
|
979
|
+
const config = {
|
|
980
|
+
server: teamsfx.getConfig("sqlServerEndpoint"),
|
|
981
|
+
authentication: {
|
|
982
|
+
type: TediousAuthenticationType.default,
|
|
1139
983
|
options: {
|
|
1140
|
-
|
|
1141
|
-
|
|
984
|
+
userName: teamsfx.getConfig("sqlUsername"),
|
|
985
|
+
password: teamsfx.getConfig("sqlPassword"),
|
|
1142
986
|
},
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
},
|
|
1178
|
-
},
|
|
987
|
+
},
|
|
988
|
+
options: {
|
|
989
|
+
database: databaseName,
|
|
990
|
+
encrypt: true,
|
|
991
|
+
},
|
|
992
|
+
};
|
|
993
|
+
return config;
|
|
994
|
+
}
|
|
995
|
+
/**
|
|
996
|
+
* Generate tedious connection configuration with azure-active-directory-access-token authentication type.
|
|
997
|
+
*
|
|
998
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth
|
|
999
|
+
*
|
|
1000
|
+
* @returns Tedious connection configuration with access token.
|
|
1001
|
+
* @internal
|
|
1002
|
+
*/
|
|
1003
|
+
function generateTokenConfig(teamsfx, databaseName) {
|
|
1004
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1005
|
+
internalLogger.verbose("Generate tedious config with MSI token");
|
|
1006
|
+
let token;
|
|
1007
|
+
try {
|
|
1008
|
+
const credential = new identity.ManagedIdentityCredential(teamsfx.getConfig("sqlIdentityId"));
|
|
1009
|
+
token = yield credential.getToken(defaultSQLScope);
|
|
1010
|
+
}
|
|
1011
|
+
catch (error) {
|
|
1012
|
+
const errMsg = "Get user MSI token failed";
|
|
1013
|
+
internalLogger.error(errMsg);
|
|
1014
|
+
throw new ErrorWithCode(errMsg, exports.ErrorCode.InternalError);
|
|
1015
|
+
}
|
|
1016
|
+
if (token) {
|
|
1017
|
+
const config = {
|
|
1018
|
+
server: teamsfx.getConfig("sqlServerEndpoint"),
|
|
1019
|
+
authentication: {
|
|
1020
|
+
type: TediousAuthenticationType.MSI,
|
|
1179
1021
|
options: {
|
|
1180
|
-
|
|
1181
|
-
encrypt: true,
|
|
1022
|
+
token: token.token,
|
|
1182
1023
|
},
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1024
|
+
},
|
|
1025
|
+
options: {
|
|
1026
|
+
database: databaseName,
|
|
1027
|
+
encrypt: true,
|
|
1028
|
+
},
|
|
1029
|
+
};
|
|
1030
|
+
internalLogger.verbose(`Generate token configuration success
|
|
1031
|
+
, server endpoint is ${teamsfx.getConfig("sqlServerEndpoint")}
|
|
1032
|
+
, database name is ${databaseName}`);
|
|
1033
|
+
return config;
|
|
1034
|
+
}
|
|
1035
|
+
internalLogger.error(`Generate token configuration
|
|
1036
|
+
, server endpoint is ${teamsfx.getConfig("sqlServerEndpoint")}
|
|
1037
|
+
, MSI token is not valid`);
|
|
1038
|
+
throw new ErrorWithCode("MSI token is not valid", exports.ErrorCode.InternalError);
|
|
1039
|
+
});
|
|
1191
1040
|
}
|
|
1192
1041
|
/**
|
|
1193
1042
|
* tedious connection config authentication type.
|
|
@@ -1200,6 +1049,25 @@ var TediousAuthenticationType;
|
|
|
1200
1049
|
TediousAuthenticationType["MSI"] = "azure-active-directory-access-token";
|
|
1201
1050
|
})(TediousAuthenticationType || (TediousAuthenticationType = {}));
|
|
1202
1051
|
|
|
1052
|
+
// Copyright (c) Microsoft Corporation.
|
|
1053
|
+
// Licensed under the MIT license.
|
|
1054
|
+
/**
|
|
1055
|
+
* Identity type to use in authentication.
|
|
1056
|
+
*
|
|
1057
|
+
* @beta
|
|
1058
|
+
*/
|
|
1059
|
+
exports.IdentityType = void 0;
|
|
1060
|
+
(function (IdentityType) {
|
|
1061
|
+
/**
|
|
1062
|
+
* Represents the current user of Teams.
|
|
1063
|
+
*/
|
|
1064
|
+
IdentityType["User"] = "User";
|
|
1065
|
+
/**
|
|
1066
|
+
* Represents the application itself.
|
|
1067
|
+
*/
|
|
1068
|
+
IdentityType["App"] = "Application";
|
|
1069
|
+
})(exports.IdentityType || (exports.IdentityType = {}));
|
|
1070
|
+
|
|
1203
1071
|
// Copyright (c) Microsoft Corporation.
|
|
1204
1072
|
const invokeResponseType = "invokeResponse";
|
|
1205
1073
|
/**
|
|
@@ -1239,7 +1107,6 @@ class TokenExchangeInvokeResponse {
|
|
|
1239
1107
|
* const dialogState = convoState.createProperty('dialogState');
|
|
1240
1108
|
* const dialogs = new DialogSet(dialogState);
|
|
1241
1109
|
*
|
|
1242
|
-
* loadConfiguration();
|
|
1243
1110
|
* dialogs.add(new TeamsBotSsoPrompt('TeamsBotSsoPrompt', {
|
|
1244
1111
|
* scopes: ["User.Read"],
|
|
1245
1112
|
* }));
|
|
@@ -1268,6 +1135,7 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1268
1135
|
/**
|
|
1269
1136
|
* Constructor of TeamsBotSsoPrompt.
|
|
1270
1137
|
*
|
|
1138
|
+
* @param {TeamsFx} teamsfx - Used to provide configuration and auth
|
|
1271
1139
|
* @param dialogId Unique ID of the dialog within its parent `DialogSet` or `ComponentDialog`.
|
|
1272
1140
|
* @param settings Settings used to configure the prompt.
|
|
1273
1141
|
*
|
|
@@ -1276,10 +1144,12 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1276
1144
|
*
|
|
1277
1145
|
* @beta
|
|
1278
1146
|
*/
|
|
1279
|
-
constructor(dialogId, settings) {
|
|
1147
|
+
constructor(teamsfx, dialogId, settings) {
|
|
1280
1148
|
super(dialogId);
|
|
1149
|
+
this.teamsfx = teamsfx;
|
|
1281
1150
|
this.settings = settings;
|
|
1282
1151
|
validateScopesType(settings.scopes);
|
|
1152
|
+
this.loadAndValidateConfig();
|
|
1283
1153
|
internalLogger.info("Create a new Teams Bot SSO Prompt");
|
|
1284
1154
|
}
|
|
1285
1155
|
/**
|
|
@@ -1384,6 +1254,31 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1384
1254
|
}
|
|
1385
1255
|
});
|
|
1386
1256
|
}
|
|
1257
|
+
loadAndValidateConfig() {
|
|
1258
|
+
if (this.teamsfx.getIdentityType() !== exports.IdentityType.User) {
|
|
1259
|
+
const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported, this.teamsfx.getIdentityType().toString(), "TeamsBotSsoPrompt");
|
|
1260
|
+
internalLogger.error(errorMsg);
|
|
1261
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.IdentityTypeNotSupported);
|
|
1262
|
+
}
|
|
1263
|
+
const missingConfigurations = [];
|
|
1264
|
+
if (!this.teamsfx.hasConfig("initiateLoginEndpoint")) {
|
|
1265
|
+
missingConfigurations.push("initiateLoginEndpoint");
|
|
1266
|
+
}
|
|
1267
|
+
if (!this.teamsfx.hasConfig("clientId")) {
|
|
1268
|
+
missingConfigurations.push("clientId");
|
|
1269
|
+
}
|
|
1270
|
+
if (!this.teamsfx.hasConfig("tenantId")) {
|
|
1271
|
+
missingConfigurations.push("tenantId");
|
|
1272
|
+
}
|
|
1273
|
+
if (!this.teamsfx.hasConfig("applicationIdUri")) {
|
|
1274
|
+
missingConfigurations.push("applicationIdUri");
|
|
1275
|
+
}
|
|
1276
|
+
if (missingConfigurations.length != 0) {
|
|
1277
|
+
const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingConfigurations.join(", "), "undefined");
|
|
1278
|
+
internalLogger.error(errorMsg);
|
|
1279
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1387
1282
|
/**
|
|
1388
1283
|
* Ensure bot is running in MS Teams since TeamsBotSsoPrompt is only supported in MS Teams channel.
|
|
1389
1284
|
* @param dc dialog context
|
|
@@ -1425,31 +1320,12 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1425
1320
|
* @internal
|
|
1426
1321
|
*/
|
|
1427
1322
|
getSignInResource(loginHint) {
|
|
1428
|
-
var _a, _b, _c, _d, _e;
|
|
1429
1323
|
internalLogger.verbose("Get sign in authentication configuration");
|
|
1430
|
-
const
|
|
1431
|
-
if (!((_a = config === null || config === void 0 ? void 0 : config.authentication) === null || _a === void 0 ? void 0 : _a.initiateLoginEndpoint)) {
|
|
1432
|
-
missingConfigurations.push("initiateLoginEndpoint");
|
|
1433
|
-
}
|
|
1434
|
-
if (!((_b = config === null || config === void 0 ? void 0 : config.authentication) === null || _b === void 0 ? void 0 : _b.clientId)) {
|
|
1435
|
-
missingConfigurations.push("clientId");
|
|
1436
|
-
}
|
|
1437
|
-
if (!((_c = config === null || config === void 0 ? void 0 : config.authentication) === null || _c === void 0 ? void 0 : _c.tenantId)) {
|
|
1438
|
-
missingConfigurations.push("tenantId");
|
|
1439
|
-
}
|
|
1440
|
-
if (!((_d = config === null || config === void 0 ? void 0 : config.authentication) === null || _d === void 0 ? void 0 : _d.applicationIdUri)) {
|
|
1441
|
-
missingConfigurations.push("applicationIdUri");
|
|
1442
|
-
}
|
|
1443
|
-
if (missingConfigurations.length != 0) {
|
|
1444
|
-
const errorMsg = formatString(ErrorMessage.InvalidConfiguration, missingConfigurations.join(", "), "undefined");
|
|
1445
|
-
internalLogger.error(errorMsg);
|
|
1446
|
-
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidConfiguration);
|
|
1447
|
-
}
|
|
1448
|
-
const signInLink = `${config.authentication.initiateLoginEndpoint}?scope=${encodeURI(this.settings.scopes.join(" "))}&clientId=${config.authentication.clientId}&tenantId=${config.authentication.tenantId}&loginHint=${loginHint}`;
|
|
1324
|
+
const signInLink = `${this.teamsfx.getConfig("initiateLoginEndpoint")}?scope=${encodeURI(this.settings.scopes.join(" "))}&clientId=${this.teamsfx.getConfig("clientId")}&tenantId=${this.teamsfx.getConfig("tenantId")}&loginHint=${loginHint}`;
|
|
1449
1325
|
internalLogger.verbose("Sign in link: " + signInLink);
|
|
1450
1326
|
const tokenExchangeResource = {
|
|
1451
1327
|
id: uuid.v4(),
|
|
1452
|
-
uri:
|
|
1328
|
+
uri: this.teamsfx.getConfig("applicationIdUri").replace(/\/$/, "") + "/access_as_user",
|
|
1453
1329
|
};
|
|
1454
1330
|
internalLogger.verbose("Token exchange resource uri: " + tokenExchangeResource.uri);
|
|
1455
1331
|
return {
|
|
@@ -1474,7 +1350,8 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1474
1350
|
}
|
|
1475
1351
|
else {
|
|
1476
1352
|
const ssoToken = context.activity.value.token;
|
|
1477
|
-
|
|
1353
|
+
this.teamsfx.setSsoToken(ssoToken);
|
|
1354
|
+
const credential = this.teamsfx.getCredential();
|
|
1478
1355
|
let exchangedToken;
|
|
1479
1356
|
try {
|
|
1480
1357
|
exchangedToken = yield credential.getToken(this.settings.scopes);
|
|
@@ -1539,18 +1416,202 @@ class TeamsBotSsoPrompt extends botbuilderDialogs.Dialog {
|
|
|
1539
1416
|
}
|
|
1540
1417
|
}
|
|
1541
1418
|
|
|
1542
|
-
|
|
1419
|
+
// Copyright (c) Microsoft Corporation.
|
|
1420
|
+
/**
|
|
1421
|
+
* A class providing credential and configuration.
|
|
1422
|
+
* @beta
|
|
1423
|
+
*/
|
|
1424
|
+
class TeamsFx {
|
|
1425
|
+
/**
|
|
1426
|
+
* Constructor of TeamsFx
|
|
1427
|
+
*
|
|
1428
|
+
* @param {IdentityType} identityType - Choose user or app identity
|
|
1429
|
+
* @param customConfig - key/value pairs of customized configuration that overrides default ones.
|
|
1430
|
+
*
|
|
1431
|
+
* @throws {@link ErrorCode|IdentityTypeNotSupported} when setting app identity in browser.
|
|
1432
|
+
*
|
|
1433
|
+
* @beta
|
|
1434
|
+
*/
|
|
1435
|
+
constructor(identityType, customConfig) {
|
|
1436
|
+
this.identityType = identityType !== null && identityType !== void 0 ? identityType : exports.IdentityType.User;
|
|
1437
|
+
this.configuration = new Map();
|
|
1438
|
+
this.loadFromEnv();
|
|
1439
|
+
if (customConfig) {
|
|
1440
|
+
for (const key of Object.keys(customConfig)) {
|
|
1441
|
+
const value = customConfig[key];
|
|
1442
|
+
if (value) {
|
|
1443
|
+
this.configuration.set(key, value);
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Identity type set by user.
|
|
1450
|
+
*
|
|
1451
|
+
* @returns identity type.
|
|
1452
|
+
* @beta
|
|
1453
|
+
*/
|
|
1454
|
+
getIdentityType() {
|
|
1455
|
+
return this.identityType;
|
|
1456
|
+
}
|
|
1457
|
+
/**
|
|
1458
|
+
* Credential instance according to identity type choice.
|
|
1459
|
+
*
|
|
1460
|
+
* @remarks If user identity is chose, will return {@link TeamsUserCredential}
|
|
1461
|
+
* in browser environment and {@link OnBehalfOfUserCredential} in NodeJS. If app
|
|
1462
|
+
* identity is chose, will return {@link AppCredential}.
|
|
1463
|
+
*
|
|
1464
|
+
* @returns instance implements TokenCredential interface.
|
|
1465
|
+
* @beta
|
|
1466
|
+
*/
|
|
1467
|
+
getCredential() {
|
|
1468
|
+
if (this.identityType === exports.IdentityType.User) {
|
|
1469
|
+
if (this.oboUserCredential) {
|
|
1470
|
+
return this.oboUserCredential;
|
|
1471
|
+
}
|
|
1472
|
+
const errorMsg = "SSO token is required to user identity. Please use setSsoToken().";
|
|
1473
|
+
internalLogger.error(errorMsg);
|
|
1474
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InvalidParameter);
|
|
1475
|
+
}
|
|
1476
|
+
else {
|
|
1477
|
+
if (!this.appCredential) {
|
|
1478
|
+
this.appCredential = new AppCredential(Object.fromEntries(this.configuration));
|
|
1479
|
+
}
|
|
1480
|
+
return this.appCredential;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Get user information.
|
|
1485
|
+
* @returns UserInfo object.
|
|
1486
|
+
* @beta
|
|
1487
|
+
*/
|
|
1488
|
+
getUserInfo() {
|
|
1489
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1490
|
+
if (this.identityType !== exports.IdentityType.User) {
|
|
1491
|
+
const errorMsg = formatString(ErrorMessage.IdentityTypeNotSupported, this.identityType.toString(), "TeamsFx");
|
|
1492
|
+
internalLogger.error(errorMsg);
|
|
1493
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.IdentityTypeNotSupported);
|
|
1494
|
+
}
|
|
1495
|
+
return Promise.resolve(this.getCredential().getUserInfo());
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
* Popup login page to get user's access token with specific scopes.
|
|
1500
|
+
*
|
|
1501
|
+
* @remarks
|
|
1502
|
+
* Only works in Teams client APP. User will be redirected to the authorization page to login and consent.
|
|
1503
|
+
*
|
|
1504
|
+
* @example
|
|
1505
|
+
* ```typescript
|
|
1506
|
+
* await teamsfx.login(["https://graph.microsoft.com/User.Read"]); // single scope using string array
|
|
1507
|
+
* await teamsfx.login("https://graph.microsoft.com/User.Read"); // single scopes using string
|
|
1508
|
+
* await teamsfx.login(["https://graph.microsoft.com/User.Read", "Calendars.Read"]); // multiple scopes using string array
|
|
1509
|
+
* await teamsfx.login("https://graph.microsoft.com/User.Read Calendars.Read"); // multiple scopes using string
|
|
1510
|
+
* ```
|
|
1511
|
+
* @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.
|
|
1512
|
+
*
|
|
1513
|
+
* @throws {@link ErrorCode|InternalError} when failed to login with unknown error.
|
|
1514
|
+
* @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.
|
|
1515
|
+
* @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
|
|
1516
|
+
* @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
|
|
1517
|
+
*
|
|
1518
|
+
* @beta
|
|
1519
|
+
*/
|
|
1520
|
+
login(scopes) {
|
|
1521
|
+
return tslib.__awaiter(this, void 0, void 0, function* () {
|
|
1522
|
+
throw new ErrorWithCode(formatString(ErrorMessage.NodejsRuntimeNotSupported, "login"), exports.ErrorCode.RuntimeNotSupported);
|
|
1523
|
+
});
|
|
1524
|
+
}
|
|
1525
|
+
/**
|
|
1526
|
+
* Set SSO token when using user identity in NodeJS.
|
|
1527
|
+
* @param {string} ssoToken - used for on behalf of user flow.
|
|
1528
|
+
* @returns self instance.
|
|
1529
|
+
* @beta
|
|
1530
|
+
*/
|
|
1531
|
+
setSsoToken(ssoToken) {
|
|
1532
|
+
if (this.identityType !== exports.IdentityType.User) {
|
|
1533
|
+
throw new Error();
|
|
1534
|
+
}
|
|
1535
|
+
this.oboUserCredential = new OnBehalfOfUserCredential(ssoToken, Object.fromEntries(this.configuration));
|
|
1536
|
+
return this;
|
|
1537
|
+
}
|
|
1538
|
+
/**
|
|
1539
|
+
* Usually used by service plugins to retrieve specific config
|
|
1540
|
+
* @param {string} key - configuration key.
|
|
1541
|
+
* @returns value in configuration.
|
|
1542
|
+
* @beta
|
|
1543
|
+
*/
|
|
1544
|
+
getConfig(key) {
|
|
1545
|
+
const value = this.configuration.get(key);
|
|
1546
|
+
if (!value) {
|
|
1547
|
+
const errorMsg = `Cannot find ${key} in configuration`;
|
|
1548
|
+
internalLogger.error(errorMsg);
|
|
1549
|
+
throw new ErrorWithCode(errorMsg, exports.ErrorCode.InternalError);
|
|
1550
|
+
}
|
|
1551
|
+
return value;
|
|
1552
|
+
}
|
|
1553
|
+
/**
|
|
1554
|
+
* Check the value of specific key.
|
|
1555
|
+
* @param {string} key - configuration key.
|
|
1556
|
+
* @returns true if corresponding value is not empty string.
|
|
1557
|
+
* @beta
|
|
1558
|
+
*/
|
|
1559
|
+
hasConfig(key) {
|
|
1560
|
+
const value = this.configuration.get(key);
|
|
1561
|
+
return !!value;
|
|
1562
|
+
}
|
|
1563
|
+
/**
|
|
1564
|
+
* Get all configurations.
|
|
1565
|
+
* @returns key value mappings.
|
|
1566
|
+
* @beta
|
|
1567
|
+
*/
|
|
1568
|
+
getConfigs() {
|
|
1569
|
+
const config = {};
|
|
1570
|
+
for (const key of this.configuration.keys()) {
|
|
1571
|
+
const value = this.configuration.get(key);
|
|
1572
|
+
if (value) {
|
|
1573
|
+
config[key] = value;
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
return config;
|
|
1577
|
+
}
|
|
1578
|
+
/**
|
|
1579
|
+
* Load configuration from environment variables.
|
|
1580
|
+
*/
|
|
1581
|
+
loadFromEnv() {
|
|
1582
|
+
const env = process.env;
|
|
1583
|
+
this.configuration.set("authorityHost", env.M365_AUTHORITY_HOST);
|
|
1584
|
+
this.configuration.set("tenantId", env.M365_TENANT_ID);
|
|
1585
|
+
this.configuration.set("clientId", env.M365_CLIENT_ID);
|
|
1586
|
+
this.configuration.set("clientSecret", env.M365_CLIENT_SECRET);
|
|
1587
|
+
this.configuration.set("initiateLoginEndpoint", env.INITIATE_LOGIN_ENDPOINT);
|
|
1588
|
+
this.configuration.set("applicationIdUri", env.M365_APPLICATION_ID_URI);
|
|
1589
|
+
this.configuration.set("apiEndpoint", env.API_ENDPOINT);
|
|
1590
|
+
this.configuration.set("apiName", env.API_NAME);
|
|
1591
|
+
this.configuration.set("sqlServerEndpoint", env.SQL_ENDPOINT);
|
|
1592
|
+
this.configuration.set("sqlUsername", env.SQL_USER_NAME);
|
|
1593
|
+
this.configuration.set("sqlPassword", env.SQL_PASSWORD);
|
|
1594
|
+
this.configuration.set("sqlDatabaseName", env.SQL_DATABASE_NAME);
|
|
1595
|
+
this.configuration.set("sqlIdentityId", env.IDENTITY_ID);
|
|
1596
|
+
Object.keys(env).forEach((key) => {
|
|
1597
|
+
const value = env[key];
|
|
1598
|
+
if (key.startsWith("TEAMSFX_") && value) {
|
|
1599
|
+
this.configuration.set(key.substring(8), value);
|
|
1600
|
+
}
|
|
1601
|
+
});
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
exports.AppCredential = AppCredential;
|
|
1543
1606
|
exports.ErrorWithCode = ErrorWithCode;
|
|
1544
|
-
exports.M365TenantCredential = M365TenantCredential;
|
|
1545
1607
|
exports.MsGraphAuthProvider = MsGraphAuthProvider;
|
|
1546
1608
|
exports.OnBehalfOfUserCredential = OnBehalfOfUserCredential;
|
|
1547
1609
|
exports.TeamsBotSsoPrompt = TeamsBotSsoPrompt;
|
|
1610
|
+
exports.TeamsFx = TeamsFx;
|
|
1548
1611
|
exports.TeamsUserCredential = TeamsUserCredential;
|
|
1549
1612
|
exports.createMicrosoftGraphClient = createMicrosoftGraphClient;
|
|
1550
|
-
exports.getAuthenticationConfiguration = getAuthenticationConfiguration;
|
|
1551
1613
|
exports.getLogLevel = getLogLevel;
|
|
1552
|
-
exports.
|
|
1553
|
-
exports.loadConfiguration = loadConfiguration;
|
|
1614
|
+
exports.getTediousConnectionConfig = getTediousConnectionConfig;
|
|
1554
1615
|
exports.setLogFunction = setLogFunction;
|
|
1555
1616
|
exports.setLogLevel = setLogLevel;
|
|
1556
1617
|
exports.setLogger = setLogger;
|