diff --git a/common/config/rush/pnpm-lock.yaml b/common/config/rush/pnpm-lock.yaml index 67e0a07a4379..e7e0c5f77643 100644 --- a/common/config/rush/pnpm-lock.yaml +++ b/common/config/rush/pnpm-lock.yaml @@ -221,6 +221,52 @@ packages: dev: false resolution: integrity: sha512-CxaMaEjwtsmIhWtjHyGimKO7RmES0YxPqGQ9+jKqGygNlhG5NYHktDaiQu6w7k3g+I51VaLXtVSt+BVFd6VWfQ== + /@azure/identity/1.2.2: + dependencies: + '@azure/core-http': 1.2.2 + '@azure/core-tracing': 1.0.0-preview.9 + '@azure/logger': 1.0.1 + '@azure/msal-node': 1.0.0-beta.3 + '@opentelemetry/api': 0.10.2 + axios: 0.21.1 + events: 3.2.0 + jws: 4.0.0 + msal: 1.4.5 + open: 7.4.0 + qs: 6.9.6 + tslib: 2.1.0 + uuid: 8.3.2 + dev: false + engines: + node: '>=8.0.0' + optionalDependencies: + keytar: 5.6.0 + resolution: + integrity: sha512-aYkeNXl52aEHW1iOZQJb3SC7Vvbu87f01iNT+pSVHwj09LpN9+gP/Lb9uoWy36Fgv9WlukM55LbjLSbb1Renqw== + /@azure/identity/1.2.2_debug@4.3.1: + dependencies: + '@azure/core-http': 1.2.2 + '@azure/core-tracing': 1.0.0-preview.9 + '@azure/logger': 1.0.1 + '@azure/msal-node': 1.0.0-beta.3_debug@4.3.1 + '@opentelemetry/api': 0.10.2 + axios: 0.21.1_debug@4.3.1 + events: 3.2.0 + jws: 4.0.0 + msal: 1.4.5 + open: 7.4.0 + qs: 6.9.6 + tslib: 2.1.0 + uuid: 8.3.2 + dev: false + engines: + node: '>=8.0.0' + optionalDependencies: + keytar: 5.6.0 + peerDependencies: + debug: '*' + resolution: + integrity: sha512-aYkeNXl52aEHW1iOZQJb3SC7Vvbu87f01iNT+pSVHwj09LpN9+gP/Lb9uoWy36Fgv9WlukM55LbjLSbb1Renqw== /@azure/logger-js/1.3.2: dependencies: tslib: 1.14.1 @@ -289,6 +335,22 @@ packages: debug: '*' resolution: integrity: sha512-aFHRw/IHhg3I9ZJW+Va4L+sCirFHMVIu6B7lFdL5mGLfG3xC5vDIdd957LRXFgy2OiKFRUC0QaKknd0YCsQIqA== + /@azure/msal-browser/2.9.0: + dependencies: + '@azure/msal-common': 2.1.0 + dev: false + engines: + node: '>=0.8.0' + resolution: + integrity: sha512-Zyus+skNaVWL5fXfSjC17c94XZ95Z3a+bZc7YKkP26KT3Dj26jbfz2oT9KJxAT4XVtH/1WPY/fPFeEFTRvytJQ== + /@azure/msal-common/2.1.0: + dependencies: + debug: 4.3.1 + dev: false + engines: + node: '>=0.8.0' + resolution: + integrity: sha512-Y1Id+jG59S3eY2ZQQtUA/lxwbRcgjcWaiib9YX+SwV3zeRauKfEiZT7l3z+lwV+T+Sst20F6l1mJsfQcfE7CEQ== /@azure/msal-common/4.0.0: dependencies: debug: 4.3.1 @@ -297,6 +359,26 @@ packages: node: '>=0.8.0' resolution: integrity: sha512-aGIUZgaIyb48m9353oepMsoy8tAan4BM6MvQ9FFybRJdMtTlHkXo7BfGcygVSFJlB2AGnW7HhCKAwCKNEpjzeQ== + /@azure/msal-node/1.0.0-beta.3: + dependencies: + '@azure/msal-common': 2.1.0 + axios: 0.21.1 + jsonwebtoken: 8.5.1 + uuid: 8.3.2 + dev: false + resolution: + integrity: sha512-/KfYRfrsOIrZONvo/0Vi5umuqbPBtCWNtmRvkse64uI0C4CP/W4WXwRD42VMws/8LtKvr1I5rYlYgFzt5zDz/A== + /@azure/msal-node/1.0.0-beta.3_debug@4.3.1: + dependencies: + '@azure/msal-common': 2.1.0 + axios: 0.21.1_debug@4.3.1 + jsonwebtoken: 8.5.1 + uuid: 8.3.2 + dev: false + peerDependencies: + debug: '*' + resolution: + integrity: sha512-/KfYRfrsOIrZONvo/0Vi5umuqbPBtCWNtmRvkse64uI0C4CP/W4WXwRD42VMws/8LtKvr1I5rYlYgFzt5zDz/A== /@azure/msal-node/1.0.0-beta.6: dependencies: '@azure/msal-common': 4.0.0 @@ -1721,14 +1803,14 @@ packages: node: '>=8' resolution: integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - /bl/4.0.4: + /bl/4.0.3: dependencies: buffer: 5.7.1 inherits: 2.0.4 readable-stream: 3.6.0 dev: false resolution: - integrity: sha512-7tdr4EpSd7jJ6tuQ21vu2ke8w7pNEstzj1O8wwq6sNNzO3UDi5MA8Gny/gquCj7r2C6fHudg8tKRGyjRgmvNxQ== + integrity: sha512-fs4G6/Hu4/EE+F75J8DuN/0IpQqNjAdC7aEQv7Qt8MHGUH7Ckv2MwTEEeN9QehD0pfIDkMI1bkHYkKy7xHyKIg== /blob/0.0.5: dev: false resolution: @@ -1856,33 +1938,33 @@ packages: dev: false resolution: integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - /chai-as-promised/7.1.1_chai@4.3.0: + /chai-as-promised/7.1.1_chai@4.2.0: dependencies: - chai: 4.3.0 + chai: 4.2.0 check-error: 1.0.2 dev: false peerDependencies: chai: '>= 2.1.2 < 5' resolution: integrity: sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== - /chai-exclude/2.0.2_chai@4.3.0: + /chai-exclude/2.0.2_chai@4.2.0: dependencies: - chai: 4.3.0 + chai: 4.2.0 fclone: 1.0.11 dev: false peerDependencies: chai: '>= 4.0.0 < 5' resolution: integrity: sha512-QmNVnvdSw8Huccdjm49mKu3HtoHxvjdavgYkY0KPQ5MI5UWfbc9sX1YqRgaMPf2GGtDXPoF2ram3AeNS4945Xw== - /chai-string/1.5.0_chai@4.3.0: + /chai-string/1.5.0_chai@4.2.0: dependencies: - chai: 4.3.0 + chai: 4.2.0 dev: false peerDependencies: chai: ^4.1.2 resolution: integrity: sha512-sydDC3S3pNAQMYwJrs6dQX0oBQ6KfIPuOZ78n7rocW0eJJlsHPh2t3kwW7xfwYA/1Bf6/arGtSUo16rxR2JFlw== - /chai/4.3.0: + /chai/4.2.0: dependencies: assertion-error: 1.1.0 check-error: 1.0.2 @@ -1892,9 +1974,9 @@ packages: type-detect: 4.0.8 dev: false engines: - node: '>=8' + node: '>=4' resolution: - integrity: sha512-/BFd2J30EcOwmdOgXvVsmM48l0Br0nmZPlO0uOW4XKh6kpsUumRXBgPV+IlaqFaqr9cYbeoZAM1Npx0i4A+aiA== + integrity: sha512-XQU3bhBukrOsQCuwZndwGcCVQHyZi53fQ6Ys1Fym7E4olpIqqZZhhoFJoaKVvV17lWQoXYwgWN2nF5crA8J2jw== /chalk/1.1.3: dependencies: ansi-styles: 2.2.1 @@ -2749,16 +2831,6 @@ packages: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 resolution: integrity: sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw== - /eslint-plugin-no-null/1.0.2_eslint@7.19.0: - dependencies: - eslint: 7.19.0 - dev: false - engines: - node: '>=5.0.0' - peerDependencies: - eslint: '>=3.0.0' - resolution: - integrity: sha1-EjaoEjkTkKGHetQAfCbnRTQclR8= /eslint-plugin-no-only-tests/2.4.0: dev: false engines: @@ -4406,9 +4478,9 @@ packages: dev: false resolution: integrity: sha1-fYa9VmefWM5qhHBKZX3TkruoGnk= - /karma-chai/0.1.0_chai@4.3.0+karma@5.2.3: + /karma-chai/0.1.0_chai@4.2.0+karma@5.2.3: dependencies: - chai: 4.3.0 + chai: 4.2.0 karma: 5.2.3 dev: false peerDependencies: @@ -4596,6 +4668,15 @@ packages: debug: '*' resolution: integrity: sha512-tHdyFADhVVPBorIKCX8A37iLHxc6RBRphkSoQ+MLKdAtFn1k97tD8WUGi1KlEtDZKL3hui0qhsY9HXUfSNDYPQ== + /keytar/5.6.0: + dependencies: + nan: 2.14.1 + prebuild-install: 5.3.3 + dev: false + optional: true + requiresBuild: true + resolution: + integrity: sha512-ueulhshHSGoryfRXaIvTj0BV1yB0KddBGhGoqCxSN9LR1Ks1GKuuCdVhF+2/YOs5fMl6MlTI9On1a4DHDXoTow== /keytar/7.3.0: dependencies: node-addon-api: 3.1.0 @@ -5056,6 +5137,11 @@ packages: node: '>=0.8.0' resolution: integrity: sha512-tKn7j7QXfH5GHtOQ2edbFmylN8z8g2bfBWU3tmZ/b09fXDQt+pelfQ0NKNu1hso83sLXjEKHF1XIbjAqVGYSsA== + /nan/2.14.1: + dev: false + optional: true + resolution: + integrity: sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== /nanoid/3.1.20: dev: false engines: @@ -5651,6 +5737,30 @@ packages: node: '>=4' resolution: integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== + /prebuild-install/5.3.3: + dependencies: + detect-libc: 1.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.5 + mkdirp: 0.5.5 + napi-build-utils: 1.0.2 + node-abi: 2.19.3 + noop-logger: 0.1.1 + npmlog: 4.1.2 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 3.1.0 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + which-pm-runs: 1.0.0 + dev: false + engines: + node: '>=6' + hasBin: true + optional: true + resolution: + integrity: sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g== /prebuild-install/6.0.0: dependencies: detect-libc: 1.0.3 @@ -6893,7 +7003,7 @@ packages: integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== /tar-stream/2.2.0: dependencies: - bl: 4.0.4 + bl: 4.0.3 end-of-stream: 1.4.4 fs-constants: 1.0.0 inherits: 2.0.4 @@ -7705,6 +7815,7 @@ packages: file:projects/ai-anomaly-detector.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -7715,7 +7826,7 @@ packages: '@types/chai': 4.2.14 '@types/mocha': 7.0.2 '@types/node': 8.10.66 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 csv-parse: 4.15.1 dotenv: 8.2.0 @@ -7749,20 +7860,21 @@ packages: dev: false name: '@rush-temp/ai-anomaly-detector' resolution: - integrity: sha512-PZCerjQuCAQte4Q0znsG1jlfRw1y7mtdSLjQxYYl1fo2+/9S5Gh3riGid9/64EIammrIymTg0eEVmer+nuLWCg== + integrity: sha512-9W3BnhYA3YOhhomokrPS13UDptR/fAuedsSizp/2UzjcNuQHxXOByf91LolzLrDupKrPikXHR2B02WKYNIz0DQ== tarball: file:projects/ai-anomaly-detector.tgz version: 0.0.0 file:projects/ai-form-recognizer.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@types/chai': 4.2.14 '@types/mocha': 7.0.2 '@types/node': 8.10.66 '@types/sinon': 9.0.10 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -7793,20 +7905,21 @@ packages: dev: false name: '@rush-temp/ai-form-recognizer' resolution: - integrity: sha512-9xOseHY7PsxgELzLuuJg2YvbOosQQYKzLrTjJkz0PLryRjaPmY+y+SwdWh+ItprdabUwBznjkhhF+KP9Iq+eKQ== + integrity: sha512-hc+1n9vrAneEKa7xouhFU8LtIqjE6i/RFkSAxEPPOkHxHosA30BQqwgIaLVIeRw2YR5x6ehJxs72Z5cobDDi5Q== tarball: file:projects/ai-form-recognizer.tgz version: 0.0.0 file:projects/ai-metrics-advisor.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@types/chai': 4.2.14 '@types/mocha': 7.0.2 '@types/node': 8.10.66 '@types/sinon': 9.0.10 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -7838,12 +7951,13 @@ packages: dev: false name: '@rush-temp/ai-metrics-advisor' resolution: - integrity: sha512-sjvb9T7w/Lq6HYMMc+T6c6ALv9j2Q2LcZ33Ou92dZpxTJ0IKpjMDKBpO2K8E/1Qbs6gk6EkscQdmhNH+kAdITw== + integrity: sha512-/Y7BDcR8puqwG/qycf4F0bwNrqH0PGdGABbg3CUHtB3OKombB/9YeprwXPgSr+FA0CZ8z0JpXY9MSWjlFV3YQQ== tarball: file:projects/ai-metrics-advisor.tgz version: 0.0.0 file:projects/ai-text-analytics.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@types/chai': 4.2.14 @@ -7851,8 +7965,8 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 '@types/sinon': 9.0.10 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -7885,12 +7999,13 @@ packages: dev: false name: '@rush-temp/ai-text-analytics' resolution: - integrity: sha512-+NHOEVzOlGo75S26z9PRSPQwzRtC0RdCN9jLfTlKoDJIU3Q41HfLT/pLhHoZ7x64UeqJpkdEMLUl7mssfKsoXQ== + integrity: sha512-7njwMwkEG3U1BZwTs1VEhmNonvN4V/U39Nm+Yf47QlmkGYftpykJWfLkmZ0D6xzqrZQpTeeL9IalxlNs2TJE9Q== tarball: file:projects/ai-text-analytics.tgz version: 0.0.0 file:projects/app-configuration.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -7904,7 +8019,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -7939,11 +8054,12 @@ packages: dev: false name: '@rush-temp/app-configuration' resolution: - integrity: sha512-yJDtTyHY5zn/FYWeUSqeDtNd3VSJUA5gpTfyf++Yb/UzqxP4NfsAK/JGKFHmOO22JwdL4Fe38e/to62LC7cH8A== + integrity: sha512-vJiXNRgX0hjI2sRdp0HCa9fd4zXqvLaBSkTQS+vhvlL2Pwt/82w1CzLN+ulAatDZntbDmPO4ch/MsSJG+wdyZQ== tarball: file:projects/app-configuration.tgz version: 0.0.0 file:projects/attestation.tgz: dependencies: + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@types/chai': 4.2.14 @@ -7952,8 +8068,8 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 buffer: 5.7.1 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 dotenv: 8.2.0 eslint: 7.19.0 jsrsasign: 10.1.5 @@ -7986,12 +8102,13 @@ packages: dev: false name: '@rush-temp/attestation' resolution: - integrity: sha512-9jKCXnBFfSRuCq5M55p3cw7GB3Jdsxd8TxG+lsVZeWYnvEvYlY6ecZhBwEHmBrCoYksFAgJNVdvt9nQUarBRLA== + integrity: sha512-gw5DkWNXWrIKsxZa7RrkO7IfS4kmuoh9l4K9c4ZdlALtI7s03Ife/1LeZ7VsvYRDk9DvCUEplTB0vr/HSWlTMA== tarball: file:projects/attestation.tgz version: 0.0.0 file:projects/communication-administration.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-documenter': 7.8.56 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 @@ -8005,7 +8122,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -8041,7 +8158,7 @@ packages: dev: false name: '@rush-temp/communication-administration' resolution: - integrity: sha512-DlH2e+6tExD7zxBhMDBu339Y/a/BkEdmdW33woggxl9qA3aQwX2YqdUHyjkYWJhvJ99GjhwfD/l8TfqIRDLDuA== + integrity: sha512-ohPRQvHq35uX34dN4OwCdEX0FNkyjJT16XQOd/w5x53lPJk4qMVHDH7001zmMSTi2mQExuIw74EKgTKJ087oFA== tarball: file:projects/communication-administration.tgz version: 0.0.0 file:projects/communication-chat.tgz: @@ -8060,7 +8177,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -8116,8 +8233,8 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 eslint: 7.19.0 events: 3.2.0 @@ -8157,6 +8274,7 @@ packages: file:projects/communication-identity.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-documenter': 7.8.56 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 @@ -8170,7 +8288,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -8206,12 +8324,13 @@ packages: dev: false name: '@rush-temp/communication-identity' resolution: - integrity: sha512-GL4qaJfqxoP4zSobWm6zUqhsb7R4CtTVS7/Vo2Phv6ScgXNXLKuyufAQ23uSMG4+fCSe1xDevyouXY7uCsB3Cg== + integrity: sha512-FApjkAK1duoiYM/1ItyAPBiGdRIrVGhFCgkHto9/AuEaLIdv9D3Zyg6WlSFHnIsODeLb/qElMfLlXIgy/kN/bw== tarball: file:projects/communication-identity.tgz version: 0.0.0 file:projects/communication-sms.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -8224,7 +8343,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -8259,11 +8378,12 @@ packages: dev: false name: '@rush-temp/communication-sms' resolution: - integrity: sha512-cfyaA/9f1wYUE9I7NAfRaHHbPfZJ6YS/CguUA9DvtwmoD73EuZoCRhWuIn+CPpvP8JSELzXSqN/gsoPJjXtyog== + integrity: sha512-7t8AEusk0xEFQJMI9uqrn9BMj9m/2GfO3TNYg1Dg6fYNzMneQvGq5niflhCPXmayiFWcB45nByWn3aIEXsTtnQ== tarball: file:projects/communication-sms.tgz version: 0.0.0 file:projects/core-amqp.tgz: dependencies: + '@azure/identity': 1.2.2_debug@4.3.1 '@microsoft/api-extractor': 7.7.11 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 '@rollup/plugin-inject': 4.0.2_rollup@1.32.1 @@ -8282,8 +8402,8 @@ packages: assert: 1.5.0 async-lock: 1.2.8 buffer: 5.7.1 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 debug: 4.3.1 dotenv: 8.2.0 @@ -8319,7 +8439,7 @@ packages: dev: false name: '@rush-temp/core-amqp' resolution: - integrity: sha512-VHx+NSvtudVq+DYQPekrLd/8i6u44TjJCE3UYa4S89aydZd06xoXUKjPX7eEy74hl0e9Bf1+poilr8IaqvNhGg== + integrity: sha512-FkZc5385M043S0+h/Tp2H1o7B5fyLzyOx+yMIXSA7TAiO+/7/cdLQ0EAEK2tCtjm7XnX+5G64ZF4lLTYNTLarA== tarball: file:projects/core-amqp.tgz version: 0.0.0 file:projects/core-asynciterator-polyfill.tgz: @@ -8384,7 +8504,7 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 '@types/sinon': 9.0.10 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 downlevel-dts: 0.4.0 eslint: 7.19.0 @@ -8432,7 +8552,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 downlevel-dts: 0.4.0 eslint: 7.19.0 @@ -8486,7 +8606,7 @@ packages: '@types/uuid': 8.3.0 '@types/xml2js': 0.4.8 babel-runtime: 6.26.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 downlevel-dts: 0.4.0 eslint: 7.19.0 @@ -8495,7 +8615,7 @@ packages: form-data: 3.0.0 glob: 7.1.6 karma: 5.2.3 - karma-chai: 0.1.0_chai@4.3.0+karma@5.2.3 + karma-chai: 0.1.0_chai@4.2.0+karma@5.2.3 karma-chrome-launcher: 3.1.0 karma-edge-launcher: 0.4.2_karma@5.2.3 karma-firefox-launcher: 1.3.0 @@ -8548,7 +8668,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 '@types/uuid': 8.3.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 downlevel-dts: 0.4.0 eslint: 7.19.0 @@ -8599,7 +8719,7 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 eslint: 7.19.0 events: 3.2.0 karma: 5.2.3 @@ -8696,7 +8816,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 '@types/xml2js': 0.4.8 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 downlevel-dts: 0.4.0 eslint: 7.19.0 @@ -8734,6 +8854,7 @@ packages: version: 0.0.0 file:projects/cosmos.tgz: dependencies: + '@azure/identity': 1.2.2_debug@4.3.1 '@microsoft/api-extractor': 7.7.11 '@rollup/plugin-json': 4.1.0_rollup@1.32.1 '@rollup/plugin-multi-entry': 3.0.1_rollup@1.32.1 @@ -8784,7 +8905,7 @@ packages: dev: false name: '@rush-temp/cosmos' resolution: - integrity: sha512-I745iqJTw3qCozHy60mRJTyaMXfDJRhT+4bjEKnqxo1HtLV8d+Mksl34z3KoyUhrIC4dlOR08VIHF+d/xz5Mag== + integrity: sha512-vDYwr7b09/0WjVOd89rZUnd856fS9mr6wk5BYWxHF06wFMaezN0mzzWzg7svZnthNTfy07MIZe2vkzHBAbvhDA== tarball: file:projects/cosmos.tgz version: 0.0.0 file:projects/data-tables.tgz: @@ -8806,7 +8927,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 '@types/uuid': 8.3.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 downlevel-dts: 0.4.0 @@ -8861,8 +8982,8 @@ packages: '@types/node': 8.10.66 '@types/prettier': 2.0.2 builtin-modules: 3.1.0 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 chalk: 3.0.0 eslint: 7.19.0 fs-extra: 8.1.0 @@ -8885,6 +9006,7 @@ packages: file:projects/digital-twins-core.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -8896,7 +9018,7 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 '@types/sinon': 9.0.10 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -8932,7 +9054,7 @@ packages: dev: false name: '@rush-temp/digital-twins-core' resolution: - integrity: sha512-0CjcSbQui3L29TEfVxqqFJ80Yd9Q78fj+fIYT96YaKJHqXashlW4pPjvMjxDdB4NbzlNK1O7qRCOSN2PwecDkA== + integrity: sha512-SALLSa/L1wNxKLeWY1MUVDocJRDp1pSu2k2IGz6RSk4snslKppwgbG7kvNMK8L+kbkqEt/zH8Q+Yl9q+Ep9hTw== tarball: file:projects/digital-twins-core.tgz version: 0.0.0 file:projects/eslint-plugin-azure-sdk.tgz: @@ -8948,7 +9070,7 @@ packages: '@typescript-eslint/experimental-utils': 4.13.0_eslint@7.19.0+typescript@4.1.2 '@typescript-eslint/parser': 4.13.0_eslint@7.19.0+typescript@4.1.2 '@typescript-eslint/typescript-estree': 4.13.0_typescript@4.1.2 - chai: 4.3.0 + chai: 4.2.0 eslint: 7.19.0 eslint-config-prettier: 7.2.0_eslint@7.19.0 eslint-plugin-import: 2.22.1_eslint@7.19.0 @@ -8974,6 +9096,7 @@ packages: file:projects/event-hubs.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2_debug@4.3.1 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -8995,9 +9118,9 @@ packages: '@types/ws': 7.4.0 assert: 1.5.0 buffer: 5.7.1 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 - chai-string: 1.5.0_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 + chai-string: 1.5.0_chai@4.2.0 cross-env: 7.0.3 debug: 4.3.1 dotenv: 8.2.0 @@ -9041,7 +9164,7 @@ packages: dev: false name: '@rush-temp/event-hubs' resolution: - integrity: sha512-20T2CbtsC2nRkXKbFGASPFDQtYsdCC8dSjnI6HI98yR4PYGDe9GOrqSkw83CS5EtVIOdm/Q8ciexMLZzHt7gIw== + integrity: sha512-xETGwr2xSOcJszIC8uN+l9saMzi2aspoROI1C+AcYA62gq/6oqQWakiCo+h3Pmbw4VydxB/WJH598x+hXq/n/g== tarball: file:projects/event-hubs.tgz version: 0.0.0 file:projects/event-processor-host.tgz: @@ -9065,9 +9188,9 @@ packages: '@types/ws': 7.4.0 async-lock: 1.2.8 azure-storage: 2.10.3 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 - chai-string: 1.5.0_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 + chai-string: 1.5.0_chai@4.2.0 cross-env: 7.0.3 debug: 4.3.1 dotenv: 8.2.0 @@ -9112,8 +9235,8 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 '@types/uuid': 8.3.0 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9170,9 +9293,9 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 assert: 1.5.0 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 - chai-string: 1.5.0_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 + chai-string: 1.5.0_chai@4.2.0 cross-env: 7.0.3 debug: 4.3.1 dotenv: 8.2.0 @@ -9216,6 +9339,7 @@ packages: file:projects/identity.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/msal-browser': 2.9.0 '@azure/msal-node': 1.0.0-beta.6 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 @@ -9271,12 +9395,13 @@ packages: optionalDependencies: keytar: 7.3.0 resolution: - integrity: sha512-RkgNLuiYgllsKZCWqAgG5YWRjgD/90RbafjKLQa/t0BYJLbvR3k/c9UVNGZDSh6ScpnSCmQ8eCr0+FGM3eB2yg== + integrity: sha512-tFR61LCHIZDfYb97aYITRuRpTDM7+7O4bQt+Rxuj07YPyrHQH11lmrFsSq2RwaEJUG6W9qfAkvo2ONiPK5k3fw== tarball: file:projects/identity.tgz version: 0.0.0 file:projects/keyvault-admin.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9291,8 +9416,8 @@ packages: '@types/sinon': 9.0.10 '@types/uuid': 8.3.0 assert: 1.5.0 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9316,12 +9441,13 @@ packages: dev: false name: '@rush-temp/keyvault-admin' resolution: - integrity: sha512-H3/yHvEC5jsPdl2owV1o0xpWmiVPs25gankrSY6FsSFLkdNduPCgQa5Z+4m6YWmFAIRwtN2kSKXrpiYdknKoOA== + integrity: sha512-9NnRZp6vmo22fomKbX+ClnTVreBRiL6K09n5kO67FdE2IbQB3kTDUu92JVqfbN9zH9WuPkJWbqRCZZZ5GLeRfg== tarball: file:projects/keyvault-admin.tgz version: 0.0.0 file:projects/keyvault-certificates.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9335,7 +9461,7 @@ packages: '@types/query-string': 6.2.0 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9374,7 +9500,7 @@ packages: dev: false name: '@rush-temp/keyvault-certificates' resolution: - integrity: sha512-o3ghASRcoAlfjxR42rXMha3bLnqgdSOukj7RyLp71C6+cK9do6laBaVHpqOT78xdOwjeTyG/6wb2Ra27XBWMxA== + integrity: sha512-qyVfG67mY4BXNwrxZQEpmkvCv2rBMrcw87usUqJWgSRrW85ogGLrMoc2oGz1DGgQb/5BEvkq6AlQzN/uvmnUYQ== tarball: file:projects/keyvault-certificates.tgz version: 0.0.0 file:projects/keyvault-common.tgz: @@ -9395,6 +9521,7 @@ packages: file:projects/keyvault-keys.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9409,8 +9536,8 @@ packages: '@types/query-string': 6.2.0 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9449,12 +9576,13 @@ packages: dev: false name: '@rush-temp/keyvault-keys' resolution: - integrity: sha512-2T3z2w3gA8WLmpZNCAXxQPEkyE3yiO6cOBHKt/UEXwCris9pvqpkfbMcEmkaX+gWwiNt0ptXJlnysziiiB7Auw== + integrity: sha512-EIAYkwSRbB03KxPTanpduIrQxlcmaIns+H3Y1yGG7rycgQwxDkKzyiy9R+FTdT4mOQZ5jnMoFzdcgr8Z1d9kxg== tarball: file:projects/keyvault-keys.tgz version: 0.0.0 file:projects/keyvault-secrets.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9468,7 +9596,7 @@ packages: '@types/query-string': 6.2.0 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9507,7 +9635,7 @@ packages: dev: false name: '@rush-temp/keyvault-secrets' resolution: - integrity: sha512-0YATav4fEaDDSzFb+Lj0o3/NuqOIyTTCyK6sdJ7kpBQOEOh/o8oI+uRRlF+9h2Y3o3Fta6ZYThc7NUrdwRJAeA== + integrity: sha512-2UgSPUIIwue+sJAiKRf/hrsutSTTJI+Yk1HtaXLMF7VdAh9WEhsd+kCRl6GoUJrKIgWueS3H1yTYev1qJuHZpg== tarball: file:projects/keyvault-secrets.tgz version: 0.0.0 file:projects/logger.tgz: @@ -9522,7 +9650,7 @@ packages: '@types/node': 8.10.66 '@types/sinon': 9.0.10 assert: 1.5.0 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 delay: 4.4.1 dotenv: 8.2.0 @@ -9561,6 +9689,9 @@ packages: file:projects/mock-hub.tgz: dependencies: '@types/node': 8.10.66 + dotenv: 8.2.0 + eslint: 7.19.0 + prettier: 1.19.1 rhea: 1.0.24 rimraf: 3.0.2 tslib: 2.1.0 @@ -9568,7 +9699,7 @@ packages: dev: false name: '@rush-temp/mock-hub' resolution: - integrity: sha512-2MtOIpVJk5Or798q7DCa4gKG3rSE+X+nk0lGPUDlbyXCNt4QDyxHMvrjSO02T6Bvv/KzfJNwIzsFLlgRAgmwQw== + integrity: sha512-Lro7rFcnDNWYuWUIr9czVrfJjSIadiaDU6I945N80JjHUW4RnMZ2WZY9Dr8v+iA1jlMEF7p6Sw0pzIpllGzQqA== tarball: file:projects/mock-hub.tgz version: 0.0.0 file:projects/monitor-opentelemetry-exporter.tgz: @@ -9603,10 +9734,12 @@ packages: version: 0.0.0 file:projects/quantum-jobs.tgz: dependencies: + '@azure/identity': 1.2.2 '@azure/storage-blob': 12.4.1 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 + '@rollup/plugin-inject': 4.0.2_rollup@1.32.1 '@rollup/plugin-json': 4.1.0_rollup@1.32.1 '@rollup/plugin-multi-entry': 3.0.1_rollup@1.32.1 '@rollup/plugin-node-resolve': 8.4.0_rollup@1.32.1 @@ -9615,7 +9748,8 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 '@types/sinon': 9.0.10 - chai: 4.3.0 + assert: 1.5.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9635,17 +9769,21 @@ packages: karma-mocha: 2.0.1 karma-mocha-reporter: 2.2.5_karma@5.2.3 karma-sourcemap-loader: 0.3.8 + mkdirp: 1.0.4 mocha: 7.2.0 mocha-junit-reporter: 1.23.3_mocha@7.2.0 + nock: 12.0.3 nyc: 14.1.1 prettier: 1.19.1 rimraf: 3.0.2 rollup: 1.32.1 + rollup-plugin-node-resolve: 3.4.0 rollup-plugin-shim: 1.0.0 rollup-plugin-sourcemaps: 0.4.2_rollup@1.32.1 rollup-plugin-terser: 5.3.1_rollup@1.32.1 rollup-plugin-visualizer: 4.2.0_rollup@1.32.1 sinon: 9.2.4 + ts-node: 8.10.2_typescript@4.1.2 tslib: 2.1.0 typedoc: 0.15.2 typescript: 4.1.2 @@ -9654,11 +9792,12 @@ packages: dev: false name: '@rush-temp/quantum-jobs' resolution: - integrity: sha512-JZ9vo+AtAREX5yO4s9Ax/h4yMA4R9dv3lnvM2o4y3zz0Ps1+hZHH2sXpF2po8T+CiAaoo73Xrjt8B2ut18/kGQ== + integrity: sha512-2+3shWDeSQceYptcSzu3vZZRkplgwoOHfbvrrFsjS7a2vvbBlya/vw7YwbTEULJNNHTmfBuKRZxPxC012Fqlng== tarball: file:projects/quantum-jobs.tgz version: 0.0.0 file:projects/schema-registry-avro.tgz: dependencies: + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9673,8 +9812,8 @@ packages: '@types/node': 8.10.66 avsc: 5.5.3 buffer: 5.7.1 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9709,11 +9848,12 @@ packages: dev: false name: '@rush-temp/schema-registry-avro' resolution: - integrity: sha512-WIat3YB9zIgvgNyg7brxLCN7gCiDyhVx2iFgF5Is+4y/MNTOf1cDxmq2rAdJLVD+2+H3d0+S0XylwmSLykRBTg== + integrity: sha512-jOZLueDs5biRkOPBfkPKfvIUmJz7Pu0bXxORAedq2Z4DAtumq/cCK3ALDPlKBU3HIYyf30yyxzt1ErT9U0Y4Rg== tarball: file:projects/schema-registry-avro.tgz version: 0.0.0 file:projects/schema-registry.tgz: dependencies: + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9725,8 +9865,8 @@ packages: '@types/chai-as-promised': 7.1.3 '@types/mocha': 7.0.2 '@types/node': 8.10.66 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9760,7 +9900,7 @@ packages: dev: false name: '@rush-temp/schema-registry' resolution: - integrity: sha512-yy0HVV9mYB8FxDTNrhQqeQcq6XifjUWKFMQfrA9KE/XP8IfVKdwjYV7mb9DcD6kmCkEpTRtlw/UZL4SiYnxBbA== + integrity: sha512-Why63wHyaPOVy7wJ+yKEluJdbDCBhFpBlu4PcnYkTQ3yf1b6JvzbzCvuzqBWkjfZOmwgDuExHgOOK4TBUWW8iQ== tarball: file:projects/schema-registry.tgz version: 0.0.0 file:projects/search-documents.tgz: @@ -9777,7 +9917,7 @@ packages: '@types/mocha': 7.0.2 '@types/node': 8.10.66 '@types/sinon': 9.0.10 - chai: 4.3.0 + chai: 4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 @@ -9821,6 +9961,7 @@ packages: file:projects/service-bus.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2_debug@4.3.1 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -9841,9 +9982,9 @@ packages: '@types/ws': 7.4.0 assert: 1.5.0 buffer: 5.7.1 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 - chai-exclude: 2.0.2_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 + chai-exclude: 2.0.2_chai@4.2.0 cross-env: 7.0.3 debug: 4.3.1 delay: 4.4.1 @@ -9891,12 +10032,13 @@ packages: dev: false name: '@rush-temp/service-bus' resolution: - integrity: sha512-xphAdLxETXLn1dV6/vfN9k+nCEg/2CKvAgrbTdL6Sv0flF3eUBMPYPekGq5MXKe85Eb/UAO2ge8RZO7QPaCyhg== + integrity: sha512-q1r29nK28/wAZQ07UlxUpJgC7d1GtySwIBXNLde6IPtdYPCoLHVzb+G3JkYhu/Pr6Svpt8aWsnrrGxYxxeL2AA== tarball: file:projects/service-bus.tgz version: 0.0.0 file:projects/storage-blob-changefeed.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@azure/storage-blob': 12.4.1 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 @@ -9950,13 +10092,14 @@ packages: dev: false name: '@rush-temp/storage-blob-changefeed' resolution: - integrity: sha512-ykcO/ViVTF0Lfk2MHd+BG6eP0XFYsHuBRRaYAb5bEJiD+9uPPj0N4qcMUPjRciAJOlRV2A2G2+ThY/AsfHbvzg== + integrity: sha512-26NUv/t3bRlRb5PQR4Y0F9eFu8+4jJUPP+Q6kjk/+7TeQLkz7B4HLj7aeNL07Q63OycvjDWlL5Nx0i/YKzu+uA== tarball: file:projects/storage-blob-changefeed.tgz version: 0.0.0 file:projects/storage-blob.tgz: dependencies: '@azure/core-https': 1.0.0-beta.1 '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -10010,12 +10153,13 @@ packages: dev: false name: '@rush-temp/storage-blob' resolution: - integrity: sha512-Y5eO2dJze6mrzpq31hgys53/C2KYe7JGGiiasluVq+gcoqLU6yBo/UE1ad6WgoK+I2Y7EzY2LjrO1kXE2O38yQ== + integrity: sha512-zHGarbMd34Fqg42CU77TwP5vjskcOUGbwABZ+jUJhOIjNtA4X+YihIKzzQmb0XCmNQ2yVt0mIgchSMdOqEMkeQ== tarball: file:projects/storage-blob.tgz version: 0.0.0 file:projects/storage-file-datalake.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -10070,7 +10214,7 @@ packages: dev: false name: '@rush-temp/storage-file-datalake' resolution: - integrity: sha512-W5quuvIxHZQWIevkfCqx/pZW2vPJJMqpwlyOdIvhv/u5dHWn6z9fteDBpaEHSfEFdRa++7VeV5EjRPNEo3ED0A== + integrity: sha512-/QQfs65LdbiqWxPV5534FH+SjCQKa6/3xbzQEGt3ZzG0U8PAwpcaO+IsnnmgY7ULcUqtye2+n5zar2l8B+Thqg== tarball: file:projects/storage-file-datalake.tgz version: 0.0.0 file:projects/storage-file-share.tgz: @@ -10183,6 +10327,7 @@ packages: file:projects/storage-queue.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@rollup/plugin-commonjs': 11.0.2_rollup@1.32.1 @@ -10232,7 +10377,7 @@ packages: dev: false name: '@rush-temp/storage-queue' resolution: - integrity: sha512-e9haFMlyQ2lf7I8Bu+8uS57lFO1VHgzJBYT/MxQfiA9ZcMkeepnQcayP2NwWtDs+xAtjkusmayO3BgOeFhfVmw== + integrity: sha512-dSKr31pxZgUe9huKWJTXklF6PzfA2E1dvyWYmZGjTQ3sv1HdxLNR7A1BIIfsejgtevz4qrBbuhR8F4k04ykXLg== tarball: file:projects/storage-queue.tgz version: 0.0.0 file:projects/synapse-access-control.tgz: @@ -10338,23 +10483,19 @@ packages: file:projects/template.tgz: dependencies: '@azure/core-tracing': 1.0.0-preview.9 + '@azure/identity': 1.2.2 '@microsoft/api-extractor': 7.7.11 '@opentelemetry/api': 0.10.2 '@types/chai': 4.2.14 '@types/chai-as-promised': 7.1.3 '@types/mocha': 7.0.2 '@types/node': 8.10.66 - '@typescript-eslint/eslint-plugin': 4.13.0_85649cb1d193687858ee685cdd7abf38 - '@typescript-eslint/parser': 4.13.0_eslint@7.19.0+typescript@4.1.2 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 cross-env: 7.0.3 dotenv: 8.2.0 eslint: 7.19.0 - eslint-config-prettier: 7.2.0_eslint@7.19.0 - eslint-plugin-no-null: 1.0.2_eslint@7.19.0 - eslint-plugin-no-only-tests: 2.4.0 - eslint-plugin-promise: 4.2.1 + events: 3.2.0 inherits: 2.0.4 karma: 5.2.3 karma-chrome-launcher: 3.1.0 @@ -10368,6 +10509,7 @@ packages: karma-junit-reporter: 2.0.1_karma@5.2.3 karma-mocha: 2.0.1 karma-mocha-reporter: 2.2.5_karma@5.2.3 + karma-sourcemap-loader: 0.3.8 mocha: 7.2.0 mocha-junit-reporter: 1.23.3_mocha@7.2.0 nyc: 14.1.1 @@ -10381,7 +10523,7 @@ packages: dev: false name: '@rush-temp/template' resolution: - integrity: sha512-la2ln03RxlmOcz2yifcBlrGPjfvOlBA62qyogBWfpA7kvmeyssMW73fKi4TWN+KQv/H0hJ8FgDJj081qRISSdA== + integrity: sha512-Uw0mPGIwdlVnEEr61oMjgeBbcpZP0XDI8b8Mf/A5mxiMe8IlYfn3a2RGd1uN32YBqNxLDbd3lSR40SW23apJ2Q== tarball: file:projects/template.tgz version: 0.0.0 file:projects/test-utils-multi-version.tgz: @@ -10390,8 +10532,8 @@ packages: '@types/chai': 4.2.14 '@types/mocha': 7.0.2 '@types/node': 8.10.66 - chai: 4.3.0 - chai-as-promised: 7.1.1_chai@4.3.0 + chai: 4.2.0 + chai-as-promised: 7.1.1_chai@4.2.0 eslint: 7.19.0 karma: 5.2.3 karma-chrome-launcher: 3.1.0 @@ -10447,7 +10589,7 @@ packages: '@types/mock-require': 2.0.0 '@types/nise': 1.4.0 '@types/node': 8.10.66 - chai: 4.3.0 + chai: 4.2.0 dotenv: 8.2.0 eslint: 7.19.0 fs-extra: 8.1.0 diff --git a/eng/ignore-links.txt b/eng/ignore-links.txt index 0cac0e9dbddf..1156285fb58d 100644 --- a/eng/ignore-links.txt +++ b/eng/ignore-links.txt @@ -8,3 +8,4 @@ https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/storage/storage-blob-c https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/storage/storage-blob-changefeed/samples/typescript https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/storage/storage-blob-changefeed/test/ https://github.com/Azure/azure-digital-twins/blob/private-preview/Documentation/how-to-manage-routes.md +https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/identity/identity/interactive-browser-credential.md diff --git a/sdk/identity/identity/CHANGELOG.md b/sdk/identity/identity/CHANGELOG.md index 39de4e845fa4..fb6b1a7bd4d9 100644 --- a/sdk/identity/identity/CHANGELOG.md +++ b/sdk/identity/identity/CHANGELOG.md @@ -1,7 +1,8 @@ # Release History -## 1.2.4 (Unreleased) +## 1.2.4-beta.1 (Unreleased) +- Breaking Change: Updated `InteractiveBrowserCredential` to use the Auth Code Flow with PKCE rather than Implicit Grant Flow by default in the browser, to better support browsers with enhanced security restrictions. A new file was added to provide more information about this credential [here](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/identity/identity/interactive-browser-credential.md). ## 1.2.3 (2021-02-09) diff --git a/sdk/identity/identity/README.md b/sdk/identity/identity/README.md index 292c22823888..9479407ebf35 100644 --- a/sdk/identity/identity/README.md +++ b/sdk/identity/identity/README.md @@ -178,33 +178,33 @@ const client = new KeyClient(vaultUrl, credentialChain); | credential | usage | | --------------------------- | --------------------------------------------------------------------------------------------------------------- | -| `DefaultAzureCredential` | provides a simplified authentication experience to quickly start developing applications run in the Azure cloud | -| `ChainedTokenCredential` | allows users to define custom authentication flows composing multiple credentials | -| `EnvironmentCredential` | authenticates a service principal or user via credential information specified in environment variables | -| `ManagedIdentityCredential` | authenticates the managed identity of an Azure resource | +| `DefaultAzureCredential` | Provides a simplified authentication experience to quickly start developing applications run in the Azure cloud. | +| `ChainedTokenCredential` | Allows users to define custom authentication flows composing multiple credentials. | +| `EnvironmentCredential` | Authenticates a service principal or user via credential information specified in environment variables. | +| `ManagedIdentityCredential` | Authenticates the managed identity of an Azure resource. | ### Authenticating Service Principals | credential | usage | | ----------------------------- | ----------------------------------------------------- | -| `ClientSecretCredential` | authenticates a service principal using a secret | -| `ClientCertificateCredential` | authenticates a service principal using a certificate | +| `ClientSecretCredential` | Authenticates a service principal using a secret. | +| `ClientCertificateCredential` | Authenticates a service principal using a certificate. | ### Authenticating Users | credential | usage | | ------------------------------ | ------------------------------------------------------------------ | -| `InteractiveBrowserCredential` | interactively authenticates a user with the default system browser | -| `DeviceCodeCredential` | interactively authenticates a user on devices with limited UI | -| `UserPasswordCredential` | authenticates a user with a username and password | -| `AuthorizationCodeCredential` | authenticate a user with a previously obtained authorization code | +| `InteractiveBrowserCredential` | Interactively authenticates a user with the default system browser. Read more about how this happens [here](https://github.com/Azure/azure-sdk-for-js/blob/master/sdk/identity/identity/interactive-browser-credential.md). | +| `DeviceCodeCredential` | Interactively authenticates a user on devices with limited UI. | +| `UserPasswordCredential` | Authenticates a user with a username and password. | +| `AuthorizationCodeCredential` | Authenticate a user with a previously obtained authorization code. | ### Authenticating via Development Tools | credential | usage | | ---------------------------- | ----------------------------------------------------------------- | -| `AzureCliCredential` | authenticate in a development environment with the Azure CLI | -| `VisualStudioCodeCredential` | authenticate in a development environment with Visual Studio Code | +| `AzureCliCredential` | Authenticate in a development environment with the Azure CLI. | +| `VisualStudioCodeCredential` | Authenticate in a development environment with Visual Studio Code. | ## Troubleshooting diff --git a/sdk/identity/identity/interactive-browser-credential.md b/sdk/identity/identity/interactive-browser-credential.md new file mode 100644 index 000000000000..39cd5b8b11e0 --- /dev/null +++ b/sdk/identity/identity/interactive-browser-credential.md @@ -0,0 +1,16 @@ +# Interactive Browser Credential + +The `InteractiveBrowserCredential` uses [Auth Code Flow][AuthCodeFlow], which uses [Proof Key for Code Exchange (PKCE)](https://tools.ietf.org/html/rfc7636), uses [MSAL v2.x](https://github.com/AzureAD/microsoft-authentication-library-for-js), and is enabled by default. It also allows switching back to the [Implicit Grant Flow][ImplicitGrantFlow] by passing the `flow` property with the value `implicit-grant` through to the constructor of the `InteractiveBrowserCredential`. + +Follow the instructions for [creating your single-page application](https://docs.microsoft.com/azure/active-directory/develop/scenario-spa-app-registration#redirect-uri-msaljs-20-with-auth-code-flow) to correctly mark your redirect URI as enabled for CORS. + +If you attempt to use the authorization code flow and see this error: + +``` +access to XMLHttpRequest at 'https://login.microsoftonline.com/common/v2.0/oauth2/token' from origin 'yourApp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. +``` + +Then you need to visit your app registration and update the redirect URI for your app to type `spa` (for "single page application"). + +[AuthCodeFlow]: https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-auth-code-flow +[ImplicitGrantFlow]: https://docs.microsoft.com/azure/active-directory/develop/v2-oauth2-implicit-grant-flow diff --git a/sdk/identity/identity/package.json b/sdk/identity/identity/package.json index ea35d567f714..b4d1cca027b9 100644 --- a/sdk/identity/identity/package.json +++ b/sdk/identity/identity/package.json @@ -1,7 +1,7 @@ { "name": "@azure/identity", "sdk-type": "client", - "version": "1.2.4", + "version": "1.2.4-beta.1", "description": "Provides credential implementations for Azure SDK libraries that can authenticate with Azure Active Directory", "main": "dist/index.js", "module": "dist-esm/src/index.js", @@ -84,6 +84,7 @@ "@azure/core-tracing": "1.0.0-preview.9", "@azure/logger": "^1.0.0", "@azure/msal-node": "1.0.0-beta.6", + "@azure/msal-browser": "2.9.0", "@opentelemetry/api": "^0.10.2", "@types/express": "^4.16.0", "axios": "^0.21.1", diff --git a/sdk/identity/identity/review/identity.api.md b/sdk/identity/identity/review/identity.api.md index b9307e131eb7..5a66cf26ab04 100644 --- a/sdk/identity/identity/review/identity.api.md +++ b/sdk/identity/identity/review/identity.api.md @@ -145,6 +145,9 @@ export function getDefaultAzureCredential(): TokenCredential; export { GetTokenOptions } +// @public +export type InteractiveBrowserAuthenticationFlow = "implicit-grant" | "auth-code"; + // @public export class InteractiveBrowserCredential implements TokenCredential { constructor(options?: InteractiveBrowserCredentialOptions); @@ -153,7 +156,10 @@ export class InteractiveBrowserCredential implements TokenCredential { // @public export interface InteractiveBrowserCredentialOptions extends TokenCredentialOptions { + authenticationRecord?: AuthenticationRecord; clientId?: string; + correlationId?: string; + flow?: InteractiveBrowserAuthenticationFlow; loginStyle?: BrowserLoginStyle; postLogoutRedirectUri?: string | (() => string); redirectUri?: string | (() => string); diff --git a/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts b/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts index 27a963bd63ac..1e4640177a56 100644 --- a/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts +++ b/sdk/identity/identity/src/credentials/interactiveBrowserCredential.browser.ts @@ -1,7 +1,6 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import * as msal from "msal"; import { AccessToken, TokenCredential, GetTokenOptions } from "@azure/core-http"; import { IdentityClient } from "../client/identityClient"; import { @@ -12,6 +11,9 @@ import { createSpan } from "../util/tracing"; import { CanonicalCode } from "@opentelemetry/api"; import { DefaultTenantId, DeveloperSignOnClientId } from "../constants"; import { credentialLogger, formatSuccess, formatError } from "../util/logging"; +import { MSALAuthCode } from "./msalBrowser/msalAuthCode"; +import { MSALImplicit } from "./msalBrowser/msalImplicit"; +import { IMSALBrowserFlow, MSALOptions } from "./msalBrowser/msalCommon"; const logger = credentialLogger("InteractiveBrowserCredential"); @@ -21,114 +23,75 @@ const logger = credentialLogger("InteractiveBrowserCredential"); * window. */ export class InteractiveBrowserCredential implements TokenCredential { + private tenantId: string; + private clientId: string; private loginStyle: BrowserLoginStyle; - private msalConfig: msal.Configuration; - private msalObject: msal.UserAgentApplication; + private msal: IMSALBrowserFlow; /** * Creates an instance of the InteractiveBrowserCredential with the * details needed to authenticate against Azure Active Directory with * a user identity. * - * @param tenantId - The Azure Active Directory tenant (directory) ID. - * @param clientId - The client (application) ID of an App Registration in the tenant. * @param options - Options for configuring the client which makes the authentication request. */ constructor(options?: InteractiveBrowserCredentialOptions) { + this.tenantId = (options && options.tenantId) || DefaultTenantId; + + // TODO: temporary - this is the Azure CLI clientID - we'll replace it when + // Developer Sign On application is available + // https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/src/Constants.cs#L9 + this.clientId = (options && options.clientId) || DeveloperSignOnClientId; + options = { ...IdentityClient.getDefaultOptions(), ...options, - tenantId: (options && options.tenantId) || DefaultTenantId, - // TODO: temporary - this is the Azure CLI clientID - we'll replace it when - // Developer Sign On application is available - // https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/identity/Azure.Identity/src/Constants.cs#L9 - clientId: (options && options.clientId) || DeveloperSignOnClientId + tenantId: this.tenantId, + clientId: this.clientId }; this.loginStyle = options.loginStyle || "popup"; - if (["redirect", "popup"].indexOf(this.loginStyle) === -1) { - const error = new Error(`Invalid loginStyle: ${options.loginStyle}`); + const loginStyles = ["redirect", "popup"]; + if (loginStyles.indexOf(this.loginStyle) === -1) { + const error = new Error( + `Invalid loginStyle: ${ + options.loginStyle + }. Should be any of the following: ${loginStyles.join(", ")}.` + ); logger.info(formatError("", error)); throw error; } - const knownAuthorities = - options.tenantId === "adfs" ? (options.authorityHost ? [options.authorityHost] : []) : []; - - this.msalConfig = { - auth: { - clientId: options.clientId!, // we just initialized it above - authority: `${options.authorityHost}/${options.tenantId}`, - knownAuthorities, - ...(options.redirectUri && { redirectUri: options.redirectUri }), - ...(options.postLogoutRedirectUri && { redirectUri: options.postLogoutRedirectUri }) - }, - cache: { - cacheLocation: "localStorage", - storeAuthStateInCookie: true - } + const { + clientId, + tenantId, + authorityHost, + correlationId, + redirectUri, + postLogoutRedirectUri, + authenticationRecord + } = options; + + const msalOptions: MSALOptions = { + clientId, + tenantId, + authorityHost, + correlationId, + authenticationRecord, + loginStyle: this.loginStyle, + knownAuthorities: tenantId === "adfs" ? (authorityHost ? [authorityHost] : []) : [], + redirectUri: typeof redirectUri === "function" ? redirectUri() : redirectUri, + postLogoutRedirectUri: + typeof postLogoutRedirectUri === "function" + ? postLogoutRedirectUri() + : postLogoutRedirectUri }; - this.msalObject = new msal.UserAgentApplication(this.msalConfig); - } - - private login(): Promise { - switch (this.loginStyle) { - case "redirect": { - const loginPromise = new Promise((resolve, reject) => { - this.msalObject.handleRedirectCallback(resolve, reject); - }); - this.msalObject.loginRedirect(); - return loginPromise; - } - case "popup": - return this.msalObject.loginPopup(); - } - } - - private async acquireToken( - authParams: msal.AuthenticationParameters - ): Promise { - let authResponse: msal.AuthResponse | undefined; - try { - logger.info("Attempting to acquire token silently"); - authResponse = await this.msalObject.acquireTokenSilent(authParams); - } catch (err) { - if (err instanceof msal.AuthError) { - switch (err.errorCode) { - case "consent_required": - case "interaction_required": - case "login_required": - logger.info(`Authentication returned errorCode ${err.errorCode}`); - break; - default: - logger.info(formatError(authParams.scopes, `Failed to acquire token: ${err.message}`)); - throw err; - } - } - } - - let authPromise: Promise | undefined; - if (authResponse === undefined) { - logger.info( - `Silent authentication failed, falling back to interactive method ${this.loginStyle}` - ); - switch (this.loginStyle) { - case "redirect": - authPromise = new Promise((resolve, reject) => { - this.msalObject.handleRedirectCallback(resolve, reject); - }); - this.msalObject.acquireTokenRedirect(authParams); - break; - case "popup": - authPromise = this.msalObject.acquireTokenPopup(authParams); - break; - } - - authResponse = authPromise && (await authPromise); + if (options.flow === "implicit-grant") { + this.msal = new MSALImplicit(msalOptions); + } else { + this.msal = new MSALAuthCode(msalOptions); } - - return authResponse; } /** @@ -147,13 +110,25 @@ export class InteractiveBrowserCredential implements TokenCredential { ): Promise { const { span } = createSpan("InteractiveBrowserCredential-getToken", options); try { - if (!this.msalObject.getAccount()) { - await this.login(); + const authResponse = await this.msal.acquireToken({ + scopes, + ...options + }); + + if (!authResponse) { + logger.getToken.info("No response"); + return null; } - const authResponse = await this.acquireToken({ - scopes: Array.isArray(scopes) ? scopes : scopes.split(",") - }); + if (!authResponse.expiresOn) { + logger.getToken.info(`Response had no "expiresOn" property.`); + return null; + } + + if (!authResponse.accessToken) { + logger.getToken.info(`Response had no "accessToken" property.`); + return null; + } if (authResponse) { const expiresOnTimestamp = authResponse.expiresOn.getTime(); diff --git a/sdk/identity/identity/src/credentials/interactiveBrowserCredentialOptions.ts b/sdk/identity/identity/src/credentials/interactiveBrowserCredentialOptions.ts index 5c5cec1820c0..6ab86432a040 100644 --- a/sdk/identity/identity/src/credentials/interactiveBrowserCredentialOptions.ts +++ b/sdk/identity/identity/src/credentials/interactiveBrowserCredentialOptions.ts @@ -1,7 +1,9 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. +import { AbortSignalLike } from "@azure/core-http"; import { TokenCredentialOptions } from "../client/identityClient"; +import { AuthenticationRecord } from "../client/msalClient"; /** * The "login style" to use in the authentication flow: @@ -13,11 +15,19 @@ import { TokenCredentialOptions } from "../client/identityClient"; */ export type BrowserLoginStyle = "redirect" | "popup"; +/** + * The Azure authentication flow. + * - Implicit Grant Flow: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow + * - Auth Code Flow: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow + */ +export type InteractiveBrowserAuthenticationFlow = "implicit-grant" | "auth-code"; + /** * Defines options for the InteractiveBrowserCredential class. */ export interface InteractiveBrowserCredentialOptions extends TokenCredentialOptions { /** + * (Only available if used from a browser) * Specifies whether a redirect or a popup window should be used to * initiate the user authentication flow. Possible values are "redirect" * or "popup" (default) for browser and "popup" (default) for node. @@ -46,4 +56,44 @@ export interface InteractiveBrowserCredentialOptions extends TokenCredentialOpti * The client (application) ID of an App Registration in the tenant. */ clientId?: string; + + /** + * Correlation ID that can be customized to keep track of the browser authentication requests. + */ + correlationId?: string; + + /** + * (Only available if used from a browser) + * Result of a previous authentication that can be used to retrieve the cached credentials of each individual account. + * This is necessary to provide in case the application wants to work with more than one account per + * Client ID and Tenant ID pair. + * + * This record can be retrieved by calling to the InteractiveBrowserCredential's `authenticate()` method, as follows: + * + * const authenticationRecord = await credential.authenticate(); + * + */ + authenticationRecord?: AuthenticationRecord; + + /** + * (Only available if used from a browser) + * Authentication flow to use. + * If the user specifies the implicit-grant flow, we will use MSAL 1. + * Otherwise, auth-code will be assumed, which uses PKCE and MSAL 2. + */ + flow?: InteractiveBrowserAuthenticationFlow; +} + +/** + * Optional parameters to the InteractiveBrowserCredential authenticate() method. + */ +export interface InteractiveBrowserAuthenticateOptions { + /** + * The signal which can be used to abort requests. + */ + abortSignal?: AbortSignalLike; + /** + * Scopes to authenticate with. + */ + scopes?: string | string[]; } diff --git a/sdk/identity/identity/src/credentials/msalBrowser/msalAuthCode.ts b/sdk/identity/identity/src/credentials/msalBrowser/msalAuthCode.ts new file mode 100644 index 000000000000..08c2bfa8e46c --- /dev/null +++ b/sdk/identity/identity/src/credentials/msalBrowser/msalAuthCode.ts @@ -0,0 +1,265 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as msalBrowser from "@azure/msal-browser"; +import { AuthenticationRecord } from "../../client/msalClient"; +import { credentialLogger } from "../../util/logging"; +import { + BrowserLoginStyle, + InteractiveBrowserAuthenticateOptions +} from "../interactiveBrowserCredentialOptions"; +import { IMSALBrowserFlow, IMSALToken, MSALOptions } from "./msalCommon"; + +const logger = credentialLogger("MSAL Browser v2 - Auth Code Flow"); + +// We keep a copy of the redirect hash. +const redirectHash = window.location.hash; + +/** + * Uses MSAL Browser 2.X for browser authentication, + * which uses the [Auth Code Flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow). + */ +export class MSALAuthCode implements IMSALBrowserFlow { + private config: msalBrowser.Configuration; + private app: msalBrowser.PublicClientApplication; + private loginStyle: BrowserLoginStyle; + private correlationId?: string; + + /** + * Sets up an MSAL object based on the given parameters. + * MSAL with Auth Code allows sending a previously obtained `authenticationRecord` through the optional parameters, + * which is set to be the active account. + * @param options - Parameters necessary and otherwise used to create the MSAL object. + */ + constructor(options: MSALOptions) { + this.loginStyle = options.loginStyle; + this.correlationId = options.correlationId; + this.config = { + auth: { + clientId: options.clientId!, // we just initialized it above + authority: `${options.authorityHost}/${options.tenantId}`, + knownAuthorities: options.knownAuthorities, + redirectUri: options.redirectUri, + postLogoutRedirectUri: options.postLogoutRedirectUri + }, + cache: { + cacheLocation: "sessionStorage", + storeAuthStateInCookie: true // Set to true to improve the experience on IE11 and Edge. + }, + system: { + loggerOptions: { + loggerCallback: (level, message, containsPii) => { + if (containsPii) { + return; + } + switch (level) { + case msalBrowser.LogLevel.Error: + logger.info(`MSAL Browser V2 error: ${message}`); + return; + case msalBrowser.LogLevel.Info: + logger.info(`MSAL Browser V2 info message: ${message}`); + return; + case msalBrowser.LogLevel.Verbose: + logger.info(`MSAL Browser V2 verbose message: ${message}`); + return; + case msalBrowser.LogLevel.Warning: + logger.info(`MSAL Browser V2 warning: ${message}`); + return; + } + } + } + } + }; + + this.app = new msalBrowser.PublicClientApplication(this.config); + + if (options.authenticationRecord) { + this.app.setActiveAccount(options.authenticationRecord); + } + } + + /** + * Loads the account based on the result of the authentication. + * If no result was received, tries to load the account from the cache. + * @param result - Result object received from MSAL. + */ + private async handleResult( + result?: msalBrowser.AuthenticationResult + ): Promise { + try { + if (result && result.account) { + logger.info(`MSAL Browser V2 authentication successful.`); + this.app.setActiveAccount(result.account); + return result.account; + } + + // If by this point we happen to have an active account, we should stop trying to parse this. + const activeAccount = this.app.getActiveAccount(); + if (activeAccount) { + return activeAccount; + } + + // If we don't have an active account, we try to activate it from all the already loaded accounts. + const accounts = this.app.getAllAccounts(); + if (accounts.length > 1) { + // If there's more than one account in memory, we force the user to authenticate again. + // At this point we can't identify which account should this credential work with, + // since at this point the user won't have provided enough information. + // We log a message in case that helps. + logger.info( + [ + "More than one account was found authenticated for this Client ID and Tenant ID.", + "However, no `authenticationRecord` has been provided for this credential,", + "therefore we're unable to pick between these accounts.", + "A new login attempt will be requested, to ensure the correct account is picked.", + "To work with multiple accounts for the same Client ID and Tenant ID, please provide an `authenticationRecord` when initializing `InteractiveBrowserCredential`." + ].join("\n") + ); + // To safely trigger a new login, we're also ensuring the local cache is cleared up for this MSAL object. + // However, we want to avoid kicking the user out of their authentication on the Azure side. + // We do this by calling to logout while specifying a `onRedirectNavigate` that returns false. + await this.app.logout({ + onRedirectNavigate: () => false + }); + return; + } + + // If there's only one account for this MSAL object, we can safely activate it. + if (accounts.length === 1) { + this.app.setActiveAccount(accounts[0]); + return accounts[0]; + } + + logger.info(`No accounts were found through MSAL.`); + } catch (e) { + logger.info(`Failed to acquire token through MSAL. ${e.message}`); + } + return; + } + + /** + * Uses MSAL to handle the redirect. + */ + public async handleRedirect(): Promise { + return this.handleResult((await this.app.handleRedirectPromise(redirectHash)) || undefined); + } + + /** + * Uses MSAL to trigger a redirect or a popup login. + */ + public async login(scopes: string | string[] = []): Promise { + const arrayScopes = Array.isArray(scopes) ? scopes : [scopes]; + const loginRequest = { + scopes: arrayScopes + }; + switch (this.loginStyle) { + case "redirect": { + await this.app.loginRedirect(loginRequest); + return; + } + case "popup": + return this.handleResult(await this.app.loginPopup(loginRequest)); + } + } + + /** + * Uses MSAL to retrieve the active account. + */ + public getActiveAccount(): AuthenticationRecord | undefined { + return this.app.getActiveAccount() || undefined; + } + + /** + * Allows users to manually authenticate and retrieve the AuthenticationRecord. + * @param options - Optional parameters to authenticate with, like the scope. + */ + public async authenticate( + options: InteractiveBrowserAuthenticateOptions + ): Promise { + // We ensure that redirection is handled at this point. + await this.handleRedirect(); + + // If we have an active account, we return that. + const account = this.getActiveAccount(); + if (account) { + return account; + } + + const scopes = options.scopes; + if (!scopes) { + throw new Error( + `Invalid scopes in the authenticate function of the MSAL Auth Code flow. Received: ${scopes}` + ); + } + + // Otherwise we try to login. + return this.login(scopes); + } + + /** + * Attempts to retrieve an authenticated token from MSAL. + * @param options - Properties useful to retrieve the token, like the scopes and the abortSignal. + */ + public async acquireToken( + options: InteractiveBrowserAuthenticateOptions + ): Promise { + const account = await this.authenticate(options); + + const scopes = options.scopes; + if (!scopes) { + throw new Error( + `Invalid scopes in the acquireToken function of the MSAL Auth Code flow. Received: ${scopes}` + ); + } + + const silentRequest: msalBrowser.SilentRequest = { + authority: this.config.auth.authority!, + correlationId: this.correlationId, // If undefined, MSAL will automatically generate one. + account, + forceRefresh: false, + scopes: Array.isArray(scopes) ? scopes : scopes.split(",") + }; + + let authResponse: msalBrowser.AuthenticationResult | undefined; + + try { + logger.info("Attempting to acquire token silently"); + authResponse = await this.app.acquireTokenSilent(silentRequest); + } catch (err) { + if (err instanceof msalBrowser.AuthError) { + switch (err.errorCode) { + case "consent_required": + case "interaction_required": + case "login_required": + logger.info(`Authentication returned errorCode ${err.errorCode}`); + break; + default: + logger.info(`Failed to acquire token: ${err.message}`); + throw err; + } + } + } + + if (authResponse === undefined) { + logger.info( + `Silent authentication failed, falling back to interactive method ${this.loginStyle}` + ); + switch (this.loginStyle) { + case "redirect": + // This will go out of the page. + // Once the InteractiveBrowserCredential is initialized again, + // we'll load the MSAL account in the constructor. + await this.app.acquireTokenRedirect(silentRequest); + return undefined; + case "popup": + authResponse = await this.app.acquireTokenPopup(silentRequest); + break; + } + } + + return { + accessToken: authResponse.accessToken, + expiresOn: authResponse.expiresOn + }; + } +} diff --git a/sdk/identity/identity/src/credentials/msalBrowser/msalCommon.ts b/sdk/identity/identity/src/credentials/msalBrowser/msalCommon.ts new file mode 100644 index 000000000000..1791a1623d30 --- /dev/null +++ b/sdk/identity/identity/src/credentials/msalBrowser/msalCommon.ts @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { AuthenticationRecord } from "../../client/msalClient"; +import { + BrowserLoginStyle, + InteractiveBrowserAuthenticateOptions +} from "../interactiveBrowserCredentialOptions"; + +/** + * Union of the constructor parameters that all MSAL flow types take. + * Some properties might not be used by some flow types. + */ +export interface MSALOptions { + clientId?: string; + tenantId?: string; + authorityHost?: string; + knownAuthorities?: string[]; + redirectUri?: string; + correlationId?: string; + postLogoutRedirectUri?: string; + authenticationRecord?: AuthenticationRecord; + loginStyle: BrowserLoginStyle; +} + +/** + * The shape we use return the token (and the expiration date). + */ +export interface IMSALToken { + accessToken?: string; + expiresOn: Date | null; +} + +/** + * The common methods we use to work with the MSAL flows. + */ +export interface IMSALBrowserFlow { + handleRedirect(): Promise; + login(scopes: string | string[]): Promise; + getActiveAccount(): AuthenticationRecord | undefined; + acquireToken(options: InteractiveBrowserAuthenticateOptions): Promise; + authenticate( + options: InteractiveBrowserAuthenticateOptions + ): Promise; +} diff --git a/sdk/identity/identity/src/credentials/msalBrowser/msalImplicit.ts b/sdk/identity/identity/src/credentials/msalBrowser/msalImplicit.ts new file mode 100644 index 000000000000..aacf052146ce --- /dev/null +++ b/sdk/identity/identity/src/credentials/msalBrowser/msalImplicit.ts @@ -0,0 +1,232 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as msal from "msal"; +import { AuthenticationRecord } from "../../client/msalClient"; +import { credentialLogger } from "../../util/logging"; +import { + BrowserLoginStyle, + InteractiveBrowserAuthenticateOptions +} from "../interactiveBrowserCredentialOptions"; +import { IMSALBrowserFlow, IMSALToken, MSALOptions } from "./msalCommon"; + +const logger = credentialLogger("MSAL Browser v1 - Implicit Grant Flow"); + +/** + * Uses MSAL directly for browser authentication, + * which uses the [Implicit Grant Flow](https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-implicit-grant-flow) + */ +export class MSALImplicit implements IMSALBrowserFlow { + private config: msal.Configuration; + private app: msal.UserAgentApplication; + private loginStyle: BrowserLoginStyle; + private correlationId?: string; + private tenantId: string; + private account: AuthenticationRecord | undefined; + + /** + * Sets up an MSAL object based on the given parameters. + * MSAL with Implicit Grant is not compatible with the account workflow we use from the MSAL Auth Code flow. + * In this case, any `authenticationRecord` received will be ignored. + * @param options - Parameters necessary and otherwise used to create the MSAL object. + */ + constructor(options: MSALOptions) { + this.loginStyle = options.loginStyle; + this.correlationId = options.correlationId; + this.tenantId = options.tenantId!; + this.config = { + auth: { + clientId: options.clientId!, // we just initialized it above + authority: `${options.authorityHost}/${options.tenantId}`, + knownAuthorities: options.knownAuthorities, + // If the users picked redirect as their login style, + // but they didn't provide a redirectUri, + // we can try to use the current page we're in as a default value. + redirectUri: options.redirectUri || window.location.origin, + postLogoutRedirectUri: options.postLogoutRedirectUri + }, + cache: { + cacheLocation: "localStorage", + storeAuthStateInCookie: true // Set to true to improve the experience on IE11 and Edge. + } + }; + + this.app = new msal.UserAgentApplication(this.config); + } + + /** + * Formats an MSAL 1 account into an `AuthenticationRecord`. + * @param account - The account in the shape defined by MSAL. + */ + private handleAccount(account: msal.Account): AuthenticationRecord { + return { + homeAccountId: account.homeAccountIdentifier, + environment: account.environment, + tenantId: this.tenantId, + localAccountId: account.accountIdentifier, + username: account.environment + }; + } + + /** + * Loads the account based on the result of the authentication. + * If no result was received, tries to load the account from the cache. + * @param result - Result object received from MSAL. + */ + private handleResult(result?: msal.AuthResponse): AuthenticationRecord | undefined { + if (result?.account) { + logger.info(`Authentication successful.`); + this.account = this.handleAccount(result?.account); + return this.account; + } + this.getActiveAccount(); + if (this.account) { + return this.account; + } + return; + } + + private redirectPromise: Promise | undefined; + + /** + * Attempts to handle a redirection request the least amount of times possible. + */ + public async handleRedirect(): Promise { + if (this.account) { + return this.account; + } + if (this.redirectPromise) { + return this.redirectPromise; + } + if (!window.location.hash) { + return; + } + this.redirectPromise = new Promise((resolve, reject) => { + this.app.handleRedirectCallback((result) => { + if (!result?.account) { + const errorMessage = `Authentication failed. No redirect result.`; + logger.info(errorMessage); + reject(new Error(errorMessage)); + } + this.handleResult(result!); + resolve(this.account); + }, reject); + }); + return this.redirectPromise; + } + + /** + * Uses MSAL to trigger a redirect or a popup login. + */ + public async login(): Promise { + if (this.getActiveAccount()) { + return this.account; + } + switch (this.loginStyle) { + case "redirect": { + this.handleRedirect(); + this.app.loginRedirect(); + return this.redirectPromise; + } + case "popup": + return this.handleResult(await this.app.loginPopup()); + } + } + + /** + * Returns the existing account, attempts to load the account from MSAL. + */ + public getActiveAccount(): AuthenticationRecord | undefined { + if (this.account) { + return this.account; + } + const account = this.app.getAccount(); + if (!account) { + return; + } + this.account = this.handleAccount(account); + return this.account; + } + + /** + * Allows users to manually authenticate and retrieve the AuthenticationRecord. + * @param options - Optional parameters to authenticate with, like the scope. + */ + public async authenticate(): Promise { + // We ensure that redirection is handled at this point. + await this.handleRedirect(); + + // If we've been able to retrieve the account, we return it. + if (this.account) { + return this.account; + } + + // Otherwise we try to login. + return this.login(); + } + + /** + * Attempts to retrieve an authenticated token from MSAL. + * @param options - Properties useful to retrieve the token, like the scopes and the abortSignal. + */ + public async acquireToken( + options: InteractiveBrowserAuthenticateOptions + ): Promise { + await this.authenticate(); + + const scopes = options.scopes; + if (!scopes) { + throw new Error( + `Invalid scopes in the acquireToken function of the MSAL Auth Code flow. Received: ${scopes}` + ); + } + + const silentRequest: msal.AuthenticationParameters = { + authority: this.config.auth.authority!, + correlationId: this.correlationId, // If undefined, MSAL will automatically generate one. + scopes: Array.isArray(scopes) ? scopes : scopes.split(",") + }; + + let authResponse: msal.AuthResponse | undefined; + + try { + logger.info("Attempting to acquire token silently"); + authResponse = await this.app.acquireTokenSilent(silentRequest); + } catch (err) { + if (err instanceof msal.AuthError) { + switch (err.errorCode) { + case "consent_required": + case "interaction_required": + case "login_required": + logger.info(`Authentication returned errorCode ${err.errorCode}`); + break; + default: + logger.info(`Failed to acquire token: ${err.message}`); + throw err; + } + } + } + + if (authResponse === undefined) { + logger.info( + `Silent authentication failed, falling back to interactive method ${this.loginStyle}` + ); + switch (this.loginStyle) { + case "redirect": + // This will go out of the page. + // Once the InteractiveBrowserCredential is initialized again, + // we'll load the MSAL account in the constructor. + this.app.acquireTokenRedirect(silentRequest); + return undefined; + case "popup": + authResponse = await this.app.acquireTokenPopup(silentRequest); + break; + } + } + + return { + accessToken: authResponse.accessToken, + expiresOn: authResponse.expiresOn + }; + } +} diff --git a/sdk/identity/identity/src/index.ts b/sdk/identity/identity/src/index.ts index f7046bef7fba..472e6d1b865a 100644 --- a/sdk/identity/identity/src/index.ts +++ b/sdk/identity/identity/src/index.ts @@ -20,7 +20,8 @@ export { AzureCliCredential } from "./credentials/azureCliCredential"; export { AuthenticationRecord } from "./client/msalClient"; export { InteractiveBrowserCredentialOptions, - BrowserLoginStyle + BrowserLoginStyle, + InteractiveBrowserAuthenticationFlow } from "./credentials/interactiveBrowserCredentialOptions"; export { ManagedIdentityCredential } from "./credentials/managedIdentityCredential"; export {