[pbs-devel] [RFC proxmox-backup 11/15] client: allow using ApiToken + secret

Fabian Grünbichler f.gruenbichler at proxmox.com
Mon Oct 19 09:39:15 CEST 2020


in place of user + password.

Signed-off-by: Fabian Grünbichler <f.gruenbichler at proxmox.com>
---

Notes:
    this will need a followup to disentangle user+password/tokenid+secret and host+port from the datastore

 src/api2/types/mod.rs     |  2 +-
 src/client/http_client.rs | 41 +++++++++++++++++++++++++++++----------
 2 files changed, 32 insertions(+), 11 deletions(-)

diff --git a/src/api2/types/mod.rs b/src/api2/types/mod.rs
index 65411f73..67740ca8 100644
--- a/src/api2/types/mod.rs
+++ b/src/api2/types/mod.rs
@@ -66,7 +66,7 @@ const_regex!{
 
     pub DNS_NAME_OR_IP_REGEX = concat!(r"^(?:", DNS_NAME!(), "|",  IPRE!(), r")$");
 
-    pub BACKUP_REPO_URL_REGEX = concat!(r"^^(?:(?:(", USER_ID_REGEX_STR!(), ")@)?(", DNS_NAME!(), "|",  IPRE_BRACKET!() ,"):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR!(), r")$");
+    pub BACKUP_REPO_URL_REGEX = concat!(r"^^(?:(?:(", USER_ID_REGEX_STR!(), "|", APITOKEN_ID_REGEX_STR!(), ")@)?(", DNS_NAME!(), "|",  IPRE_BRACKET!() ,"):)?(?:([0-9]{1,5}):)?(", PROXMOX_SAFE_ID_REGEX_STR!(), r")$");
 
     pub CERT_FINGERPRINT_SHA256_REGEX = r"^(?:[0-9a-fA-F][0-9a-fA-F])(?::[0-9a-fA-F][0-9a-fA-F]){31}$";
 
diff --git a/src/client/http_client.rs b/src/client/http_client.rs
index f0f6b9ce..8881d9a0 100644
--- a/src/client/http_client.rs
+++ b/src/client/http_client.rs
@@ -101,7 +101,7 @@ pub struct HttpClient {
     server: String,
     port: u16,
     fingerprint: Arc<Mutex<Option<String>>>,
-    first_auth: BroadcastFuture<()>,
+    first_auth: Option<BroadcastFuture<()>>,
     auth: Arc<RwLock<AuthInfo>>,
     ticket_abort: futures::future::AbortHandle,
     _options: HttpClientOptions,
@@ -375,6 +375,13 @@ impl HttpClient {
             }
         });
 
+        let first_auth = if userid.is_tokenid() {
+            // TODO check access here?
+            None
+        } else {
+            Some(BroadcastFuture::new(Box::new(login_future)))
+        };
+
         Ok(Self {
             client,
             server: String::from(server),
@@ -382,7 +389,7 @@ impl HttpClient {
             fingerprint: verified_fingerprint,
             auth,
             ticket_abort,
-            first_auth: BroadcastFuture::new(Box::new(login_future)),
+            first_auth,
             _options: options,
         })
     }
@@ -392,7 +399,10 @@ impl HttpClient {
     /// Login is done on demand, so this is only required if you need
     /// access to authentication data in 'AuthInfo'.
     pub async fn login(&self) -> Result<AuthInfo, Error> {
-        self.first_auth.listen().await?;
+        if let Some(future) = &self.first_auth {
+            future.listen().await?;
+        }
+
         let authinfo = self.auth.read().unwrap();
         Ok(authinfo.clone())
     }
@@ -475,10 +485,14 @@ impl HttpClient {
         let client = self.client.clone();
 
         let auth =  self.login().await?;
-
-        let enc_ticket = format!("PBSAuthCookie={}", percent_encode(auth.ticket.as_bytes(), DEFAULT_ENCODE_SET));
-        req.headers_mut().insert("Cookie", HeaderValue::from_str(&enc_ticket).unwrap());
-        req.headers_mut().insert("CSRFPreventionToken", HeaderValue::from_str(&auth.token).unwrap());
+        if auth.userid.is_tokenid() {
+            let enc_api_token = format!("{}:{}", auth.userid, percent_encode(auth.ticket.as_bytes(), DEFAULT_ENCODE_SET));
+            req.headers_mut().insert("Authorization", HeaderValue::from_str(&enc_api_token).unwrap());
+        } else {
+            let enc_ticket = format!("PBSAuthCookie={}", percent_encode(auth.ticket.as_bytes(), DEFAULT_ENCODE_SET));
+            req.headers_mut().insert("Cookie", HeaderValue::from_str(&enc_ticket).unwrap());
+            req.headers_mut().insert("CSRFPreventionToken", HeaderValue::from_str(&auth.token).unwrap());
+        }
 
         Self::api_request(client, req).await
     }
@@ -577,11 +591,18 @@ impl HttpClient {
         protocol_name: String,
     ) -> Result<(H2Client, futures::future::AbortHandle), Error> {
 
-        let auth = self.login().await?;
         let client = self.client.clone();
+        let auth =  self.login().await?;
+
+        if auth.userid.is_tokenid() {
+            let enc_api_token = format!("{}:{}", auth.userid, percent_encode(auth.ticket.as_bytes(), DEFAULT_ENCODE_SET));
+            req.headers_mut().insert("Authorization", HeaderValue::from_str(&enc_api_token).unwrap());
+        } else {
+            let enc_ticket = format!("PBSAuthCookie={}", percent_encode(auth.ticket.as_bytes(), DEFAULT_ENCODE_SET));
+            req.headers_mut().insert("Cookie", HeaderValue::from_str(&enc_ticket).unwrap());
+            req.headers_mut().insert("CSRFPreventionToken", HeaderValue::from_str(&auth.token).unwrap());
+        }
 
-        let enc_ticket = format!("PBSAuthCookie={}", percent_encode(auth.ticket.as_bytes(), DEFAULT_ENCODE_SET));
-        req.headers_mut().insert("Cookie", HeaderValue::from_str(&enc_ticket).unwrap());
         req.headers_mut().insert("UPGRADE", HeaderValue::from_str(&protocol_name).unwrap());
 
         let resp = client.request(req).await?;
-- 
2.20.1






More information about the pbs-devel mailing list