@@ -22,6 +22,7 @@ use tokio::sync::Mutex;
2222
2323/// Configuration for the authentication client
2424#[ derive( Debug , Clone ) ]
25+ #[ allow( dead_code) ] // TODO: Remove when auth client is integrated
2526pub struct AuthConfig {
2627 /// Base URL of the verifier (e.g., "https://verifier.example.com")
2728 pub verifier_base_url : String ,
@@ -52,26 +53,30 @@ impl Default for AuthConfig {
5253
5354/// Session token with expiration information
5455#[ derive( Debug , Clone ) ]
56+ #[ allow( dead_code) ] // TODO: Remove when auth client is integrated
5557struct SessionToken {
5658 token : String ,
5759 expires_at : DateTime < Utc > ,
5860 session_id : u64 ,
5961}
6062
6163impl SessionToken {
64+ #[ allow( dead_code) ] // TODO: Remove when auth client is integrated
6265 fn is_valid ( & self , buffer_minutes : i64 ) -> bool {
6366 let buffer = Duration :: minutes ( buffer_minutes) ;
6467 Utc :: now ( ) + buffer < self . expires_at
6568 }
6669}
6770
6871/// Mock TPM operations for testing
72+ #[ allow( dead_code) ] // TODO: Remove when auth client is integrated
6973pub trait TpmOperations : Send + Sync {
7074 fn generate_proof ( & self , challenge : & str ) -> Result < ProofOfPossession > ;
7175}
7276
7377/// Default mock TPM implementation
7478#[ derive( Debug , Clone ) ]
79+ #[ allow( dead_code) ] // TODO: Remove when auth client is integrated
7580pub struct MockTpmOperations ;
7681
7782impl TpmOperations for MockTpmOperations {
@@ -92,13 +97,15 @@ impl TpmOperations for MockTpmOperations {
9297}
9398
9499/// Standalone authentication client implementing the challenge-response protocol
100+ #[ allow( dead_code) ] // TODO: Remove when auth client is integrated
95101pub struct AuthenticationClient {
96102 config : AuthConfig ,
97103 http_client : Client ,
98104 session_token : Arc < Mutex < Option < SessionToken > > > ,
99105 tpm_ops : Box < dyn TpmOperations > ,
100106}
101107
108+ #[ allow( dead_code) ] // TODO: Remove when auth client is integrated
102109impl AuthenticationClient {
103110 /// Create a new authentication client with the given configuration
104111 pub fn new ( config : AuthConfig ) -> Result < Self > {
@@ -135,6 +142,42 @@ impl AuthenticationClient {
135142 } )
136143 }
137144
145+ /// Create a raw authentication client with no middleware
146+ /// This is used internally by the authentication middleware to avoid infinite loops
147+ pub fn new_raw ( config : AuthConfig ) -> Result < Self > {
148+ let timeout = std:: time:: Duration :: from_millis ( config. timeout_ms ) ;
149+ let http_client = Client :: builder ( )
150+ . timeout ( timeout)
151+ . danger_accept_invalid_certs ( true ) // For testing
152+ . build ( ) ?;
153+
154+ Ok ( Self {
155+ config,
156+ http_client,
157+ session_token : Arc :: new ( Mutex :: new ( None ) ) ,
158+ tpm_ops : Box :: new ( MockTpmOperations ) ,
159+ } )
160+ }
161+
162+ /// Create a raw authentication client with custom TPM operations and no middleware
163+ pub fn new_raw_with_tpm_ops (
164+ config : AuthConfig ,
165+ tpm_ops : Box < dyn TpmOperations > ,
166+ ) -> Result < Self > {
167+ let timeout = std:: time:: Duration :: from_millis ( config. timeout_ms ) ;
168+ let http_client = Client :: builder ( )
169+ . timeout ( timeout)
170+ . danger_accept_invalid_certs ( true ) // For testing
171+ . build ( ) ?;
172+
173+ Ok ( Self {
174+ config,
175+ http_client,
176+ session_token : Arc :: new ( Mutex :: new ( None ) ) ,
177+ tpm_ops,
178+ } )
179+ }
180+
138181 /// Get a valid authentication token, performing authentication if necessary
139182 pub async fn get_auth_token ( & self ) -> Result < String > {
140183 let token_guard = self . session_token . lock ( ) . await ;
@@ -176,6 +219,47 @@ impl AuthenticationClient {
176219 debug ! ( "Authentication token cleared" ) ;
177220 }
178221
222+ /// Get a valid authentication token with metadata (token, expiration, session_id)
223+ /// This method is used by the authentication middleware to access token details
224+ pub async fn get_auth_token_with_metadata (
225+ & self ,
226+ ) -> Result < ( String , DateTime < Utc > , u64 ) > {
227+ let token_guard = self . session_token . lock ( ) . await ;
228+
229+ // Check if we have a valid token
230+ if let Some ( ref token) = * token_guard {
231+ if token. is_valid ( self . config . token_refresh_buffer_minutes ) {
232+ debug ! ( "Using existing valid token with metadata" ) ;
233+ return Ok ( (
234+ token. token . clone ( ) ,
235+ token. expires_at ,
236+ token. session_id ,
237+ ) ) ;
238+ } else {
239+ debug ! (
240+ "Token expired or expiring soon, need to re-authenticate"
241+ ) ;
242+ }
243+ } else {
244+ debug ! ( "No token available, need to authenticate" ) ;
245+ }
246+
247+ drop ( token_guard) ; // Release lock before authentication
248+
249+ // Perform authentication and return metadata
250+ let _token_string = self . authenticate ( ) . await ?;
251+
252+ // Get the token details from the newly stored token
253+ let token_guard = self . session_token . lock ( ) . await ;
254+ if let Some ( ref token) = * token_guard {
255+ Ok ( ( token. token . clone ( ) , token. expires_at , token. session_id ) )
256+ } else {
257+ Err ( anyhow ! (
258+ "Token was not stored properly after authentication"
259+ ) )
260+ }
261+ }
262+
179263 /// Perform the complete authentication flow
180264 async fn authenticate ( & self ) -> Result < String > {
181265 info ! (
@@ -723,4 +807,47 @@ mod tests {
723807
724808 assert ! ( !client. has_valid_token( ) . await ) ;
725809 }
810+
811+ #[ tokio:: test]
812+ async fn test_raw_client_creation ( ) {
813+ let config = AuthConfig {
814+ verifier_base_url : "https://127.0.0.1:8881" . to_string ( ) ,
815+ agent_id : "test-agent-raw" . to_string ( ) ,
816+ avoid_tpm : true ,
817+ timeout_ms : 1000 ,
818+ token_refresh_buffer_minutes : 5 ,
819+ max_auth_retries : 2 ,
820+ } ;
821+
822+ let raw_client = AuthenticationClient :: new_raw ( config) . unwrap ( ) ;
823+
824+ // Verify the client was created successfully
825+ assert_eq ! ( raw_client. config. agent_id, "test-agent-raw" ) ;
826+ assert_eq ! ( raw_client. config. timeout_ms, 1000 ) ;
827+ assert ! ( raw_client. config. avoid_tpm) ;
828+ }
829+
830+ #[ tokio:: test]
831+ async fn test_raw_client_with_tpm_ops ( ) {
832+ let config = AuthConfig {
833+ verifier_base_url : "https://127.0.0.1:8881" . to_string ( ) ,
834+ agent_id : "test-agent-raw-tpm" . to_string ( ) ,
835+ avoid_tpm : false ,
836+ timeout_ms : 2000 ,
837+ token_refresh_buffer_minutes : 10 ,
838+ max_auth_retries : 1 ,
839+ } ;
840+
841+ let custom_tpm_ops = Box :: new ( MockTpmOperations ) ;
842+ let raw_client = AuthenticationClient :: new_raw_with_tpm_ops (
843+ config,
844+ custom_tpm_ops,
845+ )
846+ . unwrap ( ) ;
847+
848+ // Verify the client was created successfully
849+ assert_eq ! ( raw_client. config. agent_id, "test-agent-raw-tpm" ) ;
850+ assert_eq ! ( raw_client. config. timeout_ms, 2000 ) ;
851+ assert ! ( !raw_client. config. avoid_tpm) ;
852+ }
726853}
0 commit comments