Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Cosmos] Adds AAD client auth option #12793

Merged
merged 43 commits into from
Jan 26, 2021
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
826af74
Adds AAD client option
zfoster Dec 5, 2020
008695a
Fixes
zfoster Dec 7, 2020
d2df868
aad
zfoster Dec 17, 2020
2e874bc
format
zfoster Dec 17, 2020
4f479b9
Fixes AAD initializer and test
zfoster Dec 24, 2020
a86b4dd
Format
zfoster Dec 24, 2020
d8e56f4
Merge branch 'master' into zf/aad
zfoster Dec 25, 2020
bd776bb
remove log
zfoster Dec 25, 2020
178ee9d
Adds type
zfoster Dec 25, 2020
f2b5059
format
zfoster Dec 25, 2020
cc810e7
Adds correct aad type
zfoster Dec 27, 2020
ca45a80
Merge branch 'master' into zf/aad
zfoster Dec 28, 2020
487467c
Merge branch 'master' into zf/aad
zfoster Jan 4, 2021
1d4bac8
Test on 3.9 and latest
southpolesteve Jan 8, 2021
461956f
Update CosmosClientOptions.ts
southpolesteve Jan 8, 2021
08f4d56
Merge branch 'master' into zf/aad
zfoster Jan 8, 2021
7e180ee
Merge branch 'master' into zf/aad
zfoster Jan 9, 2021
5a80bb4
Empty commit
southpolesteve Jan 11, 2021
17c83d5
Merge branch 'master' into zf/aad
zfoster Jan 13, 2021
d1c91a3
Merge branch 'master' into zf/aad
zfoster Jan 13, 2021
9d4050f
Merge branch 'master' into zf/aad
zfoster Jan 15, 2021
2a948b7
Merge branch 'zf/aad' of https://github.com/Azure/azure-sdk-for-js in…
zfoster Jan 15, 2021
875b81b
Merge branch 'master' into zf/aad
zfoster Jan 15, 2021
ec22815
WIP
southpolesteve Jan 17, 2021
0fa7988
Merge branch 'master' into zf/aad
southpolesteve Jan 17, 2021
43d093c
merge
zfoster Jan 20, 2021
1446130
Fix merge
zfoster Jan 20, 2021
2547ec5
Adds eslint plugin back
zfoster Jan 21, 2021
700c4e0
empty commit
zfoster Jan 21, 2021
06b0dd2
Merge branch 'master' into zf/aad
zfoster Jan 21, 2021
5f895f2
Fix typo
zfoster Jan 21, 2021
d42a86c
Merge branch 'master' into zf/aad
zfoster Jan 22, 2021
6c5c026
Merge branch 'master' into zf/aad
zfoster Jan 25, 2021
33a7e08
fix changelog entries
zfoster Jan 25, 2021
19c6706
merge master
zfoster Jan 25, 2021
3820da5
merge pull
zfoster Jan 25, 2021
b6b3224
Merge branch 'master' into zf/aad
southpolesteve Jan 26, 2021
ab7cc6e
Update NPM
southpolesteve Jan 26, 2021
206ffbb
More robust abort test
southpolesteve Jan 26, 2021
5d559e3
More robust abort test
southpolesteve Jan 26, 2021
90c42d7
More
southpolesteve Jan 26, 2021
718c513
REmove only
southpolesteve Jan 26, 2021
d2cb2d4
Merge branch 'master' into zf/aad
zfoster Jan 26, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion sdk/core/abort-controller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
"audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit",
"build:es6": "tsc -p tsconfig.json",
"build:nodebrowser": "rollup -c 2>&1",
"build:types": "downlevel-dts types/src types/3.1",
"build:test": "rollup -c rollup.test.config.js 2>&1",
"build": "npm run build:es6 && npm run build:nodebrowser",
"build": "npm run build:es6 && npm run build:nodebrowser && npm run build:types",
"check-format": "prettier --list-different --config ../../../.prettierrc.json --ignore-path ../../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"",
"clean": "rimraf dist dist-esm dist-test types temp dist-browser/*.js* dist-browser/*.zip statistics.html coverage coverage-browser .nyc_output *.tgz *.log test*.xml TEST*.xml",
"execute:samples": "echo skipped",
Expand All @@ -34,6 +35,13 @@
"docs": "typedoc --excludePrivate --excludeNotExported --excludeExternals --stripInternal --mode file --out ./dist/docs ./src"
},
"types": "./types/src/index.d.ts",
"typesVersions": {
"<3.6": {
"types/src/*": [
"types/3.1/*"
]
}
},
"engine": {
"node": ">=8.0.0"
},
Expand Down Expand Up @@ -82,6 +90,7 @@
"assert": "^1.4.1",
"cross-env": "^7.0.2",
"delay": "^4.2.0",
"downlevel-dts": "~0.4.0",
"eslint": "^7.15.0",
"karma": "^5.1.0",
"karma-chrome-launcher": "^3.0.0",
Expand Down
8 changes: 3 additions & 5 deletions sdk/cosmosdb/cosmos/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
# Release History

## 3.9.6 (Unreleased)
## 3.10.0 (2021-01-21)

- FEATURE: Adds AAD authentication via @azure/identity.

## 3.9.5 (2021-01-18)

- BUGFIX: Throws correct Invalid Continuation Token error when making request with malformed token
- BUGFIX: Defaults partitionKeyValue to `'[{}]'` when missing in Read/Delete bulk operations

## 3.9.4 (2021-01-04)

- BUGFIX: Sums group by operations for cross-partition queries correctly with null values
- BUGFIX: Sums group by operations for cross-partition queries correctly with null values.

## 3.9.3 (2020-10-19)

Expand Down
12 changes: 5 additions & 7 deletions sdk/cosmosdb/cosmos/consumer-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const execa = require("execa");

let versions = ["3.1", "3.2", "3.3", "3.4", "3.5", "3.6"];
let versions = ["3.1", "3.9"];

if (!process.env.SKIP_LATEST) {
versions.push("latest");
Expand All @@ -15,14 +15,12 @@ async function exec(cmd) {

(async () => {
try {
console.log("Running typescript consumer test againast", versions);
await exec("npm init -y");
console.log("Setting up typescript consumer project");
await exec("npm install --save ./..");
console.log("Installing @azure/cosmos as a file dependency");
console.log("Running typescript consumer test against", versions);
for (const version of versions) {
console.log(`Compling with typescript@${version} - Basic`);
await exec(`npx -p typescript@${version} tsc ./test.ts --allowSyntheticDefaultImports true`);
await exec(
`npx -p typescript@${version} tsc ./test.ts --allowSyntheticDefaultImports true --target ES5`
);
console.log(`Compling with typescript@${version} - Custom lib`);
await exec(
`npx -p typescript@${version} tsc ./test.ts --allowSyntheticDefaultImports true --lib es2018`
Expand Down
2 changes: 1 addition & 1 deletion sdk/cosmosdb/cosmos/consumer-test/test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import * as Cosmos from "@azure/cosmos";
import * as Cosmos from "../";

console.log(Object.keys(Cosmos));
5 changes: 3 additions & 2 deletions sdk/cosmosdb/cosmos/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@azure/cosmos",
"version": "3.9.6",
"version": "3.10.0",
"description": "Microsoft Azure Cosmos DB Service Node.js SDK for SQL API",
"sdk-type": "client",
"keywords": [
Expand Down Expand Up @@ -70,7 +70,7 @@
"prebuild": "npm run clean",
"test:browser": "npm run unit-test:browser && npm run integration-test:browser",
"test:node": "npm run build:test && npm run unit-test:node && npm run integration-test:node",
"test-consumer": "node consumer-test.js 2>&1",
"test-consumer": "rimraf consumer-test/node_modules consumer-test/package-lock.json && node consumer-test.js 2>&1",
"test": "npm run unit-test && npm run integration-test",
"test:signoff": "mocha -r esm -r dotenv/config -r ./test/public/common/setup.js \"./test/internal/**/*.spec.ts\" \"./test/public/**/*.spec.ts\" --timeout 100000 --grep \"#nosignoff\" --invert",
"unit-test:browser": "echo skipped",
Expand All @@ -86,6 +86,7 @@
"tsdocFlavor": "AEDoc"
},
"dependencies": {
"@azure/identity": "^1.1.0",
"@types/debug": "^4.1.4",
"debug": "^4.1.1",
"fast-json-stable-stringify": "^2.0.0",
Expand Down
3 changes: 3 additions & 0 deletions sdk/cosmosdb/cosmos/review/cosmos.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

```ts

import { TokenCredential } from '@azure/identity';

// @public (undocumented)
export interface Agent {
// (undocumented)
Expand Down Expand Up @@ -487,6 +489,7 @@ export class CosmosClient {

// @public (undocumented)
export interface CosmosClientOptions {
aadCredentials?: TokenCredential;
agent?: Agent;
connectionPolicy?: ConnectionPolicy;
consistencyLevel?: keyof typeof ConsistencyLevel;
Expand Down
8 changes: 8 additions & 0 deletions sdk/cosmosdb/cosmos/src/CosmosClientOptions.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { TokenCredential } from "@azure/identity";
import { TokenProvider } from "./auth";
import { PermissionDefinition } from "./client";
import { ConnectionPolicy, ConsistencyLevel } from "./documents";
Expand Down Expand Up @@ -28,6 +29,13 @@ export interface CosmosClientOptions {
* Allows users to generating their own auth tokens, potentially using a separate service
*/
tokenProvider?: TokenProvider;
/** AAD token from @azure/identity
* Obtain a credential object by creating an @azure/identity credential object
* We will then use your credential object and a scope URL (your cosmos db endpoint)
* to authenticate requests to Cosmos
* This feature is in private preview and not yet available for every Cosmos account
*/
aadCredentials?: TokenCredential;
/** An array of {@link Permission} objects. */
permissionFeed?: PermissionDefinition[];
/** An instance of {@link ConnectionPolicy} class.
Expand Down
8 changes: 8 additions & 0 deletions sdk/cosmosdb/cosmos/src/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ export async function setAuthorizationHeader(
headers[Constants.HttpHeaders.Authorization] = encodeURIComponent(
await clientOptions.tokenProvider({ verb, path, resourceId, resourceType, headers })
);
} else if (clientOptions.aadCredentials) {
if (typeof clientOptions.aadCredentials?.getToken !== "function") {
throw new Error("Cannot use AAD Credentials without `getToken`. See @azure/identity docs");
}
const token = await clientOptions.aadCredentials.getToken(clientOptions.endpoint);
const AUTH_PREFIX = `type=aad&ver=1.0&sig=`;
const authorizationToken = `${AUTH_PREFIX}${token}`;
headers[Constants.HttpHeaders.Authorization] = encodeURIComponent(authorizationToken);
}
}

Expand Down
21 changes: 20 additions & 1 deletion sdk/cosmosdb/cosmos/test/public/functional/client.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
bulkInsertItems
} from "../common/TestHelpers";
import AbortController from "node-abort-controller";
import { UsernamePasswordCredential } from "@azure/identity";

describe("NodeJS CRUD Tests", function() {
this.timeout(process.env.MOCHA_TIMEOUT || 20000);
Expand Down Expand Up @@ -52,17 +53,35 @@ describe("NodeJS CRUD Tests", function() {
it("throws on a bad endpoint", function() {
assert.throws(() => new CosmosClient({ endpoint: "asda=asda;asada;" }));
});
it("fails to read databases with AAD authentication", async function() {
try {
const credentials = new UsernamePasswordCredential(
"fake-tenant-id",
"fake-client-id",
"fakeUsername",
"fakePassword"
);
const client = new CosmosClient({
endpoint,
aadCredentials: credentials
});
await client.databases.readAll().fetchAll();
} catch (e) {
assert.equal(e.code, 401);
}
});
});
describe("Validate user passed AbortController.signal", function() {
it("should throw exception if aborted during the request", async function() {
const client = new CosmosClient({ endpoint, key: masterKey });
try {
const controller = new AbortController();
const signal = controller.signal;
setTimeout(() => controller.abort(), 5);
setTimeout(() => controller.abort(), 1);
await client.getDatabaseAccount({ abortSignal: signal });
assert.fail("Must throw when trying to connect to database");
} catch (err) {
console.log(err);
assert.equal(err.name, "AbortError", "client should throw exception");
}
});
Expand Down