11mod  authorization_policy; 
22
3+ pub ( crate )  use  self :: authorization_policy:: AuthorizationPolicy ; 
4+ use  crate :: clients:: { EMULATOR_ACCOUNT ,  EMULATOR_ACCOUNT_KEY } ; 
35use  azure_core:: { 
46    auth:: TokenCredential , 
57    error:: { ErrorKind ,  ResultExt } , 
68} ; 
7- use  std:: sync:: Arc ; 
9+ use  futures:: lock:: Mutex ; 
10+ use  std:: { 
11+     mem:: replace, 
12+     ops:: { Deref ,  DerefMut } , 
13+     sync:: Arc , 
14+ } ; 
815use  url:: Url ; 
916
10- pub ( crate )  use  authorization_policy:: AuthorizationPolicy ; 
11- 
12- use  crate :: clients:: { EMULATOR_ACCOUNT ,  EMULATOR_ACCOUNT_KEY } ; 
13- 
1417/// Credentials for accessing a storage account. 
1518/// 
1619/// # Example 
@@ -22,7 +25,10 @@ use crate::clients::{EMULATOR_ACCOUNT, EMULATOR_ACCOUNT_KEY};
2225/// azure_storage::StorageCredentials::access_key("my_account", "SOMEACCESSKEY"); 
2326/// ``` 
2427#[ derive( Clone ) ]  
25- pub  enum  StorageCredentials  { 
28+ pub  struct  StorageCredentials ( pub  Arc < Mutex < StorageCredentialsInner > > ) ; 
29+ 
30+ #[ derive( Clone ) ]  
31+ pub  enum  StorageCredentialsInner  { 
2632    Key ( String ,  String ) , 
2733    SASToken ( Vec < ( String ,  String ) > ) , 
2834    BearerToken ( String ) , 
@@ -31,6 +37,11 @@ pub enum StorageCredentials {
3137} 
3238
3339impl  StorageCredentials  { 
40+     /// Create a new `StorageCredentials` from a `StorageCredentialsInner` 
41+ fn  wrap ( inner :  StorageCredentialsInner )  -> Self  { 
42+         Self ( Arc :: new ( Mutex :: new ( inner) ) ) 
43+     } 
44+ 
3445    /// Create an Access Key based credential 
3546/// 
3647/// When you create a storage account, Azure generates two 512-bit storage 
@@ -44,7 +55,7 @@ impl StorageCredentials {
4455        A :  Into < String > , 
4556        K :  Into < String > , 
4657    { 
47-         Self :: Key ( account. into ( ) ,  key. into ( ) ) 
58+         Self :: wrap ( StorageCredentialsInner :: Key ( account. into ( ) ,  key. into ( ) ) ) 
4859    } 
4960
5061    /// Create a Shared Access Signature (SAS) token based credential 
@@ -60,7 +71,7 @@ impl StorageCredentials {
6071        S :  AsRef < str > , 
6172    { 
6273        let  params = get_sas_token_parms ( token. as_ref ( ) ) ?; 
63-         Ok ( Self :: SASToken ( params) ) 
74+         Ok ( Self :: wrap ( StorageCredentialsInner :: SASToken ( params) ) ) 
6475    } 
6576
6677    /// Create an Bearer Token based credential 
@@ -77,7 +88,7 @@ impl StorageCredentials {
7788    where 
7889        T :  Into < String > , 
7990    { 
80-         Self :: BearerToken ( token. into ( ) ) 
91+         Self :: wrap ( StorageCredentialsInner :: BearerToken ( token. into ( ) ) ) 
8192    } 
8293
8394    /// Create a `TokenCredential` based credential 
@@ -98,7 +109,7 @@ impl StorageCredentials {
98109/// 
99110/// ref: <https://docs.microsoft.com/rest/api/storageservices/authorize-with-azure-active-directory> 
100111pub  fn  token_credential ( credential :  Arc < dyn  TokenCredential > )  -> Self  { 
101-         Self :: TokenCredential ( credential) 
112+         Self :: wrap ( StorageCredentialsInner :: TokenCredential ( credential) ) 
102113    } 
103114
104115    /// Create an anonymous credential 
@@ -113,45 +124,71 @@ impl StorageCredentials {
113124/// 
114125/// ref: <https://docs.microsoft.com/azure/storage/blobs/anonymous-read-access-configure> 
115126pub  fn  anonymous ( )  -> Self  { 
116-         Self :: Anonymous 
127+         Self :: wrap ( StorageCredentialsInner :: Anonymous ) 
117128    } 
118129
119130    /// Create an Access Key credential for use with the Azure Storage emulator 
120131pub  fn  emulator ( )  -> Self  { 
121132        Self :: access_key ( EMULATOR_ACCOUNT ,  EMULATOR_ACCOUNT_KEY ) 
122133    } 
134+ 
135+     /// Replace the current credentials with new credentials 
136+ /// 
137+ /// This method is useful for updating credentials that are used by multiple 
138+ /// clients at once. 
139+ pub  async  fn  replace ( & self ,  other :  Self )  -> azure_core:: Result < ( ) >  { 
140+         if  Arc :: ptr_eq ( & self . 0 ,  & other. 0 )  { 
141+             return  Ok ( ( ) ) ; 
142+         } 
143+ 
144+         let  mut  creds = self . 0 . lock ( ) . await ; 
145+         let  other = other. 0 . lock ( ) . await ; 
146+         let  creds = creds. deref_mut ( ) ; 
147+         let  other = other. deref ( ) . clone ( ) ; 
148+         let  _old_creds = replace ( creds,  other) ; 
149+ 
150+         Ok ( ( ) ) 
151+     } 
123152} 
124153
125154impl  std:: fmt:: Debug  for  StorageCredentials  { 
126155    fn  fmt ( & self ,  f :  & mut  std:: fmt:: Formatter < ' _ > )  -> std:: fmt:: Result  { 
127-         match  & self  { 
128-             StorageCredentials :: Key ( _,  _)  => f
129-                 . debug_struct ( "StorageCredentials" ) 
130-                 . field ( "credential" ,  & "Key" ) 
131-                 . finish ( ) , 
132-             StorageCredentials :: SASToken ( _)  => f
133-                 . debug_struct ( "StorageCredentials" ) 
134-                 . field ( "credential" ,  & "SASToken" ) 
135-                 . finish ( ) , 
136-             StorageCredentials :: BearerToken ( _)  => f
137-                 . debug_struct ( "StorageCredentials" ) 
138-                 . field ( "credential" ,  & "BearerToken" ) 
139-                 . finish ( ) , 
140-             StorageCredentials :: TokenCredential ( _)  => f
141-                 . debug_struct ( "StorageCredentials" ) 
142-                 . field ( "credential" ,  & "TokenCredential" ) 
143-                 . finish ( ) , 
144-             StorageCredentials :: Anonymous  => f
156+         let  creds = self . 0 . try_lock ( ) ; 
157+ 
158+         match  creds. as_deref ( )  { 
159+             None  => f
145160                . debug_struct ( "StorageCredentials" ) 
146-                 . field ( "credential" ,  & "Anonymous " ) 
161+                 . field ( "credential" ,  & "locked " ) 
147162                . finish ( ) , 
163+             Some ( inner)  => match  & inner { 
164+                 StorageCredentialsInner :: Key ( _,  _)  => f
165+                     . debug_struct ( "StorageCredentials" ) 
166+                     . field ( "credential" ,  & "Key" ) 
167+                     . finish ( ) , 
168+                 StorageCredentialsInner :: SASToken ( _)  => f
169+                     . debug_struct ( "StorageCredentials" ) 
170+                     . field ( "credential" ,  & "SASToken" ) 
171+                     . finish ( ) , 
172+                 StorageCredentialsInner :: BearerToken ( _)  => f
173+                     . debug_struct ( "StorageCredentials" ) 
174+                     . field ( "credential" ,  & "BearerToken" ) 
175+                     . finish ( ) , 
176+                 StorageCredentialsInner :: TokenCredential ( _)  => f
177+                     . debug_struct ( "StorageCredentials" ) 
178+                     . field ( "credential" ,  & "TokenCredential" ) 
179+                     . finish ( ) , 
180+                 StorageCredentialsInner :: Anonymous  => f
181+                     . debug_struct ( "StorageCredentials" ) 
182+                     . field ( "credential" ,  & "Anonymous" ) 
183+                     . finish ( ) , 
184+             } , 
148185        } 
149186    } 
150187} 
151188
152189impl  From < Arc < dyn  TokenCredential > >  for  StorageCredentials  { 
153190    fn  from ( cred :  Arc < dyn  TokenCredential > )  -> Self  { 
154-         Self :: TokenCredential ( cred) 
191+         Self :: token_credential ( cred) 
155192    } 
156193} 
157194
@@ -160,7 +197,7 @@ impl TryFrom<&Url> for StorageCredentials {
160197    fn  try_from ( value :  & Url )  -> Result < Self ,  Self :: Error >  { 
161198        match  value. query ( )  { 
162199            Some ( query)  => Self :: sas_token ( query) , 
163-             None  => Ok ( Self :: Anonymous ) , 
200+             None  => Ok ( Self :: anonymous ( ) ) , 
164201        } 
165202    } 
166203} 
@@ -188,3 +225,30 @@ fn get_sas_token_parms(sas_token: &str) -> azure_core::Result<Vec<(String, Strin
188225        . map ( |p| ( String :: from ( p. 0 ) ,  String :: from ( p. 1 ) ) ) 
189226        . collect ( ) ) 
190227} 
228+ 
229+ #[ cfg( test) ]  
230+ mod  tests { 
231+     use  super :: * ; 
232+ 
233+     #[ tokio:: test]  
234+     async  fn  test_replacement ( )  -> azure_core:: Result < ( ) >  { 
235+         let  base = StorageCredentials :: anonymous ( ) ; 
236+         let  other = StorageCredentials :: bearer_token ( "foo" ) ; 
237+ 
238+         base. replace ( other) . await ?; 
239+ 
240+         // check that the value was updated 
241+         { 
242+             let  inner = base. 0 . lock ( ) . await ; 
243+             let  inner_locked = inner. deref ( ) ; 
244+             assert ! ( 
245+                 matches!( & inner_locked,  & StorageCredentialsInner :: BearerToken ( value)  if  value == "foo" ) 
246+             ) ; 
247+         } 
248+ 
249+         // updating with the same StorageCredentials shouldn't deadlock 
250+         base. replace ( base. clone ( ) ) . await ?; 
251+ 
252+         Ok ( ( ) ) 
253+     } 
254+ } 
0 commit comments