From: Stefan Reiter <s.reiter@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH v3 proxmox-backup 08/20] server/rest: extract auth to seperate module
Date: Wed, 31 Mar 2021 12:21:50 +0200 [thread overview]
Message-ID: <20210331102202.14767-9-s.reiter@proxmox.com> (raw)
In-Reply-To: <20210331102202.14767-1-s.reiter@proxmox.com>
Signed-off-by: Stefan Reiter <s.reiter@proxmox.com>
---
src/server.rs | 2 +
src/server/auth.rs | 102 +++++++++++++++++++++++++++++++++++++++++++++
src/server/rest.rs | 96 +-----------------------------------------
3 files changed, 105 insertions(+), 95 deletions(-)
create mode 100644 src/server/auth.rs
diff --git a/src/server.rs b/src/server.rs
index 7c159c23..b6a37b92 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -89,3 +89,5 @@ mod report;
pub use report::*;
pub mod ticket;
+
+pub mod auth;
diff --git a/src/server/auth.rs b/src/server/auth.rs
new file mode 100644
index 00000000..24151886
--- /dev/null
+++ b/src/server/auth.rs
@@ -0,0 +1,102 @@
+//! Provides authentication primitives for the HTTP server
+use anyhow::{bail, format_err, Error};
+
+use crate::tools::ticket::Ticket;
+use crate::auth_helpers::*;
+use crate::tools;
+use crate::config::cached_user_info::CachedUserInfo;
+use crate::api2::types::{Authid, Userid};
+
+use hyper::header;
+use percent_encoding::percent_decode_str;
+
+pub struct UserAuthData {
+ ticket: String,
+ csrf_token: Option<String>,
+}
+
+pub enum AuthData {
+ User(UserAuthData),
+ ApiToken(String),
+}
+
+pub fn extract_auth_data(headers: &http::HeaderMap) -> Option<AuthData> {
+ if let Some(raw_cookie) = headers.get(header::COOKIE) {
+ if let Ok(cookie) = raw_cookie.to_str() {
+ if let Some(ticket) = tools::extract_cookie(cookie, "PBSAuthCookie") {
+ let csrf_token = match headers.get("CSRFPreventionToken").map(|v| v.to_str()) {
+ Some(Ok(v)) => Some(v.to_owned()),
+ _ => None,
+ };
+ return Some(AuthData::User(UserAuthData {
+ ticket,
+ csrf_token,
+ }));
+ }
+ }
+ }
+
+ match headers.get(header::AUTHORIZATION).map(|v| v.to_str()) {
+ Some(Ok(v)) => {
+ if v.starts_with("PBSAPIToken ") || v.starts_with("PBSAPIToken=") {
+ Some(AuthData::ApiToken(v["PBSAPIToken ".len()..].to_owned()))
+ } else {
+ None
+ }
+ },
+ _ => None,
+ }
+}
+
+pub fn check_auth(
+ method: &hyper::Method,
+ auth_data: &AuthData,
+ user_info: &CachedUserInfo,
+) -> Result<Authid, Error> {
+ match auth_data {
+ AuthData::User(user_auth_data) => {
+ let ticket = user_auth_data.ticket.clone();
+ let ticket_lifetime = tools::ticket::TICKET_LIFETIME;
+
+ let userid: Userid = Ticket::<super::ticket::ApiTicket>::parse(&ticket)?
+ .verify_with_time_frame(public_auth_key(), "PBS", None, -300..ticket_lifetime)?
+ .require_full()?;
+
+ let auth_id = Authid::from(userid.clone());
+ if !user_info.is_active_auth_id(&auth_id) {
+ bail!("user account disabled or expired.");
+ }
+
+ if method != hyper::Method::GET {
+ if let Some(csrf_token) = &user_auth_data.csrf_token {
+ verify_csrf_prevention_token(csrf_secret(), &userid, &csrf_token, -300, ticket_lifetime)?;
+ } else {
+ bail!("missing CSRF prevention token");
+ }
+ }
+
+ Ok(auth_id)
+ },
+ AuthData::ApiToken(api_token) => {
+ let mut parts = api_token.splitn(2, ':');
+ let tokenid = parts.next()
+ .ok_or_else(|| format_err!("failed to split API token header"))?;
+ let tokenid: Authid = tokenid.parse()?;
+
+ if !user_info.is_active_auth_id(&tokenid) {
+ bail!("user account or token disabled or expired.");
+ }
+
+ let tokensecret = parts.next()
+ .ok_or_else(|| format_err!("failed to split API token header"))?;
+ let tokensecret = percent_decode_str(tokensecret)
+ .decode_utf8()
+ .map_err(|_| format_err!("failed to decode API token header"))?;
+
+ crate::config::token_shadow::verify_secret(&tokenid, &tokensecret)?;
+
+ Ok(tokenid)
+ }
+ }
+}
+
diff --git a/src/server/rest.rs b/src/server/rest.rs
index 150125ec..9a971890 100644
--- a/src/server/rest.rs
+++ b/src/server/rest.rs
@@ -34,6 +34,7 @@ use proxmox::http_err;
use super::environment::RestEnvironment;
use super::formatter::*;
use super::ApiConfig;
+use super::auth::{check_auth, extract_auth_data};
use crate::api2::types::{Authid, Userid};
use crate::auth_helpers::*;
@@ -588,101 +589,6 @@ fn extract_lang_header(headers: &http::HeaderMap) -> Option<String> {
None
}
-struct UserAuthData {
- ticket: String,
- csrf_token: Option<String>,
-}
-
-enum AuthData {
- User(UserAuthData),
- ApiToken(String),
-}
-
-fn extract_auth_data(headers: &http::HeaderMap) -> Option<AuthData> {
- if let Some(raw_cookie) = headers.get(header::COOKIE) {
- if let Ok(cookie) = raw_cookie.to_str() {
- if let Some(ticket) = tools::extract_cookie(cookie, "PBSAuthCookie") {
- let csrf_token = match headers.get("CSRFPreventionToken").map(|v| v.to_str()) {
- Some(Ok(v)) => Some(v.to_owned()),
- _ => None,
- };
- return Some(AuthData::User(UserAuthData { ticket, csrf_token }));
- }
- }
- }
-
- match headers.get(header::AUTHORIZATION).map(|v| v.to_str()) {
- Some(Ok(v)) => {
- if v.starts_with("PBSAPIToken ") || v.starts_with("PBSAPIToken=") {
- Some(AuthData::ApiToken(v["PBSAPIToken ".len()..].to_owned()))
- } else {
- None
- }
- }
- _ => None,
- }
-}
-
-fn check_auth(
- method: &hyper::Method,
- auth_data: &AuthData,
- user_info: &CachedUserInfo,
-) -> Result<Authid, Error> {
- match auth_data {
- AuthData::User(user_auth_data) => {
- let ticket = user_auth_data.ticket.clone();
- let ticket_lifetime = tools::ticket::TICKET_LIFETIME;
-
- let userid: Userid = Ticket::<super::ticket::ApiTicket>::parse(&ticket)?
- .verify_with_time_frame(public_auth_key(), "PBS", None, -300..ticket_lifetime)?
- .require_full()?;
-
- let auth_id = Authid::from(userid.clone());
- if !user_info.is_active_auth_id(&auth_id) {
- bail!("user account disabled or expired.");
- }
-
- if method != hyper::Method::GET {
- if let Some(csrf_token) = &user_auth_data.csrf_token {
- verify_csrf_prevention_token(
- csrf_secret(),
- &userid,
- &csrf_token,
- -300,
- ticket_lifetime,
- )?;
- } else {
- bail!("missing CSRF prevention token");
- }
- }
-
- Ok(auth_id)
- }
- AuthData::ApiToken(api_token) => {
- let mut parts = api_token.splitn(2, ':');
- let tokenid = parts
- .next()
- .ok_or_else(|| format_err!("failed to split API token header"))?;
- let tokenid: Authid = tokenid.parse()?;
-
- if !user_info.is_active_auth_id(&tokenid) {
- bail!("user account or token disabled or expired.");
- }
-
- let tokensecret = parts
- .next()
- .ok_or_else(|| format_err!("failed to split API token header"))?;
- let tokensecret = percent_decode_str(tokensecret)
- .decode_utf8()
- .map_err(|_| format_err!("failed to decode API token header"))?;
-
- crate::config::token_shadow::verify_secret(&tokenid, &tokensecret)?;
-
- Ok(tokenid)
- }
- }
-}
-
async fn handle_request(
api: Arc<ApiConfig>,
req: Request<Body>,
--
2.20.1
next prev parent reply other threads:[~2021-03-31 10:23 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-31 10:21 [pbs-devel] [PATCH v3 00/20] Single file restore for VM images Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 pxar 01/20] decoder/aio: add contents() and content_size() calls Stefan Reiter
2021-03-31 11:54 ` [pbs-devel] applied: " Wolfgang Bumiller
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 02/20] vsock_client: remove wrong comment Stefan Reiter
2021-04-01 9:53 ` [pbs-devel] applied: " Thomas Lamprecht
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 03/20] vsock_client: remove some &mut restrictions and rustfmt Stefan Reiter
2021-04-01 9:54 ` [pbs-devel] applied: " Thomas Lamprecht
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 04/20] vsock_client: support authorization header Stefan Reiter
2021-04-01 9:54 ` [pbs-devel] applied: " Thomas Lamprecht
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 05/20] proxmox_client_tools: move common key related functions to key_source.rs Stefan Reiter
2021-04-01 9:54 ` [pbs-devel] applied: " Thomas Lamprecht
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 06/20] file-restore: add binary and basic commands Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 07/20] file-restore: allow specifying output-format Stefan Reiter
2021-03-31 10:21 ` Stefan Reiter [this message]
2021-04-01 9:55 ` [pbs-devel] applied: [PATCH v3 proxmox-backup 08/20] server/rest: extract auth to seperate module Thomas Lamprecht
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 09/20] server/rest: add ApiAuth trait to make user auth generic Stefan Reiter
2021-03-31 12:55 ` Wolfgang Bumiller
2021-03-31 14:07 ` Thomas Lamprecht
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 10/20] file-restore-daemon: add binary with virtio-vsock API server Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 11/20] file-restore-daemon: add watchdog module Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 12/20] file-restore-daemon: add disk module Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 13/20] add tools/cpio encoding module Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 14/20] file-restore: add qemu-helper setuid binary Stefan Reiter
2021-03-31 14:15 ` Oguz Bektas
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 15/20] file-restore: add basic VM/block device support Stefan Reiter
2021-04-01 15:43 ` [pbs-devel] [PATCH v4 " Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 16/20] debian/client: add postinst hook to rebuild file-restore initramfs Stefan Reiter
2021-03-31 10:21 ` [pbs-devel] [PATCH v3 proxmox-backup 17/20] file-restore(-daemon): implement list API Stefan Reiter
2021-03-31 10:22 ` [pbs-devel] [PATCH v3 proxmox-backup 18/20] pxar/extract: add sequential variant of extract_sub_dir Stefan Reiter
2021-03-31 10:22 ` [pbs-devel] [PATCH v3 proxmox-backup 19/20] tools/zip: add zip_directory helper Stefan Reiter
2021-03-31 10:22 ` [pbs-devel] [PATCH v3 proxmox-backup 20/20] file-restore: add 'extract' command for VM file restore Stefan Reiter
2021-04-08 14:44 ` [pbs-devel] applied: [PATCH v3 00/20] Single file restore for VM images 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=20210331102202.14767-9-s.reiter@proxmox.com \
--to=s.reiter@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.