@microsoft/teamsfx 0.4.1-alpha.fa070464.0 → 0.4.2-alpha.01a113d2.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.
@@ -1,8 +1,7 @@
1
1
  import jwt_decode from 'jwt-decode';
2
2
  import * as microsoftTeams from '@microsoft/teams-js';
3
- import axios from 'axios';
3
+ import { PublicClientApplication } from '@azure/msal-browser';
4
4
  import { Client } from '@microsoft/microsoft-graph-client';
5
- import { ManagedIdentityCredential } from '@azure/identity';
6
5
 
7
6
  // Copyright (c) Microsoft Corporation.
8
7
  // Licensed under the MIT license.
@@ -56,6 +55,10 @@ var ErrorCode;
56
55
  * Operation failed.
57
56
  */
58
57
  ErrorCode["FailedOperation"] = "FailedOperation";
58
+ /**
59
+ * Version of SDK and project does not match.
60
+ */
61
+ ErrorCode["ProjectNeedUpgrade"] = "ProjectNeedUpgrade";
59
62
  })(ErrorCode || (ErrorCode = {}));
60
63
  /**
61
64
  * @internal
@@ -168,7 +171,7 @@ function getLogLevel() {
168
171
  return internalLogger.level;
169
172
  }
170
173
  class InternalLogger {
171
- constructor() {
174
+ constructor(name, logLevel) {
172
175
  this.level = undefined;
173
176
  this.defaultLogger = {
174
177
  verbose: console.debug,
@@ -176,6 +179,8 @@ class InternalLogger {
176
179
  warn: console.warn,
177
180
  error: console.error,
178
181
  };
182
+ this.name = name;
183
+ this.level = logLevel;
179
184
  }
180
185
  error(message) {
181
186
  this.log(LogLevel.Error, (x) => x.error, message);
@@ -194,7 +199,13 @@ class InternalLogger {
194
199
  return;
195
200
  }
196
201
  const timestamp = new Date().toUTCString();
197
- const logHeader = `[${timestamp}] : @microsoft/teamsfx : ${LogLevel[logLevel]} - `;
202
+ let logHeader;
203
+ if (this.name) {
204
+ logHeader = `[${timestamp}] : @microsoft/teamsfx - ${this.name} : ${LogLevel[logLevel]} - `;
205
+ }
206
+ else {
207
+ logHeader = `[${timestamp}] : @microsoft/teamsfx : ${LogLevel[logLevel]} - `;
208
+ }
198
209
  const logMessage = `${logHeader}${message}`;
199
210
  if (this.level !== undefined && this.level <= logLevel) {
200
211
  if (this.customLogger) {
@@ -302,6 +313,57 @@ function getUserInfoFromSsoToken(ssoToken) {
302
313
  }
303
314
  return userInfo;
304
315
  }
316
+ /**
317
+ * @internal
318
+ */
319
+ function getTenantIdAndLoginHintFromSsoToken(ssoToken) {
320
+ if (!ssoToken) {
321
+ const errorMsg = "SSO token is undefined.";
322
+ internalLogger.error(errorMsg);
323
+ throw new ErrorWithCode(errorMsg, ErrorCode.InvalidParameter);
324
+ }
325
+ const tokenObject = parseJwt(ssoToken);
326
+ const userInfo = {
327
+ tid: tokenObject.tid,
328
+ loginHint: tokenObject.ver === "2.0"
329
+ ? tokenObject.preferred_username
330
+ : tokenObject.upn,
331
+ };
332
+ return userInfo;
333
+ }
334
+ /**
335
+ * @internal
336
+ */
337
+ function parseAccessTokenFromAuthCodeTokenResponse(tokenResponse) {
338
+ try {
339
+ const tokenResponseObject = typeof tokenResponse == "string"
340
+ ? JSON.parse(tokenResponse)
341
+ : tokenResponse;
342
+ if (!tokenResponseObject || !tokenResponseObject.accessToken) {
343
+ const errorMsg = "Get empty access token from Auth Code token response.";
344
+ internalLogger.error(errorMsg);
345
+ throw new Error(errorMsg);
346
+ }
347
+ const token = tokenResponseObject.accessToken;
348
+ const tokenObject = parseJwt(token);
349
+ if (tokenObject.ver !== "1.0" && tokenObject.ver !== "2.0") {
350
+ const errorMsg = "SSO token is not valid with an unknown version: " + tokenObject.ver;
351
+ internalLogger.error(errorMsg);
352
+ throw new Error(errorMsg);
353
+ }
354
+ const accessToken = {
355
+ token: token,
356
+ expiresOnTimestamp: tokenObject.exp * 1000,
357
+ };
358
+ return accessToken;
359
+ }
360
+ catch (error) {
361
+ const errorMsg = "Parse access token failed from Auth Code token response in node env with error: " +
362
+ error.message;
363
+ internalLogger.error(errorMsg);
364
+ throw new ErrorWithCode(errorMsg, ErrorCode.InternalError);
365
+ }
366
+ }
305
367
  /**
306
368
  * Format string template with replacements
307
369
  *
@@ -541,43 +603,10 @@ class OnBehalfOfUserCredential {
541
603
  }
542
604
 
543
605
  // Copyright (c) Microsoft Corporation.
544
- // Licensed under the MIT license.
545
- /**
546
- * Configuration used in initialization.
547
- * @internal
548
- */
549
- class Cache {
550
- static get(key) {
551
- return sessionStorage.getItem(key);
552
- }
553
- static set(key, value) {
554
- sessionStorage.setItem(key, value);
555
- }
556
- static remove(key) {
557
- sessionStorage.removeItem(key);
558
- }
559
- }
560
-
561
- // Copyright (c) Microsoft Corporation.
562
- // Licensed under the MIT license.
563
- /**
564
- * @internal
565
- */
566
- var GrantType;
567
- (function (GrantType) {
568
- GrantType["authCode"] = "authorization_code";
569
- GrantType["ssoToken"] = "sso_token";
570
- })(GrantType || (GrantType = {}));
571
-
572
- // Copyright (c) Microsoft Corporation.
573
- const accessTokenCacheKeyPrefix = "accessToken";
574
- const separator = "-";
575
606
  const tokenRefreshTimeSpanInMillisecond = 5 * 60 * 1000;
576
607
  const initializeTeamsSdkTimeoutInMillisecond = 5000;
577
608
  const loginPageWidth = 600;
578
609
  const loginPageHeight = 535;
579
- const maxRetryCount = 3;
580
- const retryTimeSpanInMillisecond = 3000;
581
610
  /**
582
611
  * Represent Teams current user's identity, and it is used within Teams tab application.
583
612
  *
@@ -595,7 +624,6 @@ class TeamsUserCredential {
595
624
  * ```typescript
596
625
  * const config = {
597
626
  * authentication: {
598
- * runtimeConnectorEndpoint: "https://xxx.xxx.com",
599
627
  * initiateLoginEndpoint: "https://localhost:3000/auth-start.html",
600
628
  * clientId: "xxx"
601
629
  * }
@@ -613,6 +641,7 @@ class TeamsUserCredential {
613
641
  internalLogger.info("Create teams user credential");
614
642
  this.config = this.loadAndValidateConfig();
615
643
  this.ssoToken = null;
644
+ this.initialized = false;
616
645
  }
617
646
  /**
618
647
  * Popup login page to get user's access token with specific scopes.
@@ -630,7 +659,6 @@ class TeamsUserCredential {
630
659
  * @param scopes - The list of scopes for which the token will have access, before that, we will request user to consent.
631
660
  *
632
661
  * @throws {@link ErrorCode|InternalError} when failed to login with unknown error.
633
- * @throws {@link ErrorCode|ServiceError} when simple auth server failed to exchange access token.
634
662
  * @throws {@link ErrorCode|ConsentFailed} when user canceled or failed to consent.
635
663
  * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
636
664
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
@@ -641,27 +669,46 @@ class TeamsUserCredential {
641
669
  validateScopesType(scopes);
642
670
  const scopesStr = typeof scopes === "string" ? scopes : scopes.join(" ");
643
671
  internalLogger.info(`Popup login page to get user's access token with scopes: ${scopesStr}`);
672
+ if (!this.initialized) {
673
+ await this.init();
674
+ }
644
675
  return new Promise((resolve, reject) => {
645
676
  microsoftTeams.initialize(() => {
646
677
  microsoftTeams.authentication.authenticate({
647
- url: `${this.config.initiateLoginEndpoint}?clientId=${this.config.clientId}&scope=${encodeURI(scopesStr)}`,
678
+ url: `${this.config.initiateLoginEndpoint}?clientId=${this.config.clientId}&scope=${encodeURI(scopesStr)}&loginHint=${this.loginHint}`,
648
679
  width: loginPageWidth,
649
680
  height: loginPageHeight,
650
681
  successCallback: async (result) => {
651
682
  if (!result) {
652
- const errorMsg = "Get empty authentication result from Teams";
683
+ const errorMsg = "Get empty authentication result from MSAL";
653
684
  internalLogger.error(errorMsg);
654
685
  reject(new ErrorWithCode(errorMsg, ErrorCode.InternalError));
655
686
  return;
656
687
  }
657
- const authCodeResult = JSON.parse(result);
688
+ let resultJson = {};
658
689
  try {
659
- await this.exchangeAccessTokenFromSimpleAuthServer(scopesStr, authCodeResult);
690
+ resultJson = JSON.parse(result);
691
+ }
692
+ catch (error) {
693
+ // If can not parse result as Json, will NOT throw error since user may return other info in auth-end page.
694
+ // TODO: resolve the result.
695
+ const failedToParseResult = "Failed to parse result to Json.";
696
+ internalLogger.verbose(failedToParseResult);
660
697
  resolve();
698
+ return;
699
+ }
700
+ // If code exists in result, user may using previous auth-start and auth-end page.
701
+ if (resultJson.code) {
702
+ const helpLink = "https://aka.ms/teamsfx-auth-code-flow";
703
+ const usingPreviousAuthPage = "Found auth code in response. You may be using the latest TeamsFx SDK on an old project." +
704
+ `Please refer to the help link for how to fix the issue: ${helpLink}.`;
705
+ reject(new ErrorWithCode(usingPreviousAuthPage, ErrorCode.ProjectNeedUpgrade));
661
706
  }
662
- catch (err) {
663
- reject(this.generateAuthServerError(err));
707
+ // If sessionStorage exists in result, set the values in current session storage.
708
+ if (resultJson.sessionStorage) {
709
+ this.setSessionStorage(resultJson.sessionStorage);
664
710
  }
711
+ resolve();
665
712
  },
666
713
  failureCallback: (reason) => {
667
714
  const errorMsg = `Consent failed for the scope ${scopesStr} with error: ${reason}`;
@@ -675,6 +722,8 @@ class TeamsUserCredential {
675
722
  /**
676
723
  * Get access token from credential.
677
724
  *
725
+ * Important: Access tokens are stored in sessionStorage, read more here: https://aka.ms/teamsfx-session-storage-notice
726
+ *
678
727
  * @example
679
728
  * ```typescript
680
729
  * await credential.getToken([]) // Get SSO token using empty string array
@@ -694,7 +743,6 @@ class TeamsUserCredential {
694
743
  *
695
744
  * @throws {@link ErrorCode|InternalError} when failed to get access token with unknown error.
696
745
  * @throws {@link ErrorCode|UiRequiredError} when need user consent to get access token.
697
- * @throws {@link ErrorCode|ServiceError} when failed to get access token from simple auth server.
698
746
  * @throws {@link ErrorCode|InvalidParameter} when scopes is not a valid string or string array.
699
747
  * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is nodeJS.
700
748
  *
@@ -715,21 +763,47 @@ class TeamsUserCredential {
715
763
  }
716
764
  else {
717
765
  internalLogger.info("Get access token with scopes: " + scopeStr);
718
- const cachedKey = await this.getAccessTokenCacheKey(scopeStr);
719
- const cachedToken = this.getTokenCache(cachedKey);
720
- if (cachedToken) {
721
- if (!this.isAccessTokenNearExpired(cachedToken)) {
722
- internalLogger.verbose("Get access token from cache");
723
- return cachedToken;
766
+ if (!this.initialized) {
767
+ await this.init();
768
+ }
769
+ let tokenResponse;
770
+ const scopesArray = typeof scopes === "string" ? scopes.split(" ") : scopes;
771
+ const domain = window.location.origin;
772
+ // First try to get Access Token from cache.
773
+ try {
774
+ const account = this.msalInstance.getAccountByUsername(this.loginHint);
775
+ const scopesRequestForAcquireTokenSilent = {
776
+ scopes: scopesArray,
777
+ account: account !== null && account !== void 0 ? account : undefined,
778
+ redirectUri: `${domain}/blank-auth-end.html`,
779
+ };
780
+ tokenResponse = await this.msalInstance.acquireTokenSilent(scopesRequestForAcquireTokenSilent);
781
+ }
782
+ catch (error) {
783
+ const acquireTokenSilentFailedMessage = `Failed to call acquireTokenSilent. Reason: ${error === null || error === void 0 ? void 0 : error.message}. `;
784
+ internalLogger.verbose(acquireTokenSilentFailedMessage);
785
+ }
786
+ if (!tokenResponse) {
787
+ // If fail to get Access Token from cache, try to get Access token by silent login.
788
+ try {
789
+ const scopesRequestForSsoSilent = {
790
+ scopes: scopesArray,
791
+ loginHint: this.loginHint,
792
+ redirectUri: `${domain}/blank-auth-end.html`,
793
+ };
794
+ tokenResponse = await this.msalInstance.ssoSilent(scopesRequestForSsoSilent);
724
795
  }
725
- else {
726
- internalLogger.verbose("Cached access token is expired");
796
+ catch (error) {
797
+ const ssoSilentFailedMessage = `Failed to call ssoSilent. Reason: ${error === null || error === void 0 ? void 0 : error.message}. `;
798
+ internalLogger.verbose(ssoSilentFailedMessage);
727
799
  }
728
800
  }
729
- else {
730
- internalLogger.verbose("No cached access token");
801
+ if (!tokenResponse) {
802
+ const errorMsg = `Failed to get access token cache silently, please login first: you need login first before get access token.`;
803
+ internalLogger.error(errorMsg);
804
+ throw new ErrorWithCode(errorMsg, ErrorCode.UiRequiredError);
731
805
  }
732
- const accessToken = await this.getAndCacheAccessTokenFromSimpleAuthServer(scopeStr);
806
+ const accessToken = parseAccessTokenFromAuthCodeTokenResponse(tokenResponse);
733
807
  return accessToken;
734
808
  }
735
809
  }
@@ -754,64 +828,22 @@ class TeamsUserCredential {
754
828
  const ssoToken = await this.getSSOToken();
755
829
  return getUserInfoFromSsoToken(ssoToken.token);
756
830
  }
757
- async exchangeAccessTokenFromSimpleAuthServer(scopesStr, authCodeResult) {
758
- var _a, _b;
759
- const axiosInstance = await this.getAxiosInstance();
760
- let retryCount = 0;
761
- while (true) {
762
- try {
763
- const response = await axiosInstance.post("/auth/token", {
764
- scope: scopesStr,
765
- code: authCodeResult.code,
766
- code_verifier: authCodeResult.codeVerifier,
767
- redirect_uri: authCodeResult.redirectUri,
768
- grant_type: GrantType.authCode,
769
- });
770
- const tokenResult = response.data;
771
- const key = await this.getAccessTokenCacheKey(scopesStr);
772
- this.setTokenCache(key, {
773
- token: tokenResult.access_token,
774
- expiresOnTimestamp: tokenResult.expires_on,
775
- });
776
- return;
777
- }
778
- catch (err) {
779
- if (((_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.type) && err.response.data.type === "AadUiRequiredException") {
780
- internalLogger.warn("Exchange access token failed, retry...");
781
- if (retryCount < maxRetryCount) {
782
- await this.sleep(retryTimeSpanInMillisecond);
783
- retryCount++;
784
- continue;
785
- }
786
- }
787
- throw err;
788
- }
789
- }
790
- }
791
- /**
792
- * Get access token cache from authentication server
793
- * @returns Access token
794
- */
795
- async getAndCacheAccessTokenFromSimpleAuthServer(scopesStr) {
796
- try {
797
- internalLogger.verbose("Get access token from authentication server with scopes: " + scopesStr);
798
- const axiosInstance = await this.getAxiosInstance();
799
- const response = await axiosInstance.post("/auth/token", {
800
- scope: scopesStr,
801
- grant_type: GrantType.ssoToken,
802
- });
803
- const accessTokenResult = response.data;
804
- const accessToken = {
805
- token: accessTokenResult.access_token,
806
- expiresOnTimestamp: accessTokenResult.expires_on,
807
- };
808
- const cacheKey = await this.getAccessTokenCacheKey(scopesStr);
809
- this.setTokenCache(cacheKey, accessToken);
810
- return accessToken;
811
- }
812
- catch (err) {
813
- throw this.generateAuthServerError(err);
814
- }
831
+ async init() {
832
+ const ssoToken = await this.getSSOToken();
833
+ const info = getTenantIdAndLoginHintFromSsoToken(ssoToken.token);
834
+ this.loginHint = info.loginHint;
835
+ this.tid = info.tid;
836
+ const msalConfig = {
837
+ auth: {
838
+ clientId: this.config.clientId,
839
+ authority: `https://login.microsoftonline.com/${this.tid}`,
840
+ },
841
+ cache: {
842
+ cacheLocation: "sessionStorage",
843
+ },
844
+ };
845
+ this.msalInstance = new PublicClientApplication(msalConfig);
846
+ this.initialized = true;
815
847
  }
816
848
  /**
817
849
  * Get SSO token using teams SDK
@@ -881,16 +913,13 @@ class TeamsUserCredential {
881
913
  internalLogger.error(ErrorMessage.AuthenticationConfigurationNotExists);
882
914
  throw new ErrorWithCode(ErrorMessage.AuthenticationConfigurationNotExists, ErrorCode.InvalidConfiguration);
883
915
  }
884
- if (config.initiateLoginEndpoint && config.simpleAuthEndpoint && config.clientId) {
916
+ if (config.initiateLoginEndpoint && config.clientId) {
885
917
  return config;
886
918
  }
887
919
  const missingValues = [];
888
920
  if (!config.initiateLoginEndpoint) {
889
921
  missingValues.push("initiateLoginEndpoint");
890
922
  }
891
- if (!config.simpleAuthEndpoint) {
892
- missingValues.push("simpleAuthEndpoint");
893
- }
894
923
  if (!config.clientId) {
895
924
  missingValues.push("clientId");
896
925
  }
@@ -898,111 +927,20 @@ class TeamsUserCredential {
898
927
  internalLogger.error(errorMsg);
899
928
  throw new ErrorWithCode(errorMsg, ErrorCode.InvalidConfiguration);
900
929
  }
901
- /**
902
- * Get axios instance with sso token bearer header
903
- * @returns AxiosInstance
904
- */
905
- async getAxiosInstance() {
906
- const ssoToken = await this.getSSOToken();
907
- const axiosInstance = axios.create({
908
- baseURL: this.config.simpleAuthEndpoint,
909
- });
910
- axiosInstance.interceptors.request.use((config) => {
911
- config.headers.Authorization = "Bearer " + ssoToken.token;
912
- return config;
913
- });
914
- return axiosInstance;
915
- }
916
- /**
917
- * Set access token to cache
918
- * @param key
919
- * @param token
920
- */
921
- setTokenCache(key, token) {
922
- Cache.set(key, JSON.stringify(token));
923
- }
924
- /**
925
- * Get access token from cache.
926
- * If there is no cache or cannot be parsed, then it will return null
927
- * @param key
928
- * @returns Access token or null
929
- */
930
- getTokenCache(key) {
931
- const value = Cache.get(key);
932
- if (value === null) {
933
- return null;
934
- }
935
- const accessToken = this.validateAndParseJson(value);
936
- return accessToken;
937
- }
938
- /**
939
- * Parses passed value as JSON access token, if value is not a valid json string JSON.parse() will throw an error.
940
- * @param jsonValue
941
- */
942
- validateAndParseJson(jsonValue) {
930
+ setSessionStorage(sessonStorageValues) {
943
931
  try {
944
- const parsedJson = JSON.parse(jsonValue);
945
- /**
946
- * There are edge cases in which JSON.parse will successfully parse a non-valid JSON object
947
- * (e.g. JSON.parse will parse an escaped string into an unescaped string), so adding a type check
948
- * of the parsed value is necessary in order to be certain that the string represents a valid JSON object.
949
- *
950
- */
951
- return parsedJson && typeof parsedJson === "object" ? parsedJson : null;
932
+ const sessionStorageKeys = Object.keys(sessonStorageValues);
933
+ sessionStorageKeys.forEach((key) => {
934
+ sessionStorage.setItem(key, sessonStorageValues[key]);
935
+ });
952
936
  }
953
937
  catch (error) {
954
- return null;
955
- }
956
- }
957
- /**
958
- * Generate cache key
959
- * @param scopesStr
960
- * @returns Access token cache key, a key example: accessToken-userId-clientId-tenantId-scopes
961
- */
962
- async getAccessTokenCacheKey(scopesStr) {
963
- const ssoToken = await this.getSSOToken();
964
- const ssoTokenObj = parseJwt(ssoToken.token);
965
- const clientId = this.config.clientId;
966
- const userObjectId = ssoTokenObj.oid;
967
- const tenantId = ssoTokenObj.tid;
968
- const key = [accessTokenCacheKeyPrefix, userObjectId, clientId, tenantId, scopesStr]
969
- .join(separator)
970
- .replace(/" "/g, "_");
971
- return key;
972
- }
973
- /**
974
- * Check whether the token is about to expire (within 5 minutes)
975
- * @returns Boolean value indicate whether the token is about to expire
976
- */
977
- isAccessTokenNearExpired(token) {
978
- const expireDate = new Date(token.expiresOnTimestamp);
979
- if (expireDate.getTime() - Date.now() > tokenRefreshTimeSpanInMillisecond) {
980
- return false;
938
+ // Values in result.sessionStorage can not be set into session storage.
939
+ // Throw error since this may block user.
940
+ const errorMessage = `Failed to set values in session storage. Error: ${error.message}`;
941
+ internalLogger.error(errorMessage);
942
+ throw new ErrorWithCode(errorMessage, ErrorCode.InternalError);
981
943
  }
982
- return true;
983
- }
984
- generateAuthServerError(err) {
985
- var _a, _b;
986
- let errorMessage = err.message;
987
- if ((_b = (_a = err.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.type) {
988
- errorMessage = err.response.data.detail;
989
- if (err.response.data.type === "AadUiRequiredException") {
990
- const fullErrorMsg = "Failed to get access token from authentication server, please login first: " +
991
- errorMessage;
992
- internalLogger.warn(fullErrorMsg);
993
- return new ErrorWithCode(fullErrorMsg, ErrorCode.UiRequiredError);
994
- }
995
- else {
996
- const fullErrorMsg = "Failed to get access token from authentication server: " + errorMessage;
997
- internalLogger.error(fullErrorMsg);
998
- return new ErrorWithCode(fullErrorMsg, ErrorCode.ServiceError);
999
- }
1000
- }
1001
- const fullErrorMsg = "Failed to get access token with error: " + errorMessage;
1002
- return new ErrorWithCode(fullErrorMsg, ErrorCode.InternalError);
1003
- }
1004
- sleep(ms) {
1005
- return new Promise((resolve) => setTimeout(resolve, ms));
1006
944
  }
1007
945
  }
1008
946
 
@@ -1130,174 +1068,25 @@ function createMicrosoftGraphClient(credential, scopes) {
1130
1068
 
1131
1069
  // Copyright (c) Microsoft Corporation.
1132
1070
  /**
1133
- * SQL connection configuration instance.
1071
+ * Generate connection configuration consumed by tedious.
1134
1072
  * @remarks
1135
1073
  * Only works in in server side.
1136
- *
1137
1074
  * @beta
1138
- *
1139
1075
  */
1140
1076
  class DefaultTediousConnectionConfiguration {
1141
1077
  constructor() {
1142
- /**
1143
- * MSSQL default scope
1144
- * https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi
1145
- */
1146
- this.defaultSQLScope = "https://database.windows.net/";
1078
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "DefaultTediousConnectionConfiguration"), ErrorCode.RuntimeNotSupported);
1147
1079
  }
1148
1080
  /**
1149
1081
  * Generate connection configuration consumed by tedious.
1150
- *
1151
- * @returns Connection configuration of tedious for the SQL.
1152
- *
1153
- * @throws {@link ErrorCode|InvalidConfiguration} when SQL config resource configuration is invalid.
1154
- * @throws {@link ErrorCode|InternalError} when get user MSI token failed or MSI token is invalid.
1155
- * @throws {@link ErrorCode|RuntimeNotSupported} when runtime is browser.
1156
- *
1082
+ * @remarks
1083
+ * Only works in in server side.
1157
1084
  * @beta
1158
1085
  */
1159
- async getConfig() {
1160
- internalLogger.info("Get SQL configuration");
1161
- const configuration = getResourceConfiguration(ResourceType.SQL);
1162
- if (!configuration) {
1163
- const errMsg = "SQL resource configuration not exist";
1164
- internalLogger.error(errMsg);
1165
- throw new ErrorWithCode(errMsg, ErrorCode.InvalidConfiguration);
1166
- }
1167
- try {
1168
- this.isSQLConfigurationValid(configuration);
1169
- }
1170
- catch (err) {
1171
- throw err;
1172
- }
1173
- if (!this.isMsiAuthentication()) {
1174
- const configWithUPS = this.generateDefaultConfig(configuration);
1175
- internalLogger.verbose("SQL configuration with username and password generated");
1176
- return configWithUPS;
1177
- }
1178
- try {
1179
- const configWithToken = await this.generateTokenConfig(configuration);
1180
- internalLogger.verbose("SQL configuration with MSI token generated");
1181
- return configWithToken;
1182
- }
1183
- catch (error) {
1184
- throw error;
1185
- }
1186
- }
1187
- /**
1188
- * Check SQL use MSI identity or username and password.
1189
- *
1190
- * @returns false - login with SQL MSI identity, true - login with username and password.
1191
- * @internal
1192
- */
1193
- isMsiAuthentication() {
1194
- internalLogger.verbose("Check connection config using MSI access token or username and password");
1195
- const configuration = getResourceConfiguration(ResourceType.SQL);
1196
- if ((configuration === null || configuration === void 0 ? void 0 : configuration.sqlUsername) != null && (configuration === null || configuration === void 0 ? void 0 : configuration.sqlPassword) != null) {
1197
- internalLogger.verbose("Login with username and password");
1198
- return false;
1199
- }
1200
- internalLogger.verbose("Login with MSI identity");
1201
- return true;
1202
- }
1203
- /**
1204
- * check configuration is an available configurations.
1205
- * @param { SqlConfiguration } sqlConfig
1206
- *
1207
- * @returns true - SQL configuration has a valid SQL endpoints, SQL username with password or identity ID.
1208
- * false - configuration is not valid.
1209
- * @internal
1210
- */
1211
- isSQLConfigurationValid(sqlConfig) {
1212
- internalLogger.verbose("Check SQL configuration if valid");
1213
- if (!sqlConfig.sqlServerEndpoint) {
1214
- internalLogger.error("SQL configuration is not valid without SQL server endpoint exist");
1215
- throw new ErrorWithCode("SQL configuration error without SQL server endpoint exist", ErrorCode.InvalidConfiguration);
1216
- }
1217
- if (!(sqlConfig.sqlUsername && sqlConfig.sqlPassword) && !sqlConfig.sqlIdentityId) {
1218
- const errMsg = `SQL configuration is not valid without ${sqlConfig.sqlIdentityId ? "" : "identity id "} ${sqlConfig.sqlUsername ? "" : "SQL username "} ${sqlConfig.sqlPassword ? "" : "SQL password"} exist`;
1219
- internalLogger.error(errMsg);
1220
- throw new ErrorWithCode(errMsg, ErrorCode.InvalidConfiguration);
1221
- }
1222
- internalLogger.verbose("SQL configuration is valid");
1223
- }
1224
- /**
1225
- * Generate tedious connection configuration with default authentication type.
1226
- *
1227
- * @param { SqlConfiguration } SQL configuration with username and password.
1228
- *
1229
- * @returns Tedious connection configuration with username and password.
1230
- * @internal
1231
- */
1232
- generateDefaultConfig(sqlConfig) {
1233
- internalLogger.verbose(`SQL server ${sqlConfig.sqlServerEndpoint}, user name ${sqlConfig.sqlUsername}, database name ${sqlConfig.sqlDatabaseName}`);
1234
- const config = {
1235
- server: sqlConfig.sqlServerEndpoint,
1236
- authentication: {
1237
- type: TediousAuthenticationType.default,
1238
- options: {
1239
- userName: sqlConfig.sqlUsername,
1240
- password: sqlConfig.sqlPassword,
1241
- },
1242
- },
1243
- options: {
1244
- database: sqlConfig.sqlDatabaseName,
1245
- encrypt: true,
1246
- },
1247
- };
1248
- return config;
1086
+ async getConfig(databaseName) {
1087
+ throw new ErrorWithCode(formatString(ErrorMessage.BrowserRuntimeNotSupported, "DefaultTediousConnectionConfiguration"), ErrorCode.RuntimeNotSupported);
1249
1088
  }
1250
- /**
1251
- * Generate tedious connection configuration with azure-active-directory-access-token authentication type.
1252
- *
1253
- * @param { SqlConfiguration } SQL configuration with AAD access token.
1254
- *
1255
- * @returns Tedious connection configuration with access token.
1256
- * @internal
1257
- */
1258
- async generateTokenConfig(sqlConfig) {
1259
- internalLogger.verbose("Generate tedious config with MSI token");
1260
- let token;
1261
- try {
1262
- const credential = new ManagedIdentityCredential(sqlConfig.sqlIdentityId);
1263
- token = await credential.getToken(this.defaultSQLScope);
1264
- }
1265
- catch (error) {
1266
- const errMsg = "Get user MSI token failed";
1267
- internalLogger.error(errMsg);
1268
- throw new ErrorWithCode(errMsg, ErrorCode.InternalError);
1269
- }
1270
- if (token) {
1271
- const config = {
1272
- server: sqlConfig.sqlServerEndpoint,
1273
- authentication: {
1274
- type: TediousAuthenticationType.MSI,
1275
- options: {
1276
- token: token.token,
1277
- },
1278
- },
1279
- options: {
1280
- database: sqlConfig.sqlDatabaseName,
1281
- encrypt: true,
1282
- },
1283
- };
1284
- internalLogger.verbose(`Generate token configuration success, server endpoint is ${sqlConfig.sqlServerEndpoint}, database name is ${sqlConfig.sqlDatabaseName}`);
1285
- return config;
1286
- }
1287
- internalLogger.error(`Generate token configuration, server endpoint is ${sqlConfig.sqlServerEndpoint}, MSI token is not valid`);
1288
- throw new ErrorWithCode("MSI token is not valid", ErrorCode.InternalError);
1289
- }
1290
- }
1291
- /**
1292
- * tedious connection config authentication type.
1293
- * https://tediousjs.github.io/tedious/api-connection.html
1294
- * @internal
1295
- */
1296
- var TediousAuthenticationType;
1297
- (function (TediousAuthenticationType) {
1298
- TediousAuthenticationType["default"] = "default";
1299
- TediousAuthenticationType["MSI"] = "azure-active-directory-access-token";
1300
- })(TediousAuthenticationType || (TediousAuthenticationType = {}));
1089
+ }
1301
1090
 
1302
1091
  // Copyright (c) Microsoft Corporation.
1303
1092
  /**