all lists on lists.proxmox.com
 help / color / mirror / Atom feed
From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 2/2] api2/access: implement term ticket
Date: Fri, 17 Jul 2020 15:38:38 +0200	[thread overview]
Message-ID: <20200717133838.7244-3-d.csapak@proxmox.com> (raw)
In-Reply-To: <20200717133838.7244-1-d.csapak@proxmox.com>

modeled after pves/pmgs vncticket (i substituted the vnc with term)
by putting the path and username as secret data in the ticket

when sending the ticket to /access/ticket it only verifies it,
checks the privs on the path and does not generate a new ticket

Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
---
 src/api2/access.rs  | 70 +++++++++++++++++++++++++++++++++++++++------
 src/tools/ticket.rs | 18 ++++++++++++
 2 files changed, 80 insertions(+), 8 deletions(-)

diff --git a/src/api2/access.rs b/src/api2/access.rs
index f5855ed..780fa9b 100644
--- a/src/api2/access.rs
+++ b/src/api2/access.rs
@@ -13,15 +13,21 @@ use crate::auth_helpers::*;
 use crate::api2::types::*;
 
 use crate::config::cached_user_info::CachedUserInfo;
-use crate::config::acl::PRIV_PERMISSIONS_MODIFY;
+use crate::config::acl::{PRIVILEGES, PRIV_PERMISSIONS_MODIFY};
 
 pub mod user;
 pub mod domain;
 pub mod acl;
 pub mod role;
 
-fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
-
+/// returns Ok(true) if a ticket has to be created
+/// and Ok(false) if not
+fn authenticate_user(
+    username: &str,
+    password: &str,
+    path: Option<String>,
+    privs: Option<String>,
+) -> Result<bool, Error> {
     let user_info = CachedUserInfo::new()?;
 
     if !user_info.is_active_user(&username) {
@@ -33,14 +39,42 @@ fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
     if password.starts_with("PBS:") {
         if let Ok((_age, Some(ticket_username))) = tools::ticket::verify_rsa_ticket(public_auth_key(), "PBS", password, None, -300, ticket_lifetime) {
             if ticket_username == username {
-                return Ok(());
+                return Ok(true);
             } else {
                 bail!("ticket login failed - wrong username");
             }
         }
+    } else if password.starts_with("PBSTERM:") {
+        if path.is_none() || privs.is_none() {
+            bail!("cannot check termnal ticket without path and priv");
+        }
+
+        let path = path.unwrap();
+        let privilege_name = privs.unwrap();
+
+        if let Ok((_age, _data)) = tools::ticket::verify_term_ticket(public_auth_key(), &username, &path, password) {
+
+            for (name, privilege) in PRIVILEGES {
+                if *name == privilege_name {
+
+                    let mut path_vec = Vec::new();
+                    for part in path.split('/') {
+                        if part != "" {
+                            path_vec.push(part);
+                        }
+                    }
+
+                    user_info.check_privs(username, &path_vec, *privilege, false)?;
+                    return Ok(false);
+                }
+            }
+
+            bail!("No such privilege");
+        }
     }
 
-    crate::auth::authenticate_user(username, password)
+    let _ = crate::auth::authenticate_user(username, password)?;
+    Ok(true)
 }
 
 #[api(
@@ -52,6 +86,16 @@ fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
             password: {
                 schema: PASSWORD_SCHEMA,
             },
+            path: {
+                type: String,
+                description: "path",
+                optional: true,
+            },
+            privs: {
+                type: String,
+                description: "privs",
+                optional: true,
+            },
         },
     },
     returns: {
@@ -78,9 +122,14 @@ fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
 /// Create or verify authentication ticket.
 ///
 /// Returns: An authentication ticket with additional infos.
-fn create_ticket(username: String, password: String) -> Result<Value, Error> {
-    match authenticate_user(&username, &password) {
-        Ok(_) => {
+fn create_ticket(
+    username: String,
+    password: String,
+    path: Option<String>,
+    privs: Option<String>,
+) -> Result<Value, Error> {
+    match authenticate_user(&username, &password, path, privs) {
+        Ok(true) => {
 
             let ticket = assemble_rsa_ticket( private_auth_key(), "PBS", Some(&username), None)?;
 
@@ -94,6 +143,11 @@ fn create_ticket(username: String, password: String) -> Result<Value, Error> {
                 "CSRFPreventionToken": token,
             }))
         }
+        Ok(false) => {
+            Ok(json!({
+                "username": username,
+            }))
+        }
         Err(err) => {
             let client_ip = "unknown"; // $rpcenv->get_client_ip() || '';
             log::error!("authentication failure; rhost={} user={} msg={}", client_ip, username, err.to_string());
diff --git a/src/tools/ticket.rs b/src/tools/ticket.rs
index 4727b1e..fc8750e 100644
--- a/src/tools/ticket.rs
+++ b/src/tools/ticket.rs
@@ -11,6 +11,24 @@ use crate::tools::epoch_now_u64;
 
 pub const TICKET_LIFETIME: i64 = 3600*2; // 2 hours
 
+const TERM_PREFIX: &str = "PBSTERM";
+
+pub fn assemble_term_ticket(
+    keypair: &PKey<Private>,
+    username: &str,
+    path: &str,
+) -> Result<String, Error> {
+    assemble_rsa_ticket(keypair, TERM_PREFIX, None, Some(&format!("{}{}", username, path)))
+}
+
+pub fn verify_term_ticket(
+    keypair: &PKey<Public>,
+    username: &str,
+    path: &str,
+    ticket: &str,
+) -> Result<(i64, Option<String>), Error> {
+    verify_rsa_ticket(keypair, TERM_PREFIX, ticket, Some(&format!("{}{}", username, path)), -300, TICKET_LIFETIME)
+}
 
 pub fn assemble_rsa_ticket(
     keypair: &PKey<Private>,
-- 
2.20.1





      parent reply	other threads:[~2020-07-17 13:38 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-07-17 13:38 [pbs-devel] [PATCH proxmox-backup 0/2] prerequisites for console Dominik Csapak
2020-07-17 13:38 ` [pbs-devel] [PATCH proxmox-backup 1/2] server/config: add mechanism to update template Dominik Csapak
2020-07-17 13:38 ` Dominik Csapak [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200717133838.7244-3-d.csapak@proxmox.com \
    --to=d.csapak@proxmox.com \
    --cc=pbs-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal