From: Dominik Csapak <d.csapak@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox-backup 2/5] api2/access: implement term ticket
Date: Tue, 21 Jul 2020 11:10:37 +0200 [thread overview]
Message-ID: <20200721091040.7632-3-d.csapak@proxmox.com> (raw)
In-Reply-To: <20200721091040.7632-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>
---
changes from last version:
* include the port in the termticket
* use rstfmt
src/api2/access.rs | 79 +++++++++++++++++++++++++++++++++++++++------
src/tools/ticket.rs | 32 ++++++++++++++++++
2 files changed, 101 insertions(+), 10 deletions(-)
diff --git a/src/api2/access.rs b/src/api2/access.rs
index f5855ed..46fbd99 100644
--- a/src/api2/access.rs
+++ b/src/api2/access.rs
@@ -13,15 +13,22 @@ 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>,
+ port: Option<u16>,
+) -> Result<bool, Error> {
let user_info = CachedUserInfo::new()?;
if !user_info.is_active_user(&username) {
@@ -33,14 +40,43 @@ 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() || port.is_none() {
+ bail!("cannot check termnal ticket without path, priv and port");
+ }
+
+ let path = path.unwrap();
+ let privilege_name = privs.unwrap();
+ let port = port.unwrap();
+
+ if let Ok((_age, _data)) =
+ tools::ticket::verify_term_ticket(public_auth_key(), &username, &path, port, 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 +88,21 @@ fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
password: {
schema: PASSWORD_SCHEMA,
},
+ path: {
+ type: String,
+ description: "Path for verifying terminal tickets.",
+ optional: true,
+ },
+ privs: {
+ type: String,
+ description: "Privilege for verifying terminal tickets.",
+ optional: true,
+ },
+ port: {
+ type: Integer,
+ description: "Port for verifying terminal tickets.",
+ optional: true,
+ },
},
},
returns: {
@@ -78,11 +129,16 @@ 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(_) => {
-
- let ticket = assemble_rsa_ticket( private_auth_key(), "PBS", Some(&username), None)?;
+fn create_ticket(
+ username: String,
+ password: String,
+ path: Option<String>,
+ privs: Option<String>,
+ port: Option<u16>,
+) -> Result<Value, Error> {
+ match authenticate_user(&username, &password, path, privs, port) {
+ Ok(true) => {
+ let ticket = assemble_rsa_ticket(private_auth_key(), "PBS", Some(&username), None)?;
let token = assemble_csrf_prevention_token(csrf_secret(), &username);
@@ -94,6 +150,9 @@ 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..ff639ce 100644
--- a/src/tools/ticket.rs
+++ b/src/tools/ticket.rs
@@ -11,6 +11,38 @@ 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,
+ port: u16,
+) -> Result<String, Error> {
+ assemble_rsa_ticket(
+ keypair,
+ TERM_PREFIX,
+ None,
+ Some(&format!("{}{}{}", username, path, port)),
+ )
+}
+
+pub fn verify_term_ticket(
+ keypair: &PKey<Public>,
+ username: &str,
+ path: &str,
+ port: u16,
+ ticket: &str,
+) -> Result<(i64, Option<String>), Error> {
+ verify_rsa_ticket(
+ keypair,
+ TERM_PREFIX,
+ ticket,
+ Some(&format!("{}{}{}", username, path, port)),
+ -300,
+ TICKET_LIFETIME,
+ )
+}
pub fn assemble_rsa_ticket(
keypair: &PKey<Private>,
--
2.20.1
next prev parent reply other threads:[~2020-07-21 9:10 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-21 9:10 [pbs-devel] [PATCH proxmox-backup 0/5] implement web console Dominik Csapak
2020-07-21 9:10 ` [pbs-devel] [PATCH proxmox-backup 1/5] server/config: add mechanism to update template Dominik Csapak
2020-07-21 9:10 ` Dominik Csapak [this message]
2020-07-21 9:10 ` [pbs-devel] [PATCH proxmox-backup 3/5] api2/nodes: add termproxy and vncwebsocket api calls Dominik Csapak
2020-07-21 9:10 ` [pbs-devel] [PATCH proxmox-backup 4/5] server/rest: add console to index Dominik Csapak
2020-07-21 9:10 ` [pbs-devel] [PATCH proxmox-backup 5/5] ui: add Console Button Dominik Csapak
2020-07-23 11:24 ` [pbs-devel] applied-series: [PATCH proxmox-backup 0/5] implement web console Thomas Lamprecht
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=20200721091040.7632-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox