Skip to content

Commit

Permalink
[keyvault] Verify challenge response matches request domain (#23283)
Browse files Browse the repository at this point in the history
  • Loading branch information
timovv authored Sep 20, 2022
1 parent 2d4557d commit 463f7d4
Show file tree
Hide file tree
Showing 48 changed files with 610 additions and 193 deletions.
10 changes: 9 additions & 1 deletion sdk/keyvault/keyvault-admin/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Release History

## 4.2.3 (Unreleased)
## 4.3.1 (Unreleased)

### Features Added

Expand All @@ -10,6 +10,14 @@

### Other Changes

## 4.3.0 (2022-09-20)

### Breaking Changes

- Verify the challenge resource matches the vault domain.
This should affect few customers who can set `disableChallengeResourceVerification` in the options bag to `true` to disable.
See https://aka.ms/azsdk/blog/vault-uri for more information.

## 4.2.2 (2022-08-09)

### Other Changes
Expand Down
2 changes: 1 addition & 1 deletion sdk/keyvault/keyvault-admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@azure/keyvault-admin",
"sdk-type": "client",
"author": "Microsoft Corporation",
"version": "4.2.3",
"version": "4.3.1",
"license": "MIT",
"description": "Isomorphic client library for Azure KeyVault's administrative functions.",
"homepage": "https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/keyvault/keyvault-admin/README.md",
Expand Down
2 changes: 2 additions & 0 deletions sdk/keyvault/keyvault-admin/review/keyvault-admin.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { TokenCredential } from '@azure/core-auth';

// @public
export interface AccessControlClientOptions extends CommonClientOptions {
disableChallengeResourceVerification?: boolean;
serviceVersion?: SUPPORTED_API_VERSIONS;
}

Expand Down Expand Up @@ -72,6 +73,7 @@ export class KeyVaultBackupClient {

// @public
export interface KeyVaultBackupClientOptions extends CommonClientOptions {
disableChallengeResourceVerification?: boolean;
serviceVersion?: SUPPORTED_API_VERSIONS;
}

Expand Down
6 changes: 3 additions & 3 deletions sdk/keyvault/keyvault-admin/src/accessControlClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ export class KeyVaultAccessControlClient {
*
* let client = new KeyVaultAccessControlClient(vaultUrl, credentials);
* ```
* @param vaultUrl - the URL of the Key Vault. It should have this shape: `https://${your-key-vault-name}.vault.azure.net`
* @param vaultUrl - the URL of the Key Vault. It should have this shape: `https://${your-key-vault-name}.vault.azure.net`. You should validate that this URL references a valid Key Vault or Managed HSM resource. See https://aka.ms/azsdk/blog/vault-uri for details.
* @param credential - An object that implements the `TokenCredential` interface used to authenticate requests to the service. Use the \@azure/identity package to create a credential that suits your needs.
* @param pipelineOptions - Pipeline options used to configure Key Vault API requests. Omit this parameter to use the default pipeline configuration.
* @param options - Options used to configure Key Vault API requests. Omit this parameter to use the default configuration.
*/
constructor(
vaultUrl: string,
Expand Down Expand Up @@ -92,7 +92,7 @@ export class KeyVaultAccessControlClient {
// The scopes will be populated in the challenge callbacks based on the WWW-authenticate header
// returned by the challenge, so pass an empty array as a placeholder.
scopes: [],
challengeCallbacks: createChallengeCallbacks(),
challengeCallbacks: createChallengeCallbacks(options),
})
);
}
Expand Down
6 changes: 6 additions & 0 deletions sdk/keyvault/keyvault-admin/src/accessControlModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ export interface AccessControlClientOptions extends CommonClientOptions {
* The accepted versions of the Key Vault's service API.
*/
serviceVersion?: SUPPORTED_API_VERSIONS;

/**
* Whether to disable verification that the authentication challenge resource matches the Key Vault or Managed HSM domain.
* Defaults to false.
*/
disableChallengeResourceVerification?: boolean;
}

/**
Expand Down
4 changes: 2 additions & 2 deletions sdk/keyvault/keyvault-admin/src/backupClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class KeyVaultBackupClient {
*
* let client = new KeyVaultBackupClient(vaultUrl, credentials);
* ```
* @param vaultUrl - the URL of the Key Vault. It should have this shape: `https://${your-key-vault-name}.vault.azure.net`
* @param vaultUrl - the URL of the Key Vault. It should have this shape: `https://${your-key-vault-name}.vault.azure.net`. You should validate that this URL references a valid Key Vault or Managed HSM resource. See https://aka.ms/azsdk/blog/vault-uri for details.
* @param credential - An object that implements the `TokenCredential` interface used to authenticate requests to the service. Use the \@azure/identity package to create a credential that suits your needs.
* @param options - options used to configure Key Vault API requests.
*/
Expand Down Expand Up @@ -95,7 +95,7 @@ export class KeyVaultBackupClient {
// The scopes will be populated in the challenge callbacks based on the WWW-authenticate header
// returned by the challenge, so pass an empty array as a placeholder.
scopes: [],
challengeCallbacks: createChallengeCallbacks(),
challengeCallbacks: createChallengeCallbacks(options),
})
);
}
Expand Down
6 changes: 6 additions & 0 deletions sdk/keyvault/keyvault-admin/src/backupClientModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ export interface KeyVaultBackupClientOptions extends CommonClientOptions {
* The accepted versions of the Key Vault's service API.
*/
serviceVersion?: SUPPORTED_API_VERSIONS;

/**
* Whether to disable verification that the authentication challenge resource matches the Key Vault or Managed HSM domain.
* Defaults to false.
*/
disableChallengeResourceVerification?: boolean;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion sdk/keyvault/keyvault-admin/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/**
* Current version of the Key Vault Admin SDK.
*/
export const SDK_VERSION: string = "4.2.3";
export const SDK_VERSION: string = "4.3.1";

/**
* The latest supported Key Vault service API version.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion sdk/keyvault/keyvault-admin/swagger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ input-file:
- https://raw.githubusercontent.com/Azure/azure-rest-api-specs/e2ef44b87405b412403ccb005bfb3975411adf60/specification/keyvault/data-plane/Microsoft.KeyVault/stable/7.3/backuprestore.json
output-folder: ../
source-code-folder-path: ./src/generated
package-version: 4.2.3
package-version: 4.3.1
use-extension:
"@autorest/typescript": "6.0.0-beta.15"
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe("Challenge based authentication tests", function () {
let challengeCallbacks: ChallengeCallbacks;

beforeEach(() => {
request = createPipelineRequest({ url: "https://foo.bar" });
request = createPipelineRequest({ url: "https://myvault.vault.azure.net" });
challengeCallbacks = createChallengeCallbacks();
});

Expand Down Expand Up @@ -59,7 +59,7 @@ describe("Challenge based authentication tests", function () {
request,
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="cae_scope"`,
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
Expand Down Expand Up @@ -118,36 +118,100 @@ describe("Challenge based authentication tests", function () {
request,
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="cae_scope"`,
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
},
scopes: [],
});

assert.sameMembers(getAccessTokenScopes, ["cae_scope/.default"]);
assert.sameMembers(getAccessTokenScopes, ["https://vault.azure.net/.default"]);
});

it("prefers resource scope and adds .default to resource when provided", async () => {
let getAccessTokenScopes: string[] = [];
it("throws if the resource is not a valid URL", async () => {
await assert.isRejected(
challengeCallbacks.authorizeRequestOnChallenge!({
getAccessToken: () => Promise.resolve(null),
request,
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="invalid_scope"`,
}),
request,
status: 200,
},
scopes: [],
}),
`The challenge contains invalid scope 'invalid_scope/.default'`
);
});

it("throws if the resource URI host does not match the request by default", async () => {
await assert.isRejected(
challengeCallbacks.authorizeRequestOnChallenge!({
getAccessToken: () => Promise.resolve(null),
request: createPipelineRequest({ url: "https://foo.bar" }),
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
},
scopes: [],
}),
"The challenge resource 'vault.azure.net' does not match the requested domain. Set disableChallengeResourceVerification to true in your client options to disable. See https://aka.ms/azsdk/blog/vault-uri for more information."
);
});

it("throws if the request host is a prefix, but not a subdomain, of the resource URI host", async () => {
await assert.isRejected(
challengeCallbacks.authorizeRequestOnChallenge!({
getAccessToken: () => Promise.resolve(null),
request: createPipelineRequest({ url: "https://myvault.azure.net" }),
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
},
scopes: [],
}),
"The challenge resource 'vault.azure.net' does not match the requested domain. Set disableChallengeResourceVerification to true in your client options to disable. See https://aka.ms/azsdk/blog/vault-uri for more information."
);
});

it("does not throw if the resource URI matches the request", async () => {
await challengeCallbacks.authorizeRequestOnChallenge!({
getAccessToken: (scopes) => {
getAccessTokenScopes = scopes;
return Promise.resolve(null);
},
request,
getAccessToken: () => Promise.resolve(null),
request: createPipelineRequest({ url: "https://myvault.vault.azure.net" }),
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="cae_resource", scope="cae_scope"`,
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
},
scopes: [],
});
});

assert.sameMembers(getAccessTokenScopes, ["cae_resource/.default"]);
it("does not throw if the resource URI host does not match the request but verifyChallengeResource is false", async () => {
challengeCallbacks = createChallengeCallbacks({ disableChallengeResourceVerification: true });
await challengeCallbacks.authorizeRequestOnChallenge!({
getAccessToken: () => Promise.resolve(null),
request: createPipelineRequest({ url: "https://foo.bar" }),
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
},
scopes: [],
});
});

it("passes the tenantId if provided", async () => {
Expand All @@ -163,7 +227,7 @@ describe("Challenge based authentication tests", function () {
request,
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="cae_scope" authorization="http://login.windows.net/${expectedTenantId}"`,
"WWW-Authenticate": `Bearer resource="https://vault.azure.net" authorization="http://login.windows.net/${expectedTenantId}"`,
}),
request,
status: 200,
Expand All @@ -182,7 +246,7 @@ describe("Challenge based authentication tests", function () {
request,
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="cae_scope"`,
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
Expand All @@ -200,7 +264,7 @@ describe("Challenge based authentication tests", function () {
request,
response: {
headers: createHttpHeaders({
"WWW-Authenticate": `Bearer resource="cae_scope"`,
"WWW-Authenticate": `Bearer resource="https://vault.azure.net"`,
}),
request,
status: 200,
Expand Down
10 changes: 9 additions & 1 deletion sdk/keyvault/keyvault-certificates/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Release History

## 4.5.1 (Unreleased)
## 4.6.1 (Unreleased)

### Features Added

Expand All @@ -10,6 +10,14 @@

### Other Changes

## 4.6.0 (2022-09-20)

### Breaking Changes

- Verify the challenge resource matches the vault domain.
This should affect few customers who can set `disableChallengeResourceVerification` in the options bag to `true` to disable.
See https://aka.ms/azsdk/blog/vault-uri for more information.

## 4.5.0 (2022-08-09)

### Breaking Changes
Expand Down
2 changes: 1 addition & 1 deletion sdk/keyvault/keyvault-certificates/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "@azure/keyvault-certificates",
"sdk-type": "client",
"author": "Microsoft Corporation",
"version": "4.5.1",
"version": "4.6.1",
"license": "MIT",
"description": "Isomorphic client library for Azure KeyVault's certificates.",
"homepage": "https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/keyvault/keyvault-certificates/README.md",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export class CertificateClient {

// @public
export interface CertificateClientOptions extends ExtendedCommonClientOptions {
disableChallengeResourceVerification?: boolean;
serviceVersion?: "7.0" | "7.1" | "7.2" | "7.3";
}

Expand Down
8 changes: 7 additions & 1 deletion sdk/keyvault/keyvault-certificates/src/certificatesModels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ import {
export const LATEST_API_VERSION = "7.3";

/**
* The optional parameters accepted by the KeyVault's KeyClient
* The optional parameters accepted by the KeyVault's CertificateClient
*/
export interface CertificateClientOptions extends ExtendedCommonClientOptions {
/**
* The accepted versions of the KeyVault's service API.
*/
serviceVersion?: "7.0" | "7.1" | "7.2" | "7.3";

/**
* Whether to disable verification that the authentication challenge resource matches the Key Vault domain.
* Defaults to false.
*/
disableChallengeResourceVerification?: boolean;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion sdk/keyvault/keyvault-certificates/src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

export const SDK_VERSION: string = "4.5.1";
export const SDK_VERSION: string = "4.6.1";

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions sdk/keyvault/keyvault-certificates/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ export class CertificateClient {

/**
* Creates an instance of CertificateClient.
* @param vaultUrl - the base URL to the vault.
* @param vaultUrl - the base URL to the vault. You should validate that this URL references a valid Key Vault resource. See https://aka.ms/azsdk/blog/vault-uri for details.
* @param credential - An object that implements the `TokenCredential` interface used to authenticate requests to the service. Use the \@azure/identity package to create a credential that suits your needs.
* @param clientOptions - Pipeline options used to configure Key Vault API requests.
* Omit this parameter to use the default pipeline configuration.
Expand All @@ -251,7 +251,7 @@ export class CertificateClient {
const authPolicy = bearerTokenAuthenticationPolicy({
credential,
scopes: [],
challengeCallbacks: createChallengeCallbacks(),
challengeCallbacks: createChallengeCallbacks(clientOptions),
});

const internalClientPipelineOptions: InternalClientPipelineOptions = {
Expand Down
2 changes: 1 addition & 1 deletion sdk/keyvault/keyvault-certificates/swagger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/e2ef44b
output-folder: ../
source-code-folder-path: ./src/generated
hide-clients: true
package-version: 4.5.1
package-version: 4.6.1
openapi-type: data-plane
```
Loading

0 comments on commit 463f7d4

Please sign in to comment.