Skip to content

Commit dc89211

Browse files
fadidurahCopilot
andcommitted
Wire ClientDataInfo through AcquireTokenResult
Propagate the parsed x-ms-clientdata (token endpoint) and clientdata query parameter (authorize endpoint) data from the response handlers through TokenResult, MicrosoftStsAuthorizationResult, and ultimately onto AcquireTokenResult so callers can access server-side telemetry (error, sub-error, account type, cloud instance, data boundary). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent dabefab commit dc89211

12 files changed

Lines changed: 210 additions & 7 deletions

File tree

common/src/main/java/com/microsoft/identity/common/internal/broker/BrokerResult.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ private static class SerializedNames {
9797
static final String SPE_RING = "spe_ring";
9898
static final String CLI_TELEM_ERRORCODE = "cli_telem_error_code";
9999
static final String CLI_TELEM_SUB_ERROR_CODE = "cli_telem_suberror_code";
100+
static final String CLIENT_DATA_INFO = "client_data_info";
100101
}
101102

102103
private static final long serialVersionUID = 8606631820514878489L;
@@ -236,6 +237,13 @@ private static class SerializedNames {
236237
@SerializedName(SerializedNames.REFRESH_TOKEN_AGE)
237238
private String mRefreshTokenAge;
238239

240+
/**
241+
* Server client data info from x-ms-clientdata response header (pipe-delimited format).
242+
*/
243+
@Nullable
244+
@SerializedName(SerializedNames.CLIENT_DATA_INFO)
245+
private String mClientDataInfoRaw;
246+
239247
/**
240248
* Boolean to indicate if the request succeeded without exceptions.
241249
*/
@@ -347,6 +355,7 @@ private BrokerResult(@NonNull final Builder builder) {
347355
mCachedAt = builder.mCachedAt;
348356
mSpeRing = builder.mSpeRing;
349357
mRefreshTokenAge = builder.mRefreshTokenAge;
358+
mClientDataInfoRaw = builder.mClientDataInfoRaw;
350359
mSuccess = builder.mSuccess;
351360
mTenantProfileData = builder.mTenantProfileData;
352361
mServicedFromCache = builder.mServicedFromCache;
@@ -426,6 +435,11 @@ public String getSpeRing() {
426435
return mSpeRing;
427436
}
428437

438+
@Nullable
439+
public String getClientDataInfoRaw() {
440+
return mClientDataInfoRaw;
441+
}
442+
429443
public long getCachedAt() {
430444
return mCachedAt;
431445
}
@@ -518,6 +532,7 @@ public static class Builder {
518532
private long mCachedAt;
519533
private String mSpeRing;
520534
private String mRefreshTokenAge;
535+
private String mClientDataInfoRaw;
521536
private boolean mSuccess;
522537
private String mNegotiatedBrokerProtocolVersion;
523538
private List<ICacheRecord> mTenantProfileData;
@@ -631,6 +646,11 @@ public Builder refreshTokenAge(final String refreshTokenAge) {
631646
return this;
632647
}
633648

649+
public Builder clientDataInfoRaw(@Nullable final String clientDataInfoRaw) {
650+
this.mClientDataInfoRaw = clientDataInfoRaw;
651+
return this;
652+
}
653+
634654
public Builder success(boolean success) {
635655
this.mSuccess = success;
636656
return this;

common/src/main/java/com/microsoft/identity/common/internal/controllers/LocalMSALController.java

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import com.microsoft.identity.common.java.providers.RawAuthorizationResult;
6363
import com.microsoft.identity.common.java.providers.microsoft.microsoftsts.MicrosoftStsAuthorizationRequest;
6464
import com.microsoft.identity.common.java.providers.microsoft.microsoftsts.MicrosoftStsAuthorizationResponse;
65+
import com.microsoft.identity.common.java.providers.microsoft.microsoftsts.MicrosoftStsAuthorizationResult;
6566
import com.microsoft.identity.common.java.providers.microsoft.microsoftsts.MicrosoftStsTokenRequest;
6667
import com.microsoft.identity.common.java.providers.oauth2.AuthorizationRequest;
6768
import com.microsoft.identity.common.java.providers.oauth2.AuthorizationResult;
@@ -168,6 +169,13 @@ public AcquireTokenResult acquireToken(
168169
);
169170
acquireTokenResult.setAuthorizationResult(result);
170171

172+
// Wire ClientDataInfo from the authorization result (authorize endpoint).
173+
if (result instanceof MicrosoftStsAuthorizationResult) {
174+
acquireTokenResult.setClientDataInfo(
175+
((MicrosoftStsAuthorizationResult) result).getClientDataInfo()
176+
);
177+
}
178+
171179
ResultUtil.logResult(TAG, result);
172180

173181
if (result.getAuthorizationStatus().equals(AuthorizationStatus.SUCCESS)) {
@@ -181,6 +189,11 @@ public AcquireTokenResult acquireToken(
181189

182190
acquireTokenResult.setTokenResult(tokenResult);
183191

192+
// Prefer ClientDataInfo from the token endpoint (later, more authoritative call).
193+
if (tokenResult != null && tokenResult.getClientDataInfo() != null) {
194+
acquireTokenResult.setClientDataInfo(tokenResult.getClientDataInfo());
195+
}
196+
184197
if (tokenResult != null && tokenResult.getSuccess()) {
185198
//4) Save tokens in token cache
186199
final List<ICacheRecord> records = saveTokens(
@@ -205,6 +218,11 @@ public AcquireTokenResult acquireToken(
205218
false
206219
)
207220
);
221+
222+
// Set ClientDataInfo on the LocalAuthenticationResult for IPC propagation
223+
final LocalAuthenticationResult localResult =
224+
(LocalAuthenticationResult) acquireTokenResult.getLocalAuthenticationResult();
225+
localResult.setClientDataInfo(acquireTokenResult.getClientDataInfo());
208226
}
209227
}
210228

@@ -742,6 +760,9 @@ public AcquireTokenResult acquireDeviceCodeFlowToken(
742760

743761
// Assign token result
744762
acquireTokenResult.setTokenResult(tokenResult);
763+
if (tokenResult != null) {
764+
acquireTokenResult.setClientDataInfo(tokenResult.getClientDataInfo());
765+
}
745766

746767
// If the token is valid, save it into token cache
747768
final List<ICacheRecord> records = saveTokens(
@@ -764,6 +785,13 @@ public AcquireTokenResult acquireDeviceCodeFlowToken(
764785
false
765786
)
766787
);
788+
789+
// Set ClientDataInfo on the LocalAuthenticationResult for IPC propagation
790+
if (tokenResult != null) {
791+
final LocalAuthenticationResult localResult =
792+
(LocalAuthenticationResult) acquireTokenResult.getLocalAuthenticationResult();
793+
localResult.setClientDataInfo(tokenResult.getClientDataInfo());
794+
}
767795
} catch (Exception error) {
768796
Telemetry.emit(
769797
new ApiEndEvent()

common/src/main/java/com/microsoft/identity/common/internal/result/MsalBrokerResultAdapter.java

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
import com.microsoft.identity.common.java.result.GenerateShrResult;
9999
import com.microsoft.identity.common.java.result.ILocalAuthenticationResult;
100100
import com.microsoft.identity.common.java.result.LocalAuthenticationResult;
101+
import com.microsoft.identity.common.java.telemetry.ClientDataInfo;
101102
import com.microsoft.identity.common.java.ui.PreferredAuthMethod;
102103
import com.microsoft.identity.common.java.util.BrokerProtocolVersionUtil;
103104
import com.microsoft.identity.common.java.util.HeaderSerializationUtil;
@@ -284,6 +285,17 @@ public Bundle bundleFromAuthenticationResultForWebApps(@NonNull final ILocalAuth
284285
.success(true)
285286
.servicedFromCache(authenticationResult.isServicedFromCache());
286287

288+
// Serialize ClientDataInfo as raw pipe-delimited string for IPC transfer.
289+
// The raw field is populated by ClientDataInfo.fromPipeDelimited(), the only
290+
// path that populates the parsed fields, so it is safe to ship as-is.
291+
if (authenticationResult instanceof LocalAuthenticationResult) {
292+
final ClientDataInfo clientDataInfo =
293+
((LocalAuthenticationResult) authenticationResult).getClientDataInfo();
294+
if (clientDataInfo != null) {
295+
brokerResultBuilder.clientDataInfoRaw(clientDataInfo.getRaw());
296+
}
297+
}
298+
287299
if (shouldRemoveRefreshTokenFromResult(authenticationResult, negotiatedBrokerProtocolVersion)){
288300
brokerResultBuilder.tenantProfileRecords(
289301
removeRefreshTokenFromCacheRecords(
@@ -476,12 +488,21 @@ public ILocalAuthenticationResult authenticationResultFromBundle(@NonNull final
476488
throw new ClientException(INVALID_BROKER_BUNDLE, "getTenantProfileData is null.");
477489
}
478490

479-
return new LocalAuthenticationResult(
491+
final LocalAuthenticationResult localAuthResult = new LocalAuthenticationResult(
480492
tenantProfileCacheRecords.get(0),
481493
tenantProfileCacheRecords,
482494
SdkType.MSAL,
483495
brokerResult.isServicedFromCache()
484496
);
497+
498+
// Deserialize ClientDataInfo from the broker result if available
499+
final ClientDataInfo clientDataInfo =
500+
ClientDataInfo.fromPipeDelimited(brokerResult.getClientDataInfoRaw());
501+
if (clientDataInfo != null) {
502+
localAuthResult.setClientDataInfo(clientDataInfo);
503+
}
504+
505+
return localAuthResult;
485506
}
486507

487508
@NonNull
@@ -994,7 +1015,16 @@ public AcquireTokenResult getDeviceCodeFlowTokenResultFromResultBundle(@NonNull
9941015

9951016
if (resultBundle.getBoolean(AuthenticationConstants.Broker.BROKER_REQUEST_V2_SUCCESS)) {
9961017
final AcquireTokenResult acquireTokenResult = new AcquireTokenResult();
997-
acquireTokenResult.setLocalAuthenticationResult(authenticationResultFromBundle(resultBundle));
1018+
final ILocalAuthenticationResult authResult = authenticationResultFromBundle(resultBundle);
1019+
acquireTokenResult.setLocalAuthenticationResult(authResult);
1020+
1021+
// Propagate ClientDataInfo from LocalAuthenticationResult to AcquireTokenResult
1022+
if (authResult instanceof LocalAuthenticationResult) {
1023+
acquireTokenResult.setClientDataInfo(
1024+
((LocalAuthenticationResult) authResult).getClientDataInfo()
1025+
);
1026+
}
1027+
9981028
span.setStatus(StatusCode.OK);
9991029
return acquireTokenResult;
10001030
} else if (brokerResult.getErrorCode().equals(ErrorStrings.DEVICE_CODE_FLOW_AUTHORIZATION_PENDING_ERROR_CODE)) {
@@ -1018,9 +1048,16 @@ AcquireTokenResult getAcquireTokenResultFromResultBundle(@NonNull final Bundle r
10181048
final MsalBrokerResultAdapter resultAdapter = new MsalBrokerResultAdapter();
10191049
if (resultBundle.getBoolean(AuthenticationConstants.Broker.BROKER_REQUEST_V2_SUCCESS)) {
10201050
final AcquireTokenResult acquireTokenResult = new AcquireTokenResult();
1021-
acquireTokenResult.setLocalAuthenticationResult(
1022-
resultAdapter.authenticationResultFromBundle(resultBundle)
1023-
);
1051+
final ILocalAuthenticationResult authResult =
1052+
resultAdapter.authenticationResultFromBundle(resultBundle);
1053+
acquireTokenResult.setLocalAuthenticationResult(authResult);
1054+
1055+
// Propagate ClientDataInfo from LocalAuthenticationResult to AcquireTokenResult
1056+
if (authResult instanceof LocalAuthenticationResult) {
1057+
acquireTokenResult.setClientDataInfo(
1058+
((LocalAuthenticationResult) authResult).getClientDataInfo()
1059+
);
1060+
}
10241061
// Set broker performance metrics if available
10251062
final BrokerPerformanceMetrics metrics = resultAdapter.getBrokerPerformanceMetricsFromBundle(resultBundle);
10261063
if (metrics != null) {

common4j/src/main/com/microsoft/identity/common/java/controllers/BaseController.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,9 @@ public AcquireTokenResult acquireTokenWithPassword(@NonNull final RopcTokenComma
219219
final TokenResult tokenResult = oAuth2Strategy.requestToken(ropcTokenRequest);
220220

221221
acquireTokenResult.setTokenResult(tokenResult);
222+
if (tokenResult != null) {
223+
acquireTokenResult.setClientDataInfo(tokenResult.getClientDataInfo());
224+
}
222225

223226
@SuppressWarnings(WarningType.rawtype_warning) final OAuth2TokenCache tokenCache = parameters.getOAuth2TokenCache();
224227

@@ -251,6 +254,9 @@ public AcquireTokenResult acquireTokenWithPassword(@NonNull final RopcTokenComma
251254
Telemetry.emit(new CacheEndEvent());
252255
}
253256

257+
// Set server client data info on the authentication result for IPC propagation
258+
authenticationResult.setClientDataInfo(tokenResult.getClientDataInfo());
259+
254260
// Set the AuthenticationResult on the final result object
255261
acquireTokenResult.setLocalAuthenticationResult(authenticationResult);
256262
}
@@ -484,6 +490,7 @@ protected void renewAccessToken(@NonNull final SilentTokenCommandParameters para
484490
);
485491

486492
acquireTokenSilentResult.setTokenResult(tokenResult);
493+
acquireTokenSilentResult.setClientDataInfo(tokenResult.getClientDataInfo());
487494

488495
ResultUtil.logResult(methodTag, tokenResult);
489496

@@ -528,6 +535,9 @@ protected void renewAccessToken(@NonNull final SilentTokenCommandParameters para
528535
Telemetry.emit(new CacheEndEvent());
529536
}
530537

538+
// Set server client data info on the authentication result for IPC propagation
539+
authenticationResult.setClientDataInfo(tokenResult.getClientDataInfo());
540+
531541
// Set the AuthenticationResult on the final result object
532542
acquireTokenSilentResult.setLocalAuthenticationResult(authenticationResult);
533543
} else {

common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/AbstractMicrosoftStsTokenResponseHandler.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ public TokenResult handleTokenResponse(@NonNull final HttpResponse response) thr
113113
final ClientDataInfo clientDataInfo = ClientDataInfo.fromPipeDelimited(clientDataHeader);
114114
if (null != clientDataInfo) {
115115
clientDataInfo.emitToSpan();
116+
result.setClientDataInfo(clientDataInfo);
116117
}
117118
}
118119

common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/MicrosoftStsAuthorizationResult.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
import com.microsoft.identity.common.java.providers.oauth2.AuthorizationErrorResponse;
2727
import com.microsoft.identity.common.java.providers.oauth2.AuthorizationResponse;
2828
import com.microsoft.identity.common.java.providers.oauth2.AuthorizationStatus;
29+
import com.microsoft.identity.common.java.telemetry.ClientDataInfo;
30+
31+
import javax.annotation.Nullable;
2932

3033
/**
3134
* Sub class of {@link MicrosoftAuthorizationResult}.
@@ -34,6 +37,9 @@
3437
public class MicrosoftStsAuthorizationResult
3538
extends MicrosoftAuthorizationResult<MicrosoftStsAuthorizationResponse, MicrosoftStsAuthorizationErrorResponse> {
3639

40+
@Nullable
41+
private ClientDataInfo mClientDataInfo;
42+
3743
/**
3844
* Constructor of {@link MicrosoftStsAuthorizationResult}.
3945
*
@@ -54,4 +60,22 @@ public MicrosoftStsAuthorizationResult(final AuthorizationStatus authStatus, fin
5460
super(authStatus, errorResponse);
5561
}
5662

63+
/**
64+
* Gets the {@link ClientDataInfo} parsed from the clientdata redirect query parameter.
65+
*
66+
* @return The ClientDataInfo, or null if the parameter was absent or unparseable.
67+
*/
68+
@Nullable
69+
public ClientDataInfo getClientDataInfo() {
70+
return mClientDataInfo;
71+
}
72+
73+
/**
74+
* Sets the {@link ClientDataInfo} parsed from the clientdata redirect query parameter.
75+
*
76+
* @param clientDataInfo The ClientDataInfo to set.
77+
*/
78+
public void setClientDataInfo(@Nullable final ClientDataInfo clientDataInfo) {
79+
mClientDataInfo = clientDataInfo;
80+
}
5781
}

common4j/src/main/com/microsoft/identity/common/java/providers/microsoft/microsoftsts/MicrosoftStsAuthorizationResultFactory.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,9 @@ protected MicrosoftStsAuthorizationResult parseRedirectUriAndCreateAuthorization
7575

7676
final Map<String, String> urlParameters = UrlUtil.getParameters(redirectUri);
7777

78+
ClientDataInfo clientDataInfo = null;
7879
if (CommonFlightsManager.INSTANCE.getFlightsProvider().isFlightEnabled(CommonFlight.ENABLE_SERVER_CLIENT_DATA_TELEMETRY)) {
79-
final ClientDataInfo clientDataInfo = ClientDataInfo.fromPipeDelimited(urlParameters.get(ClientDataInfo.CLIENTDATA_QUERY_PARAMETER));
80+
clientDataInfo = ClientDataInfo.fromPipeDelimited(urlParameters.get(ClientDataInfo.CLIENTDATA_QUERY_PARAMETER));
8081
if (null != clientDataInfo) {
8182
clientDataInfo.emitToSpan();
8283
}
@@ -107,6 +108,8 @@ protected MicrosoftStsAuthorizationResult parseRedirectUriAndCreateAuthorization
107108
);
108109
}
109110

111+
result.setClientDataInfo(clientDataInfo);
112+
110113
return result;
111114
}
112115

common4j/src/main/com/microsoft/identity/common/java/providers/oauth2/TokenResult.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@
2323
package com.microsoft.identity.common.java.providers.oauth2;
2424

2525
import com.microsoft.identity.common.java.telemetry.CliTelemInfo;
26+
import com.microsoft.identity.common.java.telemetry.ClientDataInfo;
27+
28+
import javax.annotation.Nullable;
2629

2730
/**
2831
* Holds the request of a token request. The request will either contain the success result or the error result.
@@ -32,6 +35,8 @@ public class TokenResult implements IResult {
3235
private TokenResponse mTokenResponse;
3336
private TokenErrorResponse mTokenErrorResponse;
3437
private CliTelemInfo mCliTelemInfo;
38+
@Nullable
39+
private ClientDataInfo mClientDataInfo;
3540
private boolean mSuccess = false;
3641

3742
public TokenResult() {
@@ -110,6 +115,25 @@ public void setCliTelemInfo(final CliTelemInfo cliTelemInfo) {
110115
mCliTelemInfo = cliTelemInfo;
111116
}
112117

118+
/**
119+
* Gets the {@link ClientDataInfo} parsed from the x-ms-clientdata response header.
120+
*
121+
* @return The ClientDataInfo, or null if the header was absent or unparseable.
122+
*/
123+
@Nullable
124+
public ClientDataInfo getClientDataInfo() {
125+
return mClientDataInfo;
126+
}
127+
128+
/**
129+
* Sets the {@link ClientDataInfo} parsed from the x-ms-clientdata response header.
130+
*
131+
* @param clientDataInfo The ClientDataInfo to set.
132+
*/
133+
public void setClientDataInfo(@Nullable final ClientDataInfo clientDataInfo) {
134+
mClientDataInfo = clientDataInfo;
135+
}
136+
113137
/**
114138
* Returns whether the token request was successful or not.
115139
*

0 commit comments

Comments
 (0)