Skip to content

Commit

Permalink
Add support for aadAudience configuration using Connection String (#1220
Browse files Browse the repository at this point in the history
)
  • Loading branch information
hectorhdzg committed Oct 4, 2023
1 parent c17860c commit 3825c85
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 7 deletions.
4 changes: 3 additions & 1 deletion Declarations/Contracts/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ export interface ConnectionString {
liveendpoint?: string;
location?: string;
endpointsuffix?: string;
aadaudience?: string;
authorization?: string;

// Note: this is a node types backcompat equivalent to
// type ConnectionString = { [key in ConnectionStringKey]?: string }
}

export type ConnectionStringKey = "instrumentationkey" | "ingestionendpoint" | "liveendpoint" | "location"| "endpointsuffix";
export type ConnectionStringKey = "instrumentationkey" | "ingestionendpoint" | "liveendpoint" | "location"| "endpointsuffix" | "aadaudience" | "authorization";
4 changes: 2 additions & 2 deletions Library/AuthorizationHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class AuthorizationHandler {

private _azureTokenPolicy: azureCore.PipelinePolicy;

constructor(credential: azureCoreAuth.TokenCredential) {
let scopes: string[] = [applicationInsightsResource];
constructor(credential: azureCoreAuth.TokenCredential, aadAudience?: string) {
let scopes: string[] = aadAudience ? [aadAudience] : [applicationInsightsResource];
this._azureTokenPolicy = azureCore.bearerTokenAuthenticationPolicy({ credential, scopes });
}

Expand Down
4 changes: 3 additions & 1 deletion Library/Config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class Config implements IConfig {
public httpsAgent: https.Agent;
public ignoreLegacyHeaders: boolean;
public aadTokenCredential?: azureCoreAuth.TokenCredential;
public aadAudience?: string;
public enableAutoCollectConsole: boolean;
public enableLoggerErrorToTrace: boolean;
public enableAutoCollectExceptions: boolean;
Expand Down Expand Up @@ -70,7 +71,7 @@ class Config implements IConfig {
private _profileQueryEndpoint: string;
private _instrumentationKey: string;
public _webInstrumentationConnectionString: string;

constructor(setupString?: string) {
// Load config values from env variables and JSON if available
this._mergeConfig();
Expand Down Expand Up @@ -117,6 +118,7 @@ class Config implements IConfig {
if (this.quickPulseHost.match(/^https?:\/\//)) {
this.quickPulseHost = new url.URL(this.quickPulseHost).host;
}
this.aadAudience = csCode.aadaudience || csEnv.aadaudience;
}

public set profileQueryEndpoint(endpoint: string) {
Expand Down
2 changes: 1 addition & 1 deletion Library/TelemetryClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ class TelemetryClient {
if (config && config.aadTokenCredential) {
if (!this.authorizationHandler) {
Logging.info(TelemetryClient.TAG, "Adding authorization handler");
this.authorizationHandler = new AuthorizationHandler(config.aadTokenCredential)
this.authorizationHandler = new AuthorizationHandler(config.aadTokenCredential, config.aadAudience);
}
return this.authorizationHandler;
}
Expand Down
24 changes: 23 additions & 1 deletion Tests/Library/AuthorizationHandler.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ class TestTokenCredential implements azureCoreAuth.TokenCredential {
private _expiresOn: Date;
private _numberOfRefreshs = 0;

public scopes: string | string[];

constructor(expiresOn?: Date) {
this._expiresOn = expiresOn || new Date();
}

async getToken(scopes: string | string[], options?: any): Promise<any> {
this.scopes = scopes;
this._numberOfRefreshs++;
return {
token: "testToken" + this._numberOfRefreshs,
Expand All @@ -40,7 +43,8 @@ describe("Library/AuthorizationHandler", () => {
describe("#addAuthorizationHeader()", () => {
it("should add Authorization header to options", async () => {
var config = new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
config.aadTokenCredential = new TestTokenCredential();
const testCredential = new TestTokenCredential();
config.aadTokenCredential = testCredential;
var handler = new AuthorizationHandler(config.aadTokenCredential);
var options = {
method: "POST",
Expand All @@ -50,6 +54,8 @@ describe("Library/AuthorizationHandler", () => {
};
await handler.addAuthorizationHeader(options);
assert.equal(options.headers["authorization"], "Bearer testToken1");
// Default scope
assert.deepEqual(testCredential.scopes, ["https://monitor.azure.com//.default"]);
});

it("should refresh token if expired", async () => {
Expand All @@ -70,5 +76,21 @@ describe("Library/AuthorizationHandler", () => {
assert.equal(tokenCredential["_numberOfRefreshs"], 2);
assert.equal(options.headers["authorization"], "Bearer testToken2");
});

it("should allow configuration of credentialScopes", async () => {
var config = new Config("1aa11111-bbbb-1ccc-8ddd-eeeeffff3333");
const testCredential = new TestTokenCredential();
config.aadTokenCredential = testCredential;
config.aadAudience = "testAudience";
var handler = new AuthorizationHandler(config.aadTokenCredential, config.aadAudience);
var options = {
method: "POST",
headers: <{ [key: string]: string }>{
"Content-Type": "application/x-json-stream"
}
};
await handler.addAuthorizationHeader(options);
assert.deepEqual(testCredential.scopes, ["testAudience"]);
});
});
});
4 changes: 3 additions & 1 deletion Tests/Library/ConnectionStringParser.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ describe("ConnectionStringParser", () => {
const instrumentationKey = "1aa11111-bbbb-1ccc-8ddd-eeeeffff3333";
const ingestionEndpoint = "ingest";
const liveEndpoint = "live";
var connectionString = `InstrumentationKey=${instrumentationKey};IngestionEndpoint=${ingestionEndpoint};LiveEndpoint=${liveEndpoint};`;
const aadAudience = "live";
var connectionString = `InstrumentationKey=${instrumentationKey};IngestionEndpoint=${ingestionEndpoint};LiveEndpoint=${liveEndpoint};AadAudience=${aadAudience};`;
const result = ConnectionStringParser.parse(connectionString);
assert.deepEqual(result.instrumentationkey, instrumentationKey);
assert.deepEqual(result.ingestionendpoint, ingestionEndpoint);
assert.deepEqual(result.liveendpoint, liveEndpoint);
assert.deepEqual(result.aadaudience, aadAudience);
});

it("should ignore invalid fields", () => {
Expand Down

0 comments on commit 3825c85

Please sign in to comment.