This is an automated email from the ASF dual-hosted git repository.
mneumann pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs-object-store.git
The following commit(s) were added to refs/heads/main by this push:
new 0ec788f fix(azure): fix integer overflow in Fabric token expiry check
(#641)
0ec788f is described below
commit 0ec788f8803d388a8c53990ba7d96c24c6d48906
Author: Desmond Cheong <[email protected]>
AuthorDate: Wed Feb 18 02:35:12 2026 -0800
fix(azure): fix integer overflow in Fabric token expiry check (#641)
* Fix Fabric token expiry check
* Update test to check for the new token
* Bikeshedding test
---
src/azure/credential.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 63 insertions(+), 3 deletions(-)
diff --git a/src/azure/credential.rs b/src/azure/credential.rs
index dcc6cdd..66ce655 100644
--- a/src/azure/credential.rs
+++ b/src/azure/credential.rs
@@ -1016,7 +1016,7 @@ impl TokenProvider for FabricTokenOAuthProvider {
) -> crate::Result<TemporaryToken<Arc<AzureCredential>>> {
if let Some(storage_access_token) = &self.storage_access_token {
if let Some(expiry) = self.token_expiry {
- let exp_in = expiry - Self::get_current_timestamp();
+ let exp_in =
expiry.saturating_sub(Self::get_current_timestamp());
if exp_in > TOKEN_MIN_TTL {
return Ok(TemporaryToken {
token:
Arc::new(AzureCredential::BearerToken(storage_access_token.clone())),
@@ -1043,8 +1043,9 @@ impl TokenProvider for FabricTokenOAuthProvider {
.text()
.await
.map_err(|source| Error::TokenResponseBody { source })?;
- let exp_in = Self::validate_and_get_expiry(&access_token)
- .map_or(3600, |expiry| expiry - Self::get_current_timestamp());
+ let exp_in = Self::validate_and_get_expiry(&access_token).map_or(3600,
|expiry| {
+ expiry.saturating_sub(Self::get_current_timestamp())
+ });
Ok(TemporaryToken {
token: Arc::new(AzureCredential::BearerToken(access_token)),
expiry: Some(Instant::now() + Duration::from_secs(exp_in)),
@@ -1216,4 +1217,63 @@ mod tests {
}
}
}
+
+ #[tokio::test]
+ async fn test_fabric_refresh_expired_token() {
+ let server = MockServer::new().await;
+
+ // Create an expired initial token (1 hour in the past)
+ let expired_timestamp =
FabricTokenOAuthProvider::get_current_timestamp() - 3600;
+ let claims = format!(r#"{{"exp":{expired_timestamp}}}"#);
+ let encoded_claims = BASE64_URL_SAFE_NO_PAD.encode(claims.as_bytes());
+ let expired_token = format!("header.{encoded_claims}.signature");
+
+ // Create a fresh token that the mock API will return (1 hour in the
future)
+ let fresh_timestamp =
FabricTokenOAuthProvider::get_current_timestamp() + 3600;
+ let fresh_claims = format!(r#"{{"exp":{fresh_timestamp}}}"#);
+ let fresh_encoded =
BASE64_URL_SAFE_NO_PAD.encode(fresh_claims.as_bytes());
+ let fresh_token = format!("header.{fresh_encoded}.signature");
+ let expected_token = fresh_token.clone();
+
+ // Mock the Fabric token service to return a fresh token
+ server.push_fn(move |req| {
+ assert_eq!(req.headers().get(&PARTNER_TOKEN).unwrap(),
"session-token");
+ assert_eq!(
+ req.headers().get(&CLUSTER_IDENTIFIER).unwrap(),
+ "cluster-id"
+ );
+ assert_eq!(req.headers().get(&PROXY_HOST).unwrap(), "fake");
+
+ Response::new(fresh_token)
+ });
+
+ let provider = FabricTokenOAuthProvider {
+ fabric_token_service_url: server.url().to_string(),
+ fabric_workload_host: "fake".to_string(),
+ fabric_session_token: "session-token".to_string(),
+ fabric_cluster_identifier: "cluster-id".to_string(),
+ storage_access_token: Some(expired_token),
+ token_expiry: Some(expired_timestamp),
+ };
+
+ let client = HttpClient::new(Client::new());
+ let retry = RetryConfig::default();
+
+ let result = provider.fetch_token(&client, &retry).await;
+
+ assert!(
+ result.is_ok(),
+ "fetch_token should handle expired cached token gracefully"
+ );
+
+ let temp_token = result.unwrap();
+
+ // Verify we got a fresh token from the API (not the expired cached
one)
+ if let AzureCredential::BearerToken(token) = temp_token.token.as_ref()
{
+ assert_eq!(
+ token, &expected_token,
+ "Should have fetched fresh token from API, not returned
expired cached token"
+ );
+ }
+ }
}