Skip to content

Commit 781fa52

Browse files
committed
Addressed feedback, modified config
1 parent b4d41fd commit 781fa52

5 files changed

Lines changed: 89 additions & 48 deletions

File tree

shared/AppInsightsCore/Tests/Unit/src/ai/AppInsightsCommon.tests.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { Assert, AITestClass } from "@microsoft/ai-test-framework";
33
import { DiagnosticLogger } from "../../../../src/diagnostics/DiagnosticLogger";
44
import { IConfiguration } from "../../../../src/interfaces/ai/IConfiguration";
55
import { dataSanitizeInput, dataSanitizeKey, dataSanitizeMessage, DataSanitizerValues, dataSanitizeString, dataSanitizeUrl } from "../../../../src/telemetry/ai/Common/DataSanitizer";
6-
6+
import { UrlRedactionOptions } from "../../../../src/enums/ai/UrlRedactionOptions"
77

88
export class ApplicationInsightsTests extends AITestClass {
99
logger = new DiagnosticLogger();
@@ -395,7 +395,8 @@ export class ApplicationInsightsTests extends AITestClass {
395395
test: () => {
396396
// URLs with sensitive query parameters
397397
let config = {
398-
appendRedactQueryParams: ["authorize", "api_key", "password"]
398+
redactUrls: UrlRedactionOptions.append,
399+
redactQueryParams: ["authorize", "api_key", "password"]
399400
} as IConfiguration;
400401
const urlWithSensitiveParams = "https://example.com/api?Signature=secret&authorize=value";
401402
const expectedRedactedUrl = "https://example.com/api?Signature=REDACTED&authorize=REDACTED";
@@ -407,11 +408,12 @@ export class ApplicationInsightsTests extends AITestClass {
407408
});
408409

409410
this.testCase({
410-
name: 'DataSanitizerTests: dataSanitizeUrl properly redacts sensitive query parameters ( only custom)',
411+
name: 'DataSanitizerTests: dataSanitizeUrl properly redacts sensitive query parameters (only custom)',
411412
test: () => {
412413
// URLs with sensitive query parameters
413414
let config = {
414-
replaceRedactQueryParams: ["authorize", "api_key", "password"]
415+
redactUrls: UrlRedactionOptions.replace,
416+
redactQueryParams: ["authorize", "api_key", "password"]
415417
} as IConfiguration;
416418
const urlWithSensitiveParams = "https://example.com/api?Signature=secret&authorize=value";
417419
const expectedRedactedUrl = "https://example.com/api?Signature=secret&authorize=REDACTED";

shared/AppInsightsCore/Tests/Unit/src/ai/ApplicationInsightsCore.Tests.ts

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { _InternalLogMessage, DiagnosticLogger } from "../../../../src/diagnosti
1111
import { ActiveStatus } from "../../../../src/enums/ai/InitActiveStatusEnum";
1212
import { createAsyncPromise, createAsyncRejectedPromise, createAsyncResolvedPromise, createTimeoutPromise, doAwaitResponse } from "@nevware21/ts-async";
1313
import { setBypassLazyCache } from "@nevware21/ts-utils";
14+
import { UrlRedactionOptions } from "../../../../src/enums/ai/UrlRedactionOptions"
1415

1516
const AIInternalMessagePrefix = "AITR_";
1617
const MaxInt32 = 0xFFFFFFFF;
@@ -2073,7 +2074,6 @@ export class ApplicationInsightsCoreTests extends AITestClass {
20732074
test: () => {
20742075
let config = {
20752076
redactUrls: false,
2076-
redactQueryParams: false,
20772077
} as IConfiguration;
20782078
const url = "https://username:password@example.com:8443/path/to/resource?sig=secret&color=blue#section2";
20792079
const redactedLocation = fieldRedaction(url, config);
@@ -2215,7 +2215,8 @@ export class ApplicationInsightsCoreTests extends AITestClass {
22152215
name: "FieldRedaction: should redact custom query parameters defined in redactQueryParams and replace custom queryParams",
22162216
test: () => {
22172217
let config = {
2218-
replaceRedactQueryParams: ["authorize", "api_key", "password"]
2218+
redactUrls: UrlRedactionOptions.replace,
2219+
redactQueryParams: ["authorize", "api_key", "password"]
22192220
} as IConfiguration;
22202221

22212222
const url = "https://example.com/path?auth_token=12345&name=test&authorize=secret";
@@ -2228,7 +2229,8 @@ export class ApplicationInsightsCoreTests extends AITestClass {
22282229
name: "FieldRedaction: should redact both default and custom query parameters",
22292230
test: () => {
22302231
let config = {
2231-
appendRedactQueryParams: ["auth_token"]
2232+
redactUrls: UrlRedactionOptions.append,
2233+
redactQueryParams: ["auth_token"]
22322234
} as IConfiguration;
22332235

22342236
const url = "https://example.com/path?sig=abc123&auth_token=12345&name=test";
@@ -2238,16 +2240,16 @@ export class ApplicationInsightsCoreTests extends AITestClass {
22382240
}
22392241
});
22402242
this.testCase({
2241-
name: "FieldRedaction:should redact custom parameters when redactUrls is disabled but redactQueryParams is not false",
2243+
name: "FieldRedaction:should replace custom parameters redactQueryParams when user specifies the replace config",
22422244
test: () => {
22432245
let config = {
2244-
redactUrls: false,
2245-
replaceRedactQueryParams: ["authorize", "api_key"]
2246+
redactUrls: UrlRedactionOptions.replace,
2247+
redactQueryParams: ["authorize", "api_key"]
22462248
} as IConfiguration;
22472249

22482250
const url = "https://username:password@example.com/path?auth_token=12345&authorize=secret";
22492251
const redactedLocation = fieldRedaction(url, config);
2250-
Assert.equal(redactedLocation, "https://username:password@example.com/path?auth_token=12345&authorize=REDACTED",
2252+
Assert.equal(redactedLocation, "https://REDACTED:REDACTED@example.com/path?auth_token=12345&authorize=REDACTED",
22512253
"URL with custom sensitive parameters should be redacted when query redaction is not disabled");
22522254
}
22532255
});
@@ -2269,7 +2271,8 @@ export class ApplicationInsightsCoreTests extends AITestClass {
22692271
name: "FieldRedaction:should handle complex URLs with both credentials and custom query parameters",
22702272
test: () => {
22712273
let config = {
2272-
appendRedactQueryParams: ["authorize", "session_id"]
2274+
redactUrls: UrlRedactionOptions.append,
2275+
redactQueryParams: ["authorize", "session_id"]
22732276
} as IConfiguration;
22742277

22752278
const url = "https://user:pass@example.com/path?sig=secret&authorize=abc123&visible=true&session_id=xyz789";
@@ -2601,7 +2604,7 @@ export class ApplicationInsightsCoreTests extends AITestClass {
26012604
name: "FieldRedaction: should redact credentials while preserving query strings when redactQueryParams is false",
26022605
test: () => {
26032606
let config = {
2604-
redactQueryParams: false
2607+
redactUrls: 5
26052608
} as IConfiguration;
26062609
const url = "https://user:password@example.com/path?sig=secret&color=blue&token=abc123";
26072610
const redactedLocation = fieldRedaction(url, config);
@@ -2614,7 +2617,8 @@ export class ApplicationInsightsCoreTests extends AITestClass {
26142617
name: "FieldRedaction: should handle custom parameters with multiple occurrences and empty values",
26152618
test: () => {
26162619
let config = {
2617-
replaceRedactQueryParams: ["auth_token", "session_id"]
2620+
redactUrls: UrlRedactionOptions.replace,
2621+
redactQueryParams: ["auth_token", "session_id"]
26182622
} as IConfiguration;
26192623
const url = "https://example.com/path?auth_token=first&name=test&auth_token=&session_id=abc&session_id=";
26202624
const redactedLocation = fieldRedaction(url, config);
@@ -2638,24 +2642,23 @@ export class ApplicationInsightsCoreTests extends AITestClass {
26382642
});
26392643

26402644
this.testCase({
2641-
name: "FieldRedaction: should preserve credentials while redacting query strings when redactUrls is false",
2645+
name: "FieldRedaction: should redact all parts of the URL (username, password, default query params) when redactUrls is set to True",
26422646
test: () => {
26432647
let config = {
2644-
redactUrls: false
2648+
redactUrls: true
26452649
} as IConfiguration;
26462650
const url = "https://user:password@example.com/path?sig=secret&color=blue&token=abc123";
26472651
const redactedLocation = fieldRedaction(url, config);
2648-
Assert.equal(redactedLocation, "https://user:password@example.com/path?sig=REDACTED&color=blue&token=abc123",
2649-
"Query string values should be redacted while credentials remain unchanged when redactUrls is false");
2652+
Assert.equal(redactedLocation, "https://REDACTED:REDACTED@example.com/path?sig=REDACTED&color=blue&token=abc123",
2653+
"All parts of the URL should be redacted when redactUrls is true");
26502654
}
26512655
});
26522656

26532657
this.testCase({
26542658
name: "FieldRedaction: should not redact credentials or query strings when redactUrls and redactQueryParams are false",
26552659
test: () => {
26562660
let config = {
2657-
redactUrls: false,
2658-
redactQueryParams: false
2661+
redactUrls: UrlRedactionOptions.false
26592662
} as IConfiguration;
26602663
const url = "https://user:password@example.com/path?sig=secret&color=blue&token=abc123";
26612664
const redactedLocation = fieldRedaction(url, config);
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
/**
5+
* Controls how the user can configure which parts of the URL should be redacted. Example, certain query parameters, username and password, etc.
6+
* @since <next_release_version>
7+
*/
8+
export const enum UrlRedactionOptions {
9+
/**
10+
* The default value, will redact the username and password as well as the default set of query parameters
11+
*/
12+
true = 1,
13+
14+
/**
15+
* Does not redact username and password or any query parameters, the URL will be left as is. Note: this is not recommended as it may lead
16+
* to sensitive data being sent in clear text.
17+
*/
18+
false = 2,
19+
20+
/**
21+
* This will append any additional queryParams that the user has provided through redactQueryParams config to the default set i.e to
22+
* @defaultValue ["sig", "Signature", "AWSAccessKeyId", "X-Goog-Signature"].
23+
*/
24+
append = 3,
25+
26+
/**
27+
* This will replace the default set of query parameters to redact with the query parameters defined in redactQueryParams config, if provided by the user.
28+
*/
29+
replace = 4,
30+
31+
/**
32+
* This will redact username and password in the URL but will not redact any query parameters, even those in the default set.
33+
*/
34+
usernamePasswordOnly = 5,
35+
36+
/**
37+
* This will only redact the query parameter in the default set of query parameters to redact. It will not redact username and password.
38+
*/
39+
queryParamsOnly = 6,
40+
41+
}

shared/AppInsightsCore/src/interfaces/ai/IConfiguration.ts

Lines changed: 3 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT License.
33
import { IPromise } from "@nevware21/ts-async";
44
import { eTraceHeadersMode } from "../../enums/ai/TraceHeadersMode";
5+
import { UrlRedactionOptions } from "../../enums/ai/UrlRedactionOptions";
56
import { IOTelConfig } from "../otel/config/IOTelConfig";
67
import { IAppInsightsCore } from "./IAppInsightsCore";
78
import { IChannelControls } from "./IChannelControls";
@@ -231,17 +232,11 @@ export interface IConfiguration extends IOTelConfig {
231232
*/
232233
expCfg?: IExceptionConfig;
233234

234-
/**
235-
* [Optional] A flag to enable or disable redaction for username and password in URLs.
236-
* @defaultValue true
237-
*/
238-
redactUrls?: boolean;
239-
240235
/**
241236
* [Optional] A flag to enable or disable redaction for query parameters.
242237
* @defaultValue true
243238
*/
244-
redactQueryParams?: boolean;
239+
redactUrls?: boolean | UrlRedactionOptions;
245240

246241
/**
247242
* [Optional] Additional query parameters to redact beyond the default set.
@@ -250,16 +245,7 @@ export interface IConfiguration extends IOTelConfig {
250245
* @defaultValue ["sig", "Signature", "AWSAccessKeyId", "X-Goog-Signature"]
251246
* @example ["sig", "Signature", "AWSAccessKeyId", "X-Goog-Signature","auth_token", "api_key", "private_data"]
252247
*/
253-
appendRedactQueryParams?: string[];
254-
255-
/**
256-
* [Optional] Replaces the default set with a custom set of query parameters to redact.
257-
* Use this to specify custom parameters that contain sensitive information.
258-
* These will replace the default parameters that are redacted.
259-
* @defaultValue ["sig", "Signature", "AWSAccessKeyId", "X-Goog-Signature"]
260-
* @example ["auth_token", "api_key", "private_data"]
261-
*/
262-
replaceRedactQueryParams?: string[];
248+
redactQueryParams?: string[];
263249

264250
///**
265251
// * [Optional] Internal SDK configuration for developers

shared/AppInsightsCore/src/utils/EnvUtils.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
isFunction, isNullOrUndefined, isString, isUndefined, mathMax, strIndexOf, strSubstring
99
} from "@nevware21/ts-utils";
1010
import { DEFAULT_SENSITIVE_PARAMS, STR_EMPTY, STR_REDACTED } from "../constants/InternalConstants";
11+
import { UrlRedactionOptions } from "../enums/ai/UrlRedactionOptions";
1112
import { IConfiguration } from "../interfaces/ai/IConfiguration";
1213
import { strContains } from "./HelperFuncs";
1314

@@ -455,10 +456,10 @@ function redactQueryParameters(url: string, config?: IConfiguration): string {
455456
return url;
456457
}
457458

458-
if (config && config.appendRedactQueryParams) {
459-
sensitiveParams = DEFAULT_SENSITIVE_PARAMS.concat(config.appendRedactQueryParams);
460-
} else if (config && config.replaceRedactQueryParams) {
461-
sensitiveParams = config.replaceRedactQueryParams;
459+
if (config && config.redactUrls === UrlRedactionOptions.append) {
460+
sensitiveParams = DEFAULT_SENSITIVE_PARAMS.concat(config.redactQueryParams);
461+
} else if (config && config.redactUrls === UrlRedactionOptions.replace) {
462+
sensitiveParams = config.redactQueryParams;
462463
} else {
463464
sensitiveParams = DEFAULT_SENSITIVE_PARAMS;
464465
}
@@ -545,25 +546,33 @@ export function fieldRedaction(input: string, config: IConfiguration): string {
545546
if (!input || !isString(input) || strIndexOf(input, " ") !== -1) {
546547
return input;
547548
}
548-
const isRedactionDisabled = config && config.redactUrls === false;
549-
const isQueryParamRedactionDisabled = config && config.redactQueryParams === false;
550-
if (isRedactionDisabled && isQueryParamRedactionDisabled) {
549+
const isRedactionDisabled = config && (config.redactUrls === false || config.redactUrls === UrlRedactionOptions.false);
550+
if (isRedactionDisabled) {
551551
return input;
552552
}
553553

554-
const hasCredentials = strIndexOf(input, "@") !== -1;
555-
const hasQueryParams = strIndexOf(input, "?") !== -1;
554+
let hasCredentials = strIndexOf(input, "@") !== -1;
555+
let hasQueryParams = strIndexOf(input, "?") !== -1;
556556

557557
// If no credentials and no query params, return original
558558
if (!hasCredentials && !hasQueryParams) {
559559
return input;
560560
}
561+
562+
if (config.redactUrls === UrlRedactionOptions.usernamePasswordOnly) {
563+
hasQueryParams = false;
564+
}
565+
566+
if (config.redactUrls === UrlRedactionOptions.queryParamsOnly) {
567+
hasCredentials = false;
568+
}
569+
561570
try {
562571
let result = input;
563-
if (hasCredentials && !isRedactionDisabled) {
572+
if (hasCredentials) {
564573
result = redactUserInfo(input);
565574
}
566-
if (hasQueryParams && !isQueryParamRedactionDisabled) {
575+
if (hasQueryParams) {
567576
result = redactQueryParameters(result, config);
568577
}
569578
return result;

0 commit comments

Comments
 (0)