Skip to content

Commit 1bbb9cb

Browse files
CopilotAvery-Dunn
andcommitted
Add correlation ID support to exception classes and key error paths
Co-authored-by: Avery-Dunn <62066438+Avery-Dunn@users.noreply.github.com>
1 parent 9f3b584 commit 1bbb9cb

10 files changed

Lines changed: 126 additions & 22 deletions

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AbstractManagedIdentitySource.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,12 @@ public ManagedIdentityResponse getManagedIdentityResponse(
5353
throw new RuntimeException(e);
5454
} catch (MsalClientException e) {
5555
if (e.getCause() instanceof SocketException) {
56-
throw new MsalServiceException(e.getMessage(), MsalError.MANAGED_IDENTITY_UNREACHABLE_NETWORK, managedIdentitySourceType);
56+
String message = e.getMessage();
57+
LOG.error(LogHelper.createMessage(
58+
"[Managed Identity] Network unreachable: " + message,
59+
managedIdentityRequest.requestContext().correlationId()));
60+
throw new MsalServiceException(message, MsalError.MANAGED_IDENTITY_UNREACHABLE_NETWORK,
61+
managedIdentityRequest.requestContext().correlationId());
5762
}
5863

5964
throw e;
@@ -74,18 +79,23 @@ public ManagedIdentityResponse handleResponse(
7479
return getSuccessfulResponse(response);
7580
} else {
7681
message = getMessageFromErrorResponse(response);
77-
LOG.error("[Managed Identity] request failed, HttpStatusCode: {}, Error message: {}",
78-
response.statusCode(), message);
79-
throw new MsalServiceException(message, AuthenticationErrorCode.MANAGED_IDENTITY_REQUEST_FAILED, managedIdentitySourceType);
82+
LOG.error(LogHelper.createMessage(
83+
String.format("[Managed Identity] request failed, HttpStatusCode: %s, Error message: %s",
84+
response.statusCode(), message),
85+
managedIdentityRequest.requestContext().correlationId()));
86+
throw new MsalServiceException(message, AuthenticationErrorCode.MANAGED_IDENTITY_REQUEST_FAILED,
87+
managedIdentityRequest.requestContext().correlationId());
8088
}
8189
} catch (Exception e) {
8290
if (!(e instanceof MsalServiceException)) {
8391
message = String.format("[Managed Identity] Unexpected exception occurred when parsing the response, HttpStatusCode: %s, Error message: %s",
8492
response.statusCode(), e.getMessage());
93+
LOG.error(LogHelper.createMessage(message, managedIdentityRequest.requestContext().correlationId()));
94+
throw new MsalServiceException(message, AuthenticationErrorCode.MANAGED_IDENTITY_REQUEST_FAILED,
95+
managedIdentityRequest.requestContext().correlationId());
8596
} else {
8697
throw e;
8798
}
88-
throw new MsalServiceException(message, AuthenticationErrorCode.MANAGED_IDENTITY_REQUEST_FAILED, managedIdentitySourceType);
8999
}
90100
}
91101

@@ -103,7 +113,10 @@ protected ManagedIdentityResponse getSuccessfulResponse(IHttpResponse response)
103113
if (managedIdentityResponse == null || managedIdentityResponse.getAccessToken() == null
104114
|| managedIdentityResponse.getAccessToken().isEmpty() || managedIdentityResponse.getExpiresOn() == null
105115
|| managedIdentityResponse.getExpiresOn().isEmpty()) {
106-
throw new MsalServiceException("[Managed Identity] Response is either null or insufficient for authentication.", MsalError.MANAGED_IDENTITY_REQUEST_FAILED, managedIdentitySourceType);
116+
String message = "[Managed Identity] Response is either null or insufficient for authentication.";
117+
LOG.error(LogHelper.createMessage(message, managedIdentityRequest.requestContext().correlationId()));
118+
throw new MsalServiceException(message, MsalError.MANAGED_IDENTITY_REQUEST_FAILED,
119+
managedIdentityRequest.requestContext().correlationId());
107120
}
108121

109122
return managedIdentityResponse;

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenByAuthorizationGrantSupplier.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,13 +139,21 @@ private Map<String, String> getAuthorizationGrantIntegrated(String userName) thr
139139

140140
params = getSAMLAuthGrantParameters(wsTrustResponse);
141141
} else if (userRealmResponse.isAccountManaged()) {
142+
String message = "Password is required for managed user";
143+
clientApplication.log.error(
144+
LogHelper.createMessage(message, msalRequest.requestContext().correlationId()));
142145
throw new MsalClientException(
143-
"Password is required for managed user",
144-
AuthenticationErrorCode.PASSWORD_REQUIRED_FOR_MANAGED_USER);
146+
message,
147+
AuthenticationErrorCode.PASSWORD_REQUIRED_FOR_MANAGED_USER,
148+
msalRequest.requestContext().correlationId());
145149
} else {
150+
String message = "User Realm request failed";
151+
clientApplication.log.error(
152+
LogHelper.createMessage(message, msalRequest.requestContext().correlationId()));
146153
throw new MsalClientException(
147-
"User Realm request failed",
148-
AuthenticationErrorCode.USER_REALM_DISCOVERY_FAILED);
154+
message,
155+
AuthenticationErrorCode.USER_REALM_DISCOVERY_FAILED,
156+
msalRequest.requestContext().correlationId());
149157
}
150158

151159
return params;

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/AcquireTokenSilentSupplier.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ AuthenticationResult execute() throws Exception {
4141
clientApplication.clientId());
4242

4343
if (res == null) {
44-
throw new MsalClientException(AuthenticationErrorMessage.NO_TOKEN_IN_CACHE, AuthenticationErrorCode.CACHE_MISS);
44+
String message = AuthenticationErrorMessage.NO_TOKEN_IN_CACHE;
45+
clientApplication.log.info(
46+
LogHelper.createMessage(message, silentRequest.requestContext().correlationId()));
47+
throw new MsalClientException(message, AuthenticationErrorCode.CACHE_MISS,
48+
silentRequest.requestContext().correlationId());
4549
}
4650

4751
//Some cached tokens were found, but this metadata will be overwritten if token needs to be refreshed
@@ -71,7 +75,11 @@ AuthenticationResult execute() throws Exception {
7175
}
7276

7377
if (res == null || StringHelper.isBlank(res.accessToken())) {
74-
throw new MsalClientException(AuthenticationErrorMessage.NO_TOKEN_IN_CACHE, AuthenticationErrorCode.CACHE_MISS);
78+
String message = AuthenticationErrorMessage.NO_TOKEN_IN_CACHE;
79+
clientApplication.log.info(
80+
LogHelper.createMessage(message, silentRequest.requestContext().correlationId()));
81+
throw new MsalClientException(message, AuthenticationErrorCode.CACHE_MISS,
82+
silentRequest.requestContext().correlationId());
7583
}
7684

7785
LOG.debug("Returning token from cache");

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/HttpHelper.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public IHttpResponse executeHttpRequest(HttpRequest httpRequest,
5555

5656
} catch (Exception e) {
5757
httpEvent.setOauthErrorCode(AuthenticationErrorCode.UNKNOWN);
58+
String message = LogHelper.createMessage(
59+
"HTTP request execution failed: " + e.getMessage(),
60+
requestContext.correlationId());
61+
LOG.error(message);
5862
throw new MsalClientException(e);
5963
}
6064

@@ -93,6 +97,10 @@ IHttpResponse executeHttpRequest(HttpRequest httpRequest,
9397

9498
} catch (Exception e) {
9599
httpEvent.setOauthErrorCode(AuthenticationErrorCode.UNKNOWN);
100+
String message = LogHelper.createMessage(
101+
"HTTP request execution failed: " + e.getMessage(),
102+
requestContext.correlationId());
103+
LOG.error(message);
96104
throw new MsalClientException(e);
97105
}
98106

@@ -113,6 +121,7 @@ IHttpResponse executeHttpRequest(HttpRequest httpRequest) {
113121
try {
114122
httpResponse = executeHttpRequestWithRetries(httpRequest, httpClient);
115123
} catch (Exception e) {
124+
LOG.error("HTTP request execution failed: " + e.getMessage());
116125
throw new MsalClientException(e);
117126
}
118127

@@ -173,7 +182,11 @@ private void checkForThrottling(RequestContext requestContext) {
173182
long retryInMs = ThrottlingCache.retryInMs(requestThumbprint);
174183

175184
if (retryInMs > 0) {
176-
throw new MsalThrottlingException(retryInMs);
185+
String message = LogHelper.createMessage(
186+
"Request throttled, retry after " + retryInMs + " ms",
187+
requestContext.correlationId());
188+
LOG.warn(message);
189+
throw new MsalThrottlingException(retryInMs, requestContext.correlationId());
177190
}
178191
}
179192
}

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MsalClientException.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,15 @@ public MsalClientException(final Throwable throwable) {
2525
public MsalClientException(final String message, final String errorCode) {
2626
super(message, errorCode);
2727
}
28+
29+
/**
30+
* Initializes a new instance of the exception class with a specified error message and correlation ID
31+
*
32+
* @param message the error message that explains the reason for the exception
33+
* @param errorCode the error code
34+
* @param correlationId the correlation ID for request tracking
35+
*/
36+
public MsalClientException(final String message, final String errorCode, final String correlationId) {
37+
super(message, errorCode, correlationId);
38+
}
2839
}

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MsalException.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ public class MsalException extends RuntimeException {
1515
*/
1616
private String errorCode;
1717

18+
/**
19+
* Correlation ID for request tracking
20+
*/
21+
private String correlationId;
22+
1823
/**
1924
* Initializes a new instance of the exception class
2025
*
@@ -34,7 +39,24 @@ public MsalException(final String message, String errorCode) {
3439
this.errorCode = errorCode;
3540
}
3641

42+
/**
43+
* Initializes a new instance of the exception class with correlation ID
44+
*
45+
* @param message the error message that explains the reason for the exception
46+
* @param errorCode the error code
47+
* @param correlationId the correlation ID for request tracking
48+
*/
49+
public MsalException(final String message, String errorCode, String correlationId) {
50+
super(LogHelper.createMessage(message, correlationId));
51+
this.errorCode = errorCode;
52+
this.correlationId = correlationId;
53+
}
54+
3755
public String errorCode() {
3856
return this.errorCode;
3957
}
58+
59+
public String correlationId() {
60+
return this.correlationId;
61+
}
4062
}

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MsalServiceException.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ public class MsalServiceException extends MsalException {
1414

1515
private Integer statusCode;
1616
private String statusMessage;
17-
private String correlationId;
1817
private String claims;
1918
private Map<String, List<String>> headers;
2019
private String managedIdentitySource;
@@ -30,6 +29,17 @@ public MsalServiceException(final String message, final String error) {
3029
super(message, error);
3130
}
3231

32+
/**
33+
* Initializes a new instance of the exception class with a specified error message and correlation ID
34+
*
35+
* @param message the error message that explains the reason for the exception
36+
* @param error a simplified error code from {@link AuthenticationErrorCode} and used for references in documentation
37+
* @param correlationId the correlation ID for request tracking
38+
*/
39+
public MsalServiceException(final String message, final String error, final String correlationId) {
40+
super(message, error, correlationId);
41+
}
42+
3343
/**
3444
* Initializes a new instance of the exception class
3545
*
@@ -40,11 +50,10 @@ public MsalServiceException(
4050
final ErrorResponse errorResponse,
4151
final Map<String, List<String>> httpHeaders) {
4252

43-
super(errorResponse.errorDescription, errorResponse.error());
53+
super(errorResponse.errorDescription, errorResponse.error(), errorResponse.correlation_id());
4454
this.statusCode = errorResponse.statusCode();
4555
this.statusMessage = errorResponse.statusMessage();
4656
this.subError = errorResponse.subError();
47-
this.correlationId = errorResponse.correlation_id();
4857
this.claims = errorResponse.claims();
4958
this.headers = Collections.unmodifiableMap(httpHeaders);
5059
}
@@ -70,9 +79,7 @@ public MsalServiceException(
7079
* @param discoveryResponse response object from instance discovery network call
7180
*/
7281
public MsalServiceException(final AadInstanceDiscoveryResponse discoveryResponse) {
73-
super(discoveryResponse.errorDescription(), discoveryResponse.error());
74-
75-
this.correlationId = discoveryResponse.correlationId();
82+
super(discoveryResponse.errorDescription(), discoveryResponse.error(), discoveryResponse.correlationId());
7683
}
7784

7885
/**
@@ -92,8 +99,9 @@ public String statusMessage() {
9299
/**
93100
* An ID that can be used to piece up a single authentication flow.
94101
*/
102+
@Override
95103
public String correlationId() {
96-
return this.correlationId;
104+
return super.correlationId();
97105
}
98106

99107
/**

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/MsalThrottlingException.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,19 @@ public MsalThrottlingException(long retryInMs) {
2020
this.retryInMs = retryInMs;
2121
}
2222

23+
/**
24+
* Constructor for MsalThrottlingException class with correlation ID
25+
*
26+
* @param retryInMs time to wait before retrying in milliseconds
27+
* @param correlationId the correlation ID for request tracking
28+
*/
29+
public MsalThrottlingException(long retryInMs, String correlationId) {
30+
super("Request was throttled according to instructions from STS. Retry in " + retryInMs + " ms.",
31+
AuthenticationErrorCode.THROTTLED_REQUEST, correlationId);
32+
33+
this.retryInMs = retryInMs;
34+
}
35+
2336
/**
2437
* how long to wait before repeating request
2538
*/

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/RequestContext.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ public RequestContext(AbstractApplicationBase clientApplication,
3737
this.publicApi = publicApi;
3838
this.authority = clientApplication.authority();
3939
this.apiParameters = apiParameters;
40+
41+
// Log the correlation ID when RequestContext is created
42+
clientApplication.log.info(LogHelper.createMessage(
43+
"Request initiated with PublicApi: " + publicApi,
44+
this.correlationId));
4045
}
4146

4247
public RequestContext(AbstractApplicationBase clientApplication,

msal4j-sdk/src/main/java/com/microsoft/aad/msal4j/TokenRequestExecutor.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ AuthenticationResult executeTokenRequest() throws IOException {
3838
OAuthHttpRequest createOauthHttpRequest() throws MalformedURLException {
3939

4040
if (requestAuthority.tokenEndpointUrl() == null) {
41-
throw new MsalClientException("The endpoint URI is not specified",
42-
AuthenticationErrorCode.INVALID_ENDPOINT_URI);
41+
String message = "The endpoint URI is not specified";
42+
LOG.error(LogHelper.createMessage(message, msalRequest.requestContext().correlationId()));
43+
throw new MsalClientException(message,
44+
AuthenticationErrorCode.INVALID_ENDPOINT_URI,
45+
msalRequest.requestContext().correlationId());
4346
}
4447

4548
final OAuthHttpRequest oauthHttpRequest = new OAuthHttpRequest(

0 commit comments

Comments
 (0)