@@ -16,105 +16,11 @@ use std::{ffi::OsStr, fmt::Debug, str, sync::Arc};
1616use time:: OffsetDateTime ;
1717use tracing:: trace;
1818
19- #[ cfg( feature = "old_azure_cli" ) ]
20- mod az_cli_date_format {
21- use azure_core:: error:: { ErrorKind , ResultExt } ;
22- use serde:: { Deserialize , Deserializer } ;
23- use time:: format_description:: FormatItem ;
24- use time:: macros:: format_description;
25- #[ cfg( not( unix) ) ]
26- use time:: UtcOffset ;
27- use time:: { OffsetDateTime , PrimitiveDateTime } ;
28-
29- // cspell:ignore subsecond
30- const FORMAT : & [ FormatItem ] =
31- format_description ! ( "[year]-[month]-[day] [hour]:[minute]:[second].[subsecond digits:6]" ) ;
32-
33- pub fn parse ( s : & str ) -> azure_core:: Result < OffsetDateTime > {
34- // expiresOn from azure cli uses the local timezone and needs to be converted to UTC
35- let dt = PrimitiveDateTime :: parse ( s, FORMAT )
36- . with_context ( ErrorKind :: DataConversion , || {
37- format ! ( "unable to parse expiresOn '{s}" )
38- } ) ?;
39- Ok ( assume_local ( & dt) )
40- }
41-
42- #[ cfg( unix) ]
43- /// attempt to convert `PrimitiveDateTime` to `OffsetDate` using
44- /// `tz::TimeZone`. If any part of the conversion fails, such as if no
45- /// timezone can be found, then use use the value as UTC.
46- pub ( crate ) fn assume_local ( date : & PrimitiveDateTime ) -> OffsetDateTime {
47- let as_utc = date. assume_utc ( ) ;
48-
49- // try parsing the timezone from `TZ` environment variable. If that
50- // fails, or the environment variable doesn't exist, try using
51- // `TimeZone::local`. If that fails, then just return the UTC date.
52- let Some ( tz) = std:: env:: var ( "TZ" )
53- . ok ( )
54- . and_then ( |x| tz:: TimeZone :: from_posix_tz ( & x) . ok ( ) )
55- . or_else ( || tz:: TimeZone :: local ( ) . ok ( ) )
56- else {
57- return as_utc;
58- } ;
59-
60- let as_unix = as_utc. unix_timestamp ( ) ;
61-
62- // if we can't find the local time type, just return the UTC date
63- let Ok ( local_time_type) = tz. find_local_time_type ( as_unix) else {
64- return as_utc;
65- } ;
66-
67- // if we can't convert the unix timestamp to a DateTime, just return the UTC date
68- let date = as_utc. date ( ) ;
69- let time = as_utc. time ( ) ;
70- let Ok ( date) = tz:: DateTime :: new (
71- date. year ( ) ,
72- u8:: from ( date. month ( ) ) ,
73- date. day ( ) ,
74- time. hour ( ) ,
75- time. minute ( ) ,
76- time. second ( ) ,
77- time. nanosecond ( ) ,
78- * local_time_type,
79- ) else {
80- return as_utc;
81- } ;
82-
83- // if we can't then convert to unix time (with the timezone) and then
84- // back into an OffsetDateTime, then return the UTC date
85- let Ok ( date) = OffsetDateTime :: from_unix_timestamp ( date. unix_time ( ) ) else {
86- return as_utc;
87- } ;
88-
89- date
90- }
91-
92- /// Assumes the local offset. Default to UTC if unable to get local offset.
93- #[ cfg( not( unix) ) ]
94- pub ( crate ) fn assume_local ( date : & PrimitiveDateTime ) -> OffsetDateTime {
95- date. assume_offset ( UtcOffset :: current_local_offset ( ) . unwrap_or ( UtcOffset :: UTC ) )
96- }
97-
98- pub fn deserialize < ' de , D > ( deserializer : D ) -> Result < OffsetDateTime , D :: Error >
99- where
100- D : Deserializer < ' de > ,
101- {
102- let s = String :: deserialize ( deserializer) ?;
103- parse ( & s) . map_err ( serde:: de:: Error :: custom)
104- }
105- }
106-
10719/// The response from `az account get-access-token --output json`.
10820#[ derive( Debug , Clone , Deserialize ) ]
10921struct CliTokenResponse {
11022 #[ serde( rename = "accessToken" ) ]
11123 pub access_token : Secret ,
112- #[ cfg( feature = "old_azure_cli" ) ]
113- #[ serde( rename = "expiresOn" , with = "az_cli_date_format" ) ]
114- /// The token's expiry time formatted in the local timezone.
115- /// Unfortunately, this requires additional timezone dependencies.
116- /// See https://github.com/Azure/azure-cli/issues/19700 for details.
117- pub local_expires_on : OffsetDateTime ,
11824 #[ serde( rename = "expires_on" ) ]
11925 /// The token's expiry time in seconds since the epoch, a unix timestamp.
12026 /// Available in Azure CLI 2.54.0 or newer.
@@ -131,19 +37,10 @@ impl CliTokenResponse {
13137 . with_context ( ErrorKind :: DataConversion , || {
13238 format ! ( "unable to parse expires_on '{timestamp}'" )
13339 } ) ?) ,
134- None => {
135- #[ cfg( feature = "old_azure_cli" ) ]
136- {
137- Ok ( self . local_expires_on )
138- }
139- #[ cfg( not( feature = "old_azure_cli" ) ) ]
140- {
141- Err ( Error :: message (
142- ErrorKind :: DataConversion ,
143- "expires_on field not found. Please use Azure CLI 2.54.0 or newer." ,
144- ) )
145- }
146- }
40+ None => Err ( Error :: message (
41+ ErrorKind :: DataConversion ,
42+ "expires_on field not found. Please use Azure CLI 2.54.0 or newer." ,
43+ ) ) ,
14744 }
14845 }
14946}
@@ -307,68 +204,7 @@ impl From<TokenCredentialOptions> for AzureCliCredentialOptions {
307204#[ cfg( test) ]
308205mod tests {
309206 use super :: * ;
310- #[ cfg( feature = "old_azure_cli" ) ]
311- use serial_test:: serial;
312- #[ cfg( feature = "old_azure_cli" ) ]
313- use time:: macros:: datetime;
314-
315- #[ cfg( feature = "old_azure_cli" ) ]
316- #[ test]
317- #[ serial]
318- fn can_parse_expires_on ( ) -> azure_core:: Result < ( ) > {
319- let expires_on = "2022-07-30 12:12:53.919110" ;
320- assert_eq ! (
321- az_cli_date_format:: parse( expires_on) ?,
322- az_cli_date_format:: assume_local( & datetime!( 2022 -07 -30 12 : 12 : 53.919110 ) )
323- ) ;
324-
325- Ok ( ( ) )
326- }
327-
328- #[ cfg( all( feature = "old_azure_cli" , unix) ) ]
329- #[ test]
330- #[ serial]
331- /// test the timezone conversion works as expected on unix platforms
332- ///
333- /// To validate the timezone conversion works as expected, this test
334- /// temporarily sets the timezone to PST, performs the check, then resets
335- /// the TZ environment variable.
336- fn check_timezone ( ) -> azure_core:: Result < ( ) > {
337- let before = std:: env:: var ( "TZ" ) . ok ( ) ;
338- std:: env:: set_var ( "TZ" , "US/Pacific" ) ;
339- let expires_on = "2022-11-30 12:12:53.919110" ;
340- let result = az_cli_date_format:: parse ( expires_on) ;
341-
342- if let Some ( before) = before {
343- std:: env:: set_var ( "TZ" , before) ;
344- } else {
345- std:: env:: remove_var ( "TZ" ) ;
346- }
347-
348- let expected = datetime ! ( 2022 -11 -30 20 : 12 : 53.0 ) . assume_utc ( ) ;
349- assert_eq ! ( expected, result?) ;
350-
351- Ok ( ( ) )
352- }
353-
354- /// Test `from_json` for `CliTokenResponse` for old Azure CLI
355- #[ test]
356- fn read_old_cli_token_response ( ) -> azure_core:: Result < ( ) > {
357- let json = br#"
358- {
359- "accessToken": "MuchLonger_NotTheRealOne_Sv8Orn0Wq0OaXuQEg",
360- "expiresOn": "2024-01-01 19:23:16.000000",
361- "subscription": "33b83be5-faf7-42ea-a712-320a5f9dd111",
362- "tenant": "065e9f5e-870d-4ed1-af2b-1b58092353f3",
363- "tokenType": "Bearer"
364- }
365- "# ;
366- let token_response: CliTokenResponse = from_json ( json) ?;
367- assert_eq ! ( token_response. expires_on, None ) ;
368- Ok ( ( ) )
369- }
370207
371- /// Test `from_json` for `CliTokenResponse` for current Azure CLI
372208 #[ test]
373209 fn read_cli_token_response ( ) -> azure_core:: Result < ( ) > {
374210 let json = br#"
0 commit comments