From 83a8057a6af93f2f553fd39315e79306f00ebacd Mon Sep 17 00:00:00 2001 From: Azure DevOps Pipeline Date: Fri, 22 May 2026 01:53:33 +0000 Subject: [PATCH 1/4] Update to RC1 --- changelog.txt | 3 +++ common/build.gradle | 2 +- common4j/versioning/version.properties | 2 +- versioning/version.properties | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/changelog.txt b/changelog.txt index c428e9633b..c173395780 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,8 @@ vNext ---------- + +Version 24.3.0-RC1 +---------- - [PATCH] Emit ipc_strategy telemetry attribute for successful device registration IPC strategy and refactor execute flow to pack protocol request once before strategy retries (#3124) - [PATCH] Fix Edge browser selection on devices where Microsoft Edge is the default browser: add the rotated Edge signing certificate hash to the Edge BrowserDescriptor and accept multi-signer browsers when any signature intersects the safelist, instead of requiring strict set-equality (resolves MSAL #2414) - [MINOR] Refactor Auth Tab integration to use provider-based strategy selection. Adds AuthTabStrategyProvider and BrowserLaunchStrategy with Custom Tabs fallback. Compatible with androidx.browser:browser:1.7.0. diff --git a/common/build.gradle b/common/build.gradle index 95ce168bac..f31fe904e6 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -87,7 +87,7 @@ tasks.register("jacocoTestReport", JacocoReport) { // In dev, we want to keep the dependencies(common4j, broker4j, common) to 1.0.+ to be able to be consumed by daily dev pipeline. // In release/*, we change these to specific versions being consumed. -def common4jVersion = "1.0.+" +def common4jVersion = "24.3.0-RC1" if (project.hasProperty("distCommon4jVersion") && project.distCommon4jVersion != '') { common4jVersion = project.distCommon4jVersion } diff --git a/common4j/versioning/version.properties b/common4j/versioning/version.properties index e8798f6c33..2e060cc6fc 100644 --- a/common4j/versioning/version.properties +++ b/common4j/versioning/version.properties @@ -1,4 +1,4 @@ #Wed May 12 20:08:39 UTC 2021 -versionName=24.2.0 +versionName=24.3.0-RC1 versionCode=1 latestPatchVersion=227 diff --git a/versioning/version.properties b/versioning/version.properties index 841aee0266..34c3c00b14 100644 --- a/versioning/version.properties +++ b/versioning/version.properties @@ -1,4 +1,4 @@ #Tue Apr 06 22:55:08 UTC 2021 -versionName=24.2.0 +versionName=24.3.0-RC1 versionCode=1 latestPatchVersion=234 From 0c035c548d1f691c875cfbfb2cb2a8ca29a7b247 Mon Sep 17 00:00:00 2001 From: Azure DevOps Pipeline Date: Fri, 22 May 2026 01:56:26 +0000 Subject: [PATCH 2/4] Update to RC2 --- changelog.txt | 2 +- common/build.gradle | 2 +- common4j/versioning/version.properties | 2 +- versioning/version.properties | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index c173395780..792f600763 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,7 @@ vNext ---------- -Version 24.3.0-RC1 +Version 24.3.0-RC2 ---------- - [PATCH] Emit ipc_strategy telemetry attribute for successful device registration IPC strategy and refactor execute flow to pack protocol request once before strategy retries (#3124) - [PATCH] Fix Edge browser selection on devices where Microsoft Edge is the default browser: add the rotated Edge signing certificate hash to the Edge BrowserDescriptor and accept multi-signer browsers when any signature intersects the safelist, instead of requiring strict set-equality (resolves MSAL #2414) diff --git a/common/build.gradle b/common/build.gradle index f31fe904e6..0312ce1a17 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -87,7 +87,7 @@ tasks.register("jacocoTestReport", JacocoReport) { // In dev, we want to keep the dependencies(common4j, broker4j, common) to 1.0.+ to be able to be consumed by daily dev pipeline. // In release/*, we change these to specific versions being consumed. -def common4jVersion = "24.3.0-RC1" +def common4jVersion = "24.3.0-RC2" if (project.hasProperty("distCommon4jVersion") && project.distCommon4jVersion != '') { common4jVersion = project.distCommon4jVersion } diff --git a/common4j/versioning/version.properties b/common4j/versioning/version.properties index 2e060cc6fc..69b1e75ddc 100644 --- a/common4j/versioning/version.properties +++ b/common4j/versioning/version.properties @@ -1,4 +1,4 @@ #Wed May 12 20:08:39 UTC 2021 -versionName=24.3.0-RC1 +versionName=24.3.0-RC2 versionCode=1 latestPatchVersion=227 diff --git a/versioning/version.properties b/versioning/version.properties index 34c3c00b14..863f9c830a 100644 --- a/versioning/version.properties +++ b/versioning/version.properties @@ -1,4 +1,4 @@ #Tue Apr 06 22:55:08 UTC 2021 -versionName=24.3.0-RC1 +versionName=24.3.0-RC2 versionCode=1 latestPatchVersion=234 From fff60fc90e5fa8ea1f96795f22aab1f9c531ca07 Mon Sep 17 00:00:00 2001 From: fadidurah <88730756+fadidurah@users.noreply.github.com> Date: Tue, 26 May 2026 17:11:45 -0400 Subject: [PATCH 3/4] Cherrypick token endpoint telemetry fix, Fixes AB#3604499 (#3129) Original PR: https://github.com/AzureAD/microsoft-authentication-library-common-for-android/pull/3128 [AB#3604499](https://identitydivision.visualstudio.com/fac9d424-53d2-45c0-91b5-ef6ba7a6bf26/_workitems/edit/3604499) --- changelog.txt | 1 + ...tractMicrosoftStsTokenResponseHandler.java | 28 ++++++++++--- .../common/java/telemetry/ClientDataInfo.java | 3 ++ .../MicrosoftStsTokenResponseHandlerTest.java | 42 +++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/changelog.txt b/changelog.txt index 792f600763..9540e386b9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ vNext Version 24.3.0-RC2 ---------- +- [PATCH] Fix Token Endpoint Server Telemetry Parsing (#3128) - [PATCH] Emit ipc_strategy telemetry attribute for successful device registration IPC strategy and refactor execute flow to pack protocol request once before strategy retries (#3124) - [PATCH] Fix Edge browser selection on devices where Microsoft Edge is the default browser: add the rotated Edge signing certificate hash to the Edge BrowserDescriptor and accept multi-signer browsers when any signature intersects the safelist, instead of requiring strict set-equality (resolves MSAL #2414) - [MINOR] Refactor Auth Tab integration to use provider-based strategy selection. Adds AuthTabStrategyProvider and BrowserLaunchStrategy with Custom Tabs fallback. Compatible with androidx.browser:browser:1.7.0. diff --git a/common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/AbstractMicrosoftStsTokenResponseHandler.java b/common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/AbstractMicrosoftStsTokenResponseHandler.java index 39249e9d48..cec878d7f9 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/AbstractMicrosoftStsTokenResponseHandler.java +++ b/common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/AbstractMicrosoftStsTokenResponseHandler.java @@ -31,6 +31,7 @@ import com.microsoft.identity.common.java.exception.ClientException; import com.microsoft.identity.common.java.flighting.CommonFlight; import com.microsoft.identity.common.java.flighting.CommonFlightsManager; +import com.microsoft.identity.common.java.logging.Logger; import com.microsoft.identity.common.java.net.HttpResponse; import com.microsoft.identity.common.java.opentelemetry.AttributeName; import com.microsoft.identity.common.java.opentelemetry.SpanExtension; @@ -43,6 +44,7 @@ import com.microsoft.identity.common.java.util.HeaderSerializationUtil; import com.microsoft.identity.common.java.util.ObjectMapper; import com.microsoft.identity.common.java.util.ResultUtil; +import com.microsoft.identity.common.java.util.StringUtil; import java.net.HttpURLConnection; import java.util.HashMap; @@ -109,11 +111,27 @@ public TokenResult handleTokenResponse(@NonNull final HttpResponse response) thr } final String clientDataHeader = response.getHeaderValue(X_MS_CLIENTDATA, 0); - if (CommonFlightsManager.INSTANCE.getFlightsProvider().isFlightEnabled(CommonFlight.ENABLE_SERVER_CLIENT_DATA_TELEMETRY)) { - final ClientDataInfo clientDataInfo = ClientDataInfo.fromPipeDelimited(clientDataHeader); - if (null != clientDataInfo) { - clientDataInfo.emitToSpan(); - result.setClientDataInfo(clientDataInfo); + if (CommonFlightsManager.INSTANCE.getFlightsProvider().isFlightEnabled(CommonFlight.ENABLE_SERVER_CLIENT_DATA_TELEMETRY) + && !StringUtil.isNullOrEmpty(clientDataHeader)) { + // eSTS URL-encodes the pipe-delimited value in the response header (e.g. "m%7C0x800482A5%7C%7C..."). + // ClientDataInfo.fromPipeDelimited expects an already-decoded value (its contract matches the + // authorize-endpoint path, where UrlUtil#getParameters has already decoded the query param). + // Decode here so the token-endpoint header path produces the same shape. + String decodedClientDataHeader = null; + try { + decodedClientDataHeader = StringUtil.urlFormDecode(clientDataHeader); + } catch (final Exception e) { + // Malformed percent-encoding shouldn't break token parsing; swallow and fall through. + Logger.warn(methodTag, "Failed to URL-decode x-ms-clientdata header: " + e.getMessage()); + // Emit that we failed to decode the clientdata value + SpanExtension.current().setAttribute(AttributeName.server_error.name(), "msal_android_decoding_failed"); + } + if (decodedClientDataHeader != null) { + final ClientDataInfo clientDataInfo = ClientDataInfo.fromPipeDelimited(decodedClientDataHeader); + if (null != clientDataInfo) { + clientDataInfo.emitToSpan(); + result.setClientDataInfo(clientDataInfo); + } } } diff --git a/common4j/src/main/com/microsoft/identity/common/java/telemetry/ClientDataInfo.java b/common4j/src/main/com/microsoft/identity/common/java/telemetry/ClientDataInfo.java index fd19094f8e..2368688f3b 100644 --- a/common4j/src/main/com/microsoft/identity/common/java/telemetry/ClientDataInfo.java +++ b/common4j/src/main/com/microsoft/identity/common/java/telemetry/ClientDataInfo.java @@ -130,6 +130,9 @@ public static ClientDataInfo fromPipeDelimited(@Nullable final String decodedVal return info; } catch (final Exception e) { Logger.warn(TAG, "Failed to parse clientdata pipe-delimited value: " + e.getMessage()); + // Emit that we failed to parse the clientdata value + final Span span = SpanExtension.current(); + span.setAttribute(AttributeName.server_error.name(), "msal_android_parsing_failed"); return null; } } diff --git a/common4j/src/test/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/MicrosoftStsTokenResponseHandlerTest.java b/common4j/src/test/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/MicrosoftStsTokenResponseHandlerTest.java index 0f440f0161..1ac7058eec 100644 --- a/common4j/src/test/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/MicrosoftStsTokenResponseHandlerTest.java +++ b/common4j/src/test/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/MicrosoftStsTokenResponseHandlerTest.java @@ -139,6 +139,48 @@ public void testHandleTokenResponse_withClientDataHeader_attributesEmitted() { } } + @SneakyThrows + @Test + public void testHandleTokenResponse_withUrlEncodedClientDataHeader_attributesEmitted() { + // eSTS URL-encodes pipe separators in the response header (e.g. "%7C" for "|"). + // Real-world example: x-ms-clientdata=[m%7C0x800482A5%7C%7Cmicrosoftonline.com%7Cnone] + final String encodedClientDataHeader = "m%7C0x800482A5%7C%7Cmicrosoftonline.com%7Cnone"; + final HashMap> headers = new HashMap<>(); + headers.put("Content-Type", Collections.singletonList("application/json; charset=utf-8")); + headers.put(HttpConstants.HeaderField.X_MS_CLIENTDATA, + Collections.singletonList(encodedClientDataHeader)); + final HttpResponse response = new HttpResponse(200, MOCK_TOKEN_SUCCESS_RESPONSE, headers); + final MicrosoftStsTokenResponseHandler handler = new MicrosoftStsTokenResponseHandler(); + final Span mockSpan = mock(Span.class); + when(mockSpan.setAttribute(Mockito.anyString(), Mockito.anyString())).thenReturn(mockSpan); + try (MockedStatic mockedExtension = Mockito.mockStatic(SpanExtension.class)) { + mockedExtension.when(SpanExtension::current).thenReturn(mockSpan); + final TokenResult tokenResult = handler.handleTokenResponse(response); + Assert.assertNotNull(tokenResult); + Assert.assertTrue(tokenResult.getSuccess()); + Assert.assertNotNull(tokenResult.getClientDataInfo()); + verify(mockSpan).setAttribute(AttributeName.server_error.name(), "0x800482A5"); + verify(mockSpan).setAttribute(AttributeName.account_type.name(), "MSA"); + } + } + @SneakyThrows + @Test + public void testHandleTokenResponse_withMalformedPercentEncoding_doesNotCrash() { + // Lone '%' is invalid percent-encoding; decode should fail gracefully and skip ClientDataInfo. + final String malformedHeader = "e|AADSTS50058|%ZZ|us|public"; + final HashMap> headers = new HashMap<>(); + headers.put("Content-Type", Collections.singletonList("application/json; charset=utf-8")); + headers.put(HttpConstants.HeaderField.X_MS_CLIENTDATA, + Collections.singletonList(malformedHeader)); + final HttpResponse response = new HttpResponse(200, MOCK_TOKEN_SUCCESS_RESPONSE, headers); + final MicrosoftStsTokenResponseHandler handler = new MicrosoftStsTokenResponseHandler(); + final TokenResult tokenResult = handler.handleTokenResponse(response); + Assert.assertNotNull(tokenResult); + Assert.assertTrue(tokenResult.getSuccess()); + // Malformed encoding => null ClientDataInfo, but token result still valid. + Assert.assertNull(tokenResult.getClientDataInfo()); + } + @SneakyThrows @Test public void testHandleTokenResponse_noClientDataHeader_doesNotCrash() { From e8011745121053f6f7337a243c83a294c486b31a Mon Sep 17 00:00:00 2001 From: Azure DevOps Pipeline Date: Tue, 26 May 2026 23:23:43 +0000 Subject: [PATCH 4/4] remove RC --- changelog.txt | 2 +- common/build.gradle | 2 +- common4j/versioning/version.properties | 2 +- versioning/version.properties | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/changelog.txt b/changelog.txt index 9540e386b9..a6c4666798 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,7 +1,7 @@ vNext ---------- -Version 24.3.0-RC2 +Version 24.3.0 ---------- - [PATCH] Fix Token Endpoint Server Telemetry Parsing (#3128) - [PATCH] Emit ipc_strategy telemetry attribute for successful device registration IPC strategy and refactor execute flow to pack protocol request once before strategy retries (#3124) diff --git a/common/build.gradle b/common/build.gradle index 0312ce1a17..66729d05cc 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -87,7 +87,7 @@ tasks.register("jacocoTestReport", JacocoReport) { // In dev, we want to keep the dependencies(common4j, broker4j, common) to 1.0.+ to be able to be consumed by daily dev pipeline. // In release/*, we change these to specific versions being consumed. -def common4jVersion = "24.3.0-RC2" +def common4jVersion = "24.3.0" if (project.hasProperty("distCommon4jVersion") && project.distCommon4jVersion != '') { common4jVersion = project.distCommon4jVersion } diff --git a/common4j/versioning/version.properties b/common4j/versioning/version.properties index 69b1e75ddc..cb4418b722 100644 --- a/common4j/versioning/version.properties +++ b/common4j/versioning/version.properties @@ -1,4 +1,4 @@ #Wed May 12 20:08:39 UTC 2021 -versionName=24.3.0-RC2 +versionName=24.3.0 versionCode=1 latestPatchVersion=227 diff --git a/versioning/version.properties b/versioning/version.properties index 863f9c830a..aa3517696d 100644 --- a/versioning/version.properties +++ b/versioning/version.properties @@ -1,4 +1,4 @@ #Tue Apr 06 22:55:08 UTC 2021 -versionName=24.3.0-RC2 +versionName=24.3.0 versionCode=1 latestPatchVersion=234