Skip to content

Commit

Permalink
[core] bearerTokenAuthenticationPolicy shouldn't sign HTTP URLs (#15785)
Browse files Browse the repository at this point in the history
  • Loading branch information
sadasant authored Jun 18, 2021
1 parent a955ff2 commit f99402d
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,12 @@ export function bearerTokenAuthenticationPolicy(
}

public async sendRequest(webResource: WebResourceLike): Promise<HttpOperationResponse> {
if (!webResource.url.toLowerCase().startsWith("https://")) {
throw new Error(
"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs."
);
}

const { token } = await getToken({
abortSignal: webResource.abortSignal,
tracingOptions: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,30 @@ describe("BearerTokenAuthenticationPolicy", function() {
assert.equal(expireDelayMs + 2 * getTokenDelay, Date.now() - startTime, exceptionMessage);
});

function createRequest(operationSpec?: OperationSpec): WebResource {
const request = new WebResource();
it("throws if the target URI doesn't start with 'https'", async () => {
const expiresOn = Date.now() + 1000 * 60; // One minute later.
const credential = new MockRefreshAzureCredential(expiresOn);
const request = createRequest(undefined, "http://azure.com");
const policy = createBearerTokenPolicy("test-scope", credential);

let error: Error | undefined;
try {
await policy.sendRequest(request);
} catch (e) {
error = e;
}

assert.equal(
error?.message,
"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs."
);
});

function createRequest(
operationSpec?: OperationSpec,
uri: string = "https://azure.com"
): WebResource {
const request = new WebResource(uri);
request.operationSpec = operationSpec;
return request;
}
Expand Down
28 changes: 14 additions & 14 deletions sdk/core/core-http/test/serviceClientTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ describe("ServiceClient", function() {

const testOperationSpec: OperationSpec = {
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
serializer: new Serializer(),
headerParameters: [
{
Expand Down Expand Up @@ -217,7 +217,7 @@ describe("ServiceClient", function() {
},
{
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
serializer: new Serializer(),
headerParameters: [
{
Expand Down Expand Up @@ -271,7 +271,7 @@ describe("ServiceClient", function() {
{},
{
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
serializer: new Serializer(),
headerParameters: [],
responses: {
Expand Down Expand Up @@ -385,7 +385,7 @@ describe("ServiceClient", function() {
});

it("should serialize collection with empty multi query parameter", async function() {
await testSendOperationRequest([], QueryCollectionFormat.Multi, true, "httpbin.org");
await testSendOperationRequest([], QueryCollectionFormat.Multi, true, "https://bin.org");
});

it("should apply withCredentials to requests", async function() {
Expand All @@ -406,7 +406,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: { 200: {} }
}
);
Expand All @@ -423,7 +423,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: { 200: {} }
}
);
Expand Down Expand Up @@ -454,7 +454,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: {
200: {
bodyMapper: {
Expand Down Expand Up @@ -494,7 +494,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: {}
}
);
Expand All @@ -521,7 +521,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: {}
}
);
Expand All @@ -547,7 +547,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: {}
}
);
Expand Down Expand Up @@ -576,7 +576,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: {}
}
);
Expand Down Expand Up @@ -607,7 +607,7 @@ describe("ServiceClient", function() {
{
serializer: new Serializer(),
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
responses: {}
}
);
Expand Down Expand Up @@ -1960,7 +1960,7 @@ describe("ServiceClient", function() {
bodyMapper: BodyMapper
}
},
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
serializer
};

Expand Down Expand Up @@ -2032,7 +2032,7 @@ async function testSendOperationRequest(
},
{
httpMethod: "GET",
baseUrl: "httpbin.org",
baseUrl: "https://bin.org",
serializer: new Serializer(),
queryParameters: [
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,12 @@ export function bearerTokenAuthenticationPolicy(
* - Retrieve a token with the challenge information, then re-send the request.
*/
async sendRequest(request: PipelineRequest, next: SendRequest): Promise<PipelineResponse> {
if (!request.url.toLowerCase().startsWith("https://")) {
throw new Error(
"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs."
);
}

await callbacks.authorizeRequest({
scopes: Array.isArray(scopes) ? scopes : [scopes],
request,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,28 @@ describe("BearerTokenAuthenticationPolicy", function() {
assert.equal(expireDelayMs + 2 * getTokenDelay, Date.now() - startTime, exceptionMessage);
});

it("throws if the target URI doesn't start with 'https'", async () => {
const expireDelayMs = defaultRefreshWindow + 5000;
const tokenExpiration = Date.now() + expireDelayMs;
const credential = new MockRefreshAzureCredential(tokenExpiration);

const request = createPipelineRequest({ url: "http://example.com" });
const policy = createBearerTokenPolicy("test-scope", credential);
const next = sinon.stub<Parameters<SendRequest>, ReturnType<SendRequest>>();

let error: Error | undefined;
try {
await policy.sendRequest(request, next);
} catch (e) {
error = e;
}

assert.equal(
error?.message,
"Bearer token authentication is not permitted for non-TLS protected (non-https) URLs."
);
});

function createBearerTokenPolicy(
scopes: string | string[],
credential: TokenCredential
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ describe("LogsQueryClient unit tests", () => {
};

const client = new LogsQueryClient(tokenCredential, {
endpoint: "customEndpoint1",
endpoint: "https://customEndpoint1",
scopes: "customScopes1"
});

assert.equal(client["_logAnalytics"].$host, "customEndpoint1");
assert.equal(client["_logAnalytics"]["baseUri"], "customEndpoint1");
assert.equal(client["_logAnalytics"].$host, "https://customEndpoint1");
assert.equal(client["_logAnalytics"]["baseUri"], "https://customEndpoint1");

try {
await client.queryLogs("workspaceId", "query", Durations.last5Minutes);
Expand Down

0 comments on commit f99402d

Please sign in to comment.