From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [212.224.123.68]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by lists.proxmox.com (Postfix) with ESMTPS id 3328B6B52F for ; Mon, 20 Sep 2021 12:37:39 +0200 (CEST) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 2671A1F86F for ; Mon, 20 Sep 2021 12:37:39 +0200 (CEST) Received: from proxmox-new.maurer-it.com (proxmox-new.maurer-it.com [94.136.29.106]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by firstgate.proxmox.com (Proxmox) with ESMTPS id 1D7D51F864 for ; Mon, 20 Sep 2021 12:37:37 +0200 (CEST) Received: from proxmox-new.maurer-it.com (localhost.localdomain [127.0.0.1]) by proxmox-new.maurer-it.com (Proxmox) with ESMTP id E0B2D4469C for ; Mon, 20 Sep 2021 12:37:36 +0200 (CEST) Date: Mon, 20 Sep 2021 12:37:27 +0200 From: Fabian =?iso-8859-1?q?Gr=FCnbichler?= To: Proxmox Backup Server development discussion References: <20210920091340.3251578-1-dietmar@proxmox.com> <20210920091340.3251578-12-dietmar@proxmox.com> In-Reply-To: <20210920091340.3251578-12-dietmar@proxmox.com> MIME-Version: 1.0 User-Agent: astroid/0.15.0 (https://github.com/astroidmail/astroid) Message-Id: <1632133600.d9d0bh5jn6.astroid@nora.none> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-SPAM-LEVEL: Spam detection results: 0 AWL 0.359 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Subject: Re: [pbs-devel] [PATCH proxmox-backup rebase 12/15] rest server: cleanup auth-log handling X-BeenThere: pbs-devel@lists.proxmox.com X-Mailman-Version: 2.1.29 Precedence: list List-Id: Proxmox Backup Server development discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Sep 2021 10:37:39 -0000 some small further cleanup potential in-line. On September 20, 2021 11:13 am, Dietmar Maurer wrote: > Handle auth logs the same way as access log. > - Configure with ApiConfig > - CommandoSocket command to reload auth-logs "api-auth-log-reopen" >=20 > Inside API calls, we now access the ApiConfig using the RestEnvironment. >=20 > The openid_login api now also logs failed logins and return http_err!(UNA= UTHORIZED, ..) > on failed logins. > --- > pbs-server/src/api_config.rs | 45 ++++++++++- > pbs-server/src/environment.rs | 49 +++++++++++- > src/api2/access/mod.rs | 26 +++---- > src/api2/access/openid.rs | 134 ++++++++++++++++++-------------- > src/bin/proxmox-backup-api.rs | 8 ++ > src/bin/proxmox-backup-proxy.rs | 31 +++++++- > src/server/rest.rs | 30 ++----- > 7 files changed, 215 insertions(+), 108 deletions(-) >=20 > diff --git a/pbs-server/src/api_config.rs b/pbs-server/src/api_config.rs > index fee94e88..e09f7af9 100644 > --- a/pbs-server/src/api_config.rs > +++ b/pbs-server/src/api_config.rs > @@ -26,6 +26,7 @@ pub struct ApiConfig { > templates: RwLock>, > template_files: RwLock>, > request_log: Option>>, > + auth_log: Option>>, > pub api_auth: Arc, > get_index_fn: GetIndexFn, > } > @@ -46,6 +47,7 @@ impl ApiConfig { > templates: RwLock::new(Handlebars::new()), > template_files: RwLock::new(HashMap::new()), > request_log: None, > + auth_log: None, > api_auth, > get_index_fn, > }) > @@ -172,7 +174,7 @@ impl ApiConfig { > self.request_log =3D Some(Arc::clone(&request_log)); > =20 > commando_sock.register_command("api-access-log-reopen".into(), m= ove |_args| { > - println!("re-opening log file"); > + println!("re-opening access-log file"); > request_log.lock().unwrap().reopen()?; > Ok(serde_json::Value::Null) > })?; > @@ -180,7 +182,46 @@ impl ApiConfig { > Ok(()) > } > =20 > - pub fn get_file_log(&self) -> Option<&Arc>> { > + pub fn enable_auth_log

( this is basically enable_file_log, but with > + &mut self, > + path: P, > + dir_opts: Option, > + file_opts: Option, > + commando_sock: &mut CommandoSocket, > + ) -> Result<(), Error> > + where > + P: Into > + { > + let path: PathBuf =3D path.into(); > + if let Some(base) =3D path.parent() { > + if !base.exists() { > + create_path(base, None, dir_opts).map_err(|err| format_e= rr!("{}", err))?; > + } > + } > + > + let logger_options =3D FileLogOptions { > + append: true, > + prefix_time: true, this set to true > + file_opts: file_opts.unwrap_or(CreateOptions::default()), > + ..Default::default() > + }; > + let auth_log =3D Arc::new(Mutex::new(FileLogger::new(&path, logg= er_options)?)); > + self.auth_log =3D Some(Arc::clone(&auth_log)); > + > + commando_sock.register_command("api-auth-log-reopen".into(), mov= e |_args| { > + println!("re-opening auth-log file"); and the command string and this message being different > + auth_log.lock().unwrap().reopen()?; > + Ok(serde_json::Value::Null) > + })?; > + > + Ok(()) > + } > + > + pub fn get_access_log(&self) -> Option<&Arc>> { > self.request_log.as_ref() > } > + > + pub fn get_auth_log(&self) -> Option<&Arc>> { > + self.auth_log.as_ref() > + } > } > diff --git a/pbs-server/src/environment.rs b/pbs-server/src/environment.r= s > index 0548b5bc..57d0d7d5 100644 > --- a/pbs-server/src/environment.rs > +++ b/pbs-server/src/environment.rs > @@ -1,24 +1,65 @@ > +use std::sync::Arc; > +use std::net::SocketAddr; > + > use serde_json::{json, Value}; > =20 > use proxmox::api::{RpcEnvironment, RpcEnvironmentType}; > =20 > +use crate::ApiConfig; > + > /// Encapsulates information about the runtime environment > pub struct RestEnvironment { > env_type: RpcEnvironmentType, > result_attributes: Value, > auth_id: Option, > - client_ip: Option, > + client_ip: Option, > + api: Arc, > } > =20 > impl RestEnvironment { > - pub fn new(env_type: RpcEnvironmentType) -> Self { > + pub fn new(env_type: RpcEnvironmentType, api: Arc) -> Sel= f { > Self { > result_attributes: json!({}), > auth_id: None, > client_ip: None, > env_type, > + api, > } > } > + > + pub fn api_config(&self) -> &ApiConfig { > + &self.api > + } > + > + pub fn log_auth(&self, auth_id: &str) { > + let msg =3D format!("successful auth for user '{}'", auth_id); > + log::info!("{}", msg); > + if let Some(auth_logger) =3D self.api.get_auth_log() { > + auth_logger.lock().unwrap().log(&msg); > + } > + } > + > + pub fn log_failed_auth(&self, failed_auth_id: Option, msg: &= str) { > + let msg =3D match (self.client_ip, failed_auth_id) { > + (Some(peer), Some(user)) =3D> { > + format!("authentication failure; rhost=3D{} user=3D{} ms= g=3D{}", peer, user, msg) > + } > + (Some(peer), None) =3D> { > + format!("authentication failure; rhost=3D{} msg=3D{}", p= eer, msg) > + } > + (None, Some(user)) =3D> { > + format!("authentication failure; rhost=3Dunknown user=3D= {} msg=3D{}", user, msg) > + } > + (None, None) =3D> { > + format!("authentication failure; rhost=3Dunknown msg=3D{= }", msg) > + } > + }; > + log::error!("{}", msg); > + if let Some(auth_logger) =3D self.api.get_auth_log() { > + auth_logger.lock().unwrap().log(&msg); > + } > + } > + > } > =20 > impl RpcEnvironment for RestEnvironment { > @@ -43,11 +84,11 @@ impl RpcEnvironment for RestEnvironment { > self.auth_id.clone() > } > =20 > - fn set_client_ip(&mut self, client_ip: Option)= { > + fn set_client_ip(&mut self, client_ip: Option) { > self.client_ip =3D client_ip; > } > =20 > - fn get_client_ip(&self) -> Option { > + fn get_client_ip(&self) -> Option { > self.client_ip > } > } > diff --git a/src/api2/access/mod.rs b/src/api2/access/mod.rs > index 58ac8ca4..0d247288 100644 > --- a/src/api2/access/mod.rs > +++ b/src/api2/access/mod.rs > @@ -12,7 +12,7 @@ use proxmox::{http_err, list_subdirs_api_method}; > use proxmox::{identity, sortable}; > =20 > use pbs_api_types::{ > - Userid, Authid, PASSWORD_SCHEMA, ACL_PATH_SCHEMA,=20 > + Userid, Authid, PASSWORD_SCHEMA, ACL_PATH_SCHEMA, > PRIVILEGES, PRIV_PERMISSIONS_MODIFY, PRIV_SYS_AUDIT, > }; > use pbs_tools::auth::private_auth_key; > @@ -196,6 +196,12 @@ pub fn create_ticket( > tfa_challenge: Option, > rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > + > + use pbs_server::RestEnvironment; > + > + let env: &RestEnvironment =3D rpcenv.as_any().downcast_ref::() > + .ok_or_else(|| format_err!("detected worng RpcEnvironment type")= )?; > + > match authenticate_user(&username, &password, path, privs, port, tfa= _challenge) { > Ok(AuthResult::Success) =3D> Ok(json!({ "username": username }))= , > Ok(AuthResult::CreateTicket) =3D> { > @@ -203,8 +209,7 @@ pub fn create_ticket( > let ticket =3D Ticket::new("PBS", &api_ticket)?.sign(private= _auth_key(), None)?; > let token =3D assemble_csrf_prevention_token(csrf_secret(), = &username); > =20 > - crate::server::rest::auth_logger()? > - .log(format!("successful auth for user '{}'", username))= ; > + env.log_auth(username.as_str()); > =20 > Ok(json!({ > "username": username, > @@ -223,20 +228,7 @@ pub fn create_ticket( > })) > } > Err(err) =3D> { > - let client_ip =3D match rpcenv.get_client_ip().map(|addr| ad= dr.ip()) { > - Some(ip) =3D> format!("{}", ip), > - None =3D> "unknown".into(), > - }; > - > - let msg =3D format!( > - "authentication failure; rhost=3D{} user=3D{} msg=3D{}", > - client_ip, > - username, > - err.to_string() > - ); > - crate::server::rest::auth_logger()?.log(&msg); > - log::error!("{}", msg); > - > + env.log_failed_auth(Some(username.to_string()), &err.to_stri= ng()); > Err(http_err!(UNAUTHORIZED, "permission check failed.")) > } > } > diff --git a/src/api2/access/openid.rs b/src/api2/access/openid.rs > index 38fab409..22166c5a 100644 > --- a/src/api2/access/openid.rs > +++ b/src/api2/access/openid.rs > @@ -1,14 +1,13 @@ > //! OpenID redirect/login API > use std::convert::TryFrom; > =20 > -use anyhow::{bail, Error}; > +use anyhow::{bail, format_err, Error}; > =20 > use serde_json::{json, Value}; > =20 > use proxmox::api::router::{Router, SubdirMap}; > use proxmox::api::{api, Permission, RpcEnvironment}; > -use proxmox::{list_subdirs_api_method}; > -use proxmox::{identity, sortable}; > +use proxmox::{http_err, list_subdirs_api_method, identity, sortable}; > =20 > use proxmox_openid::{OpenIdAuthenticator, OpenIdConfig}; > =20 > @@ -80,76 +79,95 @@ pub fn openid_login( > state: String, > code: String, > redirect_url: String, > - _rpcenv: &mut dyn RpcEnvironment, > + rpcenv: &mut dyn RpcEnvironment, > ) -> Result { > + use pbs_server::RestEnvironment; > + > + let env: &RestEnvironment =3D rpcenv.as_any().downcast_ref::() > + .ok_or_else(|| format_err!("detected worng RpcEnvironment type")= )?; > + > let user_info =3D CachedUserInfo::new()?; > =20 > - let (realm, private_auth_state) =3D > - OpenIdAuthenticator::verify_public_auth_state(PROXMOX_BACKUP_RUN= _DIR_M!(), &state)?; > + let mut tested_username =3D None; > =20 > - let (domains, _digest) =3D pbs_config::domains::config()?; > - let config: OpenIdRealmConfig =3D domains.lookup("openid", &realm)?; > + let result =3D proxmox::try_block!({ > =20 > - let open_id =3D openid_authenticator(&config, &redirect_url)?; > + let (realm, private_auth_state) =3D > + OpenIdAuthenticator::verify_public_auth_state(PROXMOX_BACKUP= _RUN_DIR_M!(), &state)?; > + > + let (domains, _digest) =3D pbs_config::domains::config()?; > + let config: OpenIdRealmConfig =3D domains.lookup("openid", &real= m)?; > + > + let open_id =3D openid_authenticator(&config, &redirect_url)?; > =20 > - let info =3D open_id.verify_authorization_code(&code, &private_auth_= state)?; > + let info =3D open_id.verify_authorization_code(&code, &private_a= uth_state)?; > =20 > - // eprintln!("VERIFIED {} {:?} {:?}", info.subject().as_str(), info.= name(), info.email()); > + // eprintln!("VERIFIED {} {:?} {:?}", info.subject().as_str(), i= nfo.name(), info.email()); > =20 > - let unique_name =3D match config.username_claim { > - None | Some(OpenIdUserAttribute::Subject) =3D> info.subject().as= _str(), > - Some(OpenIdUserAttribute::Username) =3D> { > - match info.preferred_username() { > - Some(name) =3D> name.as_str(), > - None =3D> bail!("missing claim 'preferred_name'"), > + let unique_name =3D match config.username_claim { > + None | Some(OpenIdUserAttribute::Subject) =3D> info.subject(= ).as_str(), > + Some(OpenIdUserAttribute::Username) =3D> { > + match info.preferred_username() { > + Some(name) =3D> name.as_str(), > + None =3D> bail!("missing claim 'preferred_name'"), > + } > } > - } > - Some(OpenIdUserAttribute::Email) =3D> { > - match info.email() { > - Some(name) =3D> name.as_str(), > - None =3D> bail!("missing claim 'email'"), > + Some(OpenIdUserAttribute::Email) =3D> { > + match info.email() { > + Some(name) =3D> name.as_str(), > + None =3D> bail!("missing claim 'email'"), > + } > } > - } > - }; > - > - let user_id =3D Userid::try_from(format!("{}@{}", unique_name, realm= ))?; > - > - if !user_info.is_active_user_id(&user_id) { > - if config.autocreate.unwrap_or(false) { > - use pbs_config::user; > - let _lock =3D open_backup_lockfile(user::USER_CFG_LOCKFILE, = None, true)?; > - let user =3D User { > - userid: user_id.clone(), > - comment: None, > - enable: None, > - expire: None, > - firstname: info.given_name().and_then(|n| n.get(None)).m= ap(|n| n.to_string()), > - lastname: info.family_name().and_then(|n| n.get(None)).m= ap(|n| n.to_string()), > - email: info.email().map(|e| e.to_string()), > - }; > - let (mut config, _digest) =3D user::config()?; > - if config.sections.get(user.userid.as_str()).is_some() { > - bail!("autocreate user failed - '{}' already exists.", u= ser.userid); > + }; > + > + > + let user_id =3D Userid::try_from(format!("{}@{}", unique_name, r= ealm))?; > + tested_username =3D Some(unique_name.to_string()); > + > + if !user_info.is_active_user_id(&user_id) { > + if config.autocreate.unwrap_or(false) { > + use pbs_config::user; > + let _lock =3D open_backup_lockfile(user::USER_CFG_LOCKFI= LE, None, true)?; > + let user =3D User { > + userid: user_id.clone(), > + comment: None, > + enable: None, > + expire: None, > + firstname: info.given_name().and_then(|n| n.get(None= )).map(|n| n.to_string()), > + lastname: info.family_name().and_then(|n| n.get(None= )).map(|n| n.to_string()), > + email: info.email().map(|e| e.to_string()), > + }; > + let (mut config, _digest) =3D user::config()?; > + if config.sections.get(user.userid.as_str()).is_some() { > + bail!("autocreate user failed - '{}' already exists.= ", user.userid); > + } > + config.set_data(user.userid.as_str(), "user", &user)?; > + user::save_config(&config)?; > + } else { > + bail!("user account '{}' missing, disabled or expired.",= user_id); > } > - config.set_data(user.userid.as_str(), "user", &user)?; > - user::save_config(&config)?; > - } else { > - bail!("user account '{}' missing, disabled or expired.", use= r_id); > } > - } > =20 > - let api_ticket =3D ApiTicket::full(user_id.clone()); > - let ticket =3D Ticket::new("PBS", &api_ticket)?.sign(private_auth_ke= y(), None)?; > - let token =3D assemble_csrf_prevention_token(csrf_secret(), &user_id= ); > + let api_ticket =3D ApiTicket::full(user_id.clone()); > + let ticket =3D Ticket::new("PBS", &api_ticket)?.sign(private_aut= h_key(), None)?; > + let token =3D assemble_csrf_prevention_token(csrf_secret(), &use= r_id); > + > + env.log_auth(user_id.as_str()); > =20 > - crate::server::rest::auth_logger()? > - .log(format!("successful auth for user '{}'", user_id)); > + Ok(json!({ > + "username": user_id, > + "ticket": ticket, > + "CSRFPreventionToken": token, > + })) > + }); > + > + if let Err(ref err) =3D result { > + let msg =3D err.to_string(); > + env.log_failed_auth(tested_username, &msg); > + return Err(http_err!(UNAUTHORIZED, "{}", msg)) > + } > =20 > - Ok(json!({ > - "username": user_id, > - "ticket": ticket, > - "CSRFPreventionToken": token, > - })) > + result > } > =20 > #[api( > diff --git a/src/bin/proxmox-backup-api.rs b/src/bin/proxmox-backup-api.r= s > index bb083b7d..f9f82ee8 100644 > --- a/src/bin/proxmox-backup-api.rs > +++ b/src/bin/proxmox-backup-api.rs > @@ -96,11 +96,19 @@ async fn run() -> Result<(), Error> { > =20 > config.enable_file_log( > pbs_buildcfg::API_ACCESS_LOG_FN, > + Some(dir_opts.clone()), > + Some(file_opts.clone()), > + &mut commando_sock, > + )?; > + > + config.enable_auth_log( > + pbs_buildcfg::API_AUTH_LOG_FN, > Some(dir_opts), > Some(file_opts), > &mut commando_sock, > )?; > =20 > + > let rest_server =3D RestServer::new(config); > =20 > // http server future: > diff --git a/src/bin/proxmox-backup-proxy.rs b/src/bin/proxmox-backup-pro= xy.rs > index 5e75ec72..f9277644 100644 > --- a/src/bin/proxmox-backup-proxy.rs > +++ b/src/bin/proxmox-backup-proxy.rs > @@ -196,6 +196,13 @@ async fn run() -> Result<(), Error> { > =20 > config.enable_file_log( > pbs_buildcfg::API_ACCESS_LOG_FN, > + Some(dir_opts.clone()), > + Some(file_opts.clone()), > + &mut commando_sock, > + )?; > + > + config.enable_auth_log( > + pbs_buildcfg::API_AUTH_LOG_FN, > Some(dir_opts), > Some(file_opts), > &mut commando_sock, > @@ -762,7 +769,7 @@ async fn schedule_task_log_rotate() { > =20 > if logrotate.rotate(max_size, None, Some(max_files))? { > println!("rotated access log, telling daemons to re-= open log file"); > - pbs_runtime::block_on(command_reopen_logfiles())?; > + pbs_runtime::block_on(command_reopen_access_logfiles= ())?; > worker.log("API access log was rotated".to_string())= ; > } else { > worker.log("API access log was not rotated".to_strin= g()); > @@ -772,6 +779,8 @@ async fn schedule_task_log_rotate() { > .ok_or_else(|| format_err!("could not get API au= th log file names"))?; > =20 > if logrotate.rotate(max_size, None, Some(max_files))? { > + println!("rotated auth log, telling daemons to re-op= en log file"); > + pbs_runtime::block_on(command_reopen_auth_logfiles()= )?; > worker.log("API authentication log was rotated".to_s= tring()); > } else { > worker.log("API authentication log was not rotated".= to_string()); > @@ -794,7 +803,7 @@ async fn schedule_task_log_rotate() { > =20 > } > =20 > -async fn command_reopen_logfiles() -> Result<(), Error> { > +async fn command_reopen_access_logfiles() -> Result<(), Error> { > // only care about the most recent daemon instance for each, proxy &= api, as other older ones > // should not respond to new requests anyway, but only finish their = current one and then exit. > let sock =3D crate::server::our_ctrl_sock(); > @@ -812,6 +821,24 @@ async fn command_reopen_logfiles() -> Result<(), Err= or> { > } > } > =20 > +async fn command_reopen_auth_logfiles() -> Result<(), Error> { this is command_reopen_access_logfiles, just with the command changed.. > + // only care about the most recent daemon instance for each, proxy &= api, as other older ones > + // should not respond to new requests anyway, but only finish their = current one and then exit. > + let sock =3D crate::server::our_ctrl_sock(); > + let f1 =3D pbs_server::send_command(sock, "{\"command\":\"api-auth-l= og-reopen\"}\n"); > + > + let pid =3D crate::server::read_pid(pbs_buildcfg::PROXMOX_BACKUP_API= _PID_FN)?; > + let sock =3D crate::server::ctrl_sock_from_pid(pid); > + let f2 =3D pbs_server::send_command(sock, "{\"command\":\"api-auth-l= og-reopen\"}\n"); > + > + match futures::join!(f1, f2) { > + (Err(e1), Err(e2)) =3D> Err(format_err!("reopen commands failed,= proxy: {}; api: {}", e1, e2)), > + (Err(e1), Ok(_)) =3D> Err(format_err!("reopen commands failed, p= roxy: {}", e1)), > + (Ok(_), Err(e2)) =3D> Err(format_err!("reopen commands failed, a= pi: {}", e2)), > + _ =3D> Ok(()), > + } > +} > + > async fn run_stat_generator() { > =20 > let mut count =3D 0; > diff --git a/src/server/rest.rs b/src/server/rest.rs > index f0187a67..0f367a48 100644 > --- a/src/server/rest.rs > +++ b/src/server/rest.rs > @@ -29,12 +29,11 @@ use proxmox::api::{ > RpcEnvironmentType, UserInformation, > }; > use proxmox::http_err; > -use proxmox::tools::fs::CreateOptions; > =20 > use pbs_tools::compression::{DeflateEncoder, Level}; > use pbs_tools::stream::AsyncReaderStream; > use pbs_server::{ > - ApiConfig, FileLogger, FileLogOptions, AuthError, RestEnvironment, C= ompressionMethod, > + ApiConfig, FileLogger, AuthError, RestEnvironment, CompressionMethod= , > extract_cookie, normalize_uri_path, > }; > use pbs_server::formatter::*; > @@ -200,22 +199,6 @@ fn log_response( > } > } > =20 > -pub fn auth_logger() -> Result { > - let backup_user =3D pbs_config::backup_user()?; > - > - let file_opts =3D CreateOptions::new() > - .owner(backup_user.uid) > - .group(backup_user.gid); > - > - let logger_options =3D FileLogOptions { > - append: true, > - prefix_time: true, > - file_opts, > - ..Default::default() > - }; > - FileLogger::new(pbs_buildcfg::API_AUTH_LOG_FN, logger_options) > -} > - > fn get_proxied_peer(headers: &HeaderMap) -> Option= { > lazy_static! { > static ref RE: Regex =3D Regex::new(r#"for=3D"([^"]+)""#).unwrap= (); > @@ -272,7 +255,7 @@ impl tower_service::Service> for ApiSer= vice { > .body(err.into())? > } > }; > - let logger =3D config.get_file_log(); > + let logger =3D config.get_access_log(); > log_response(logger, &peer, method, &path, &response, user_a= gent); > Ok(response) > } > @@ -631,7 +614,7 @@ async fn handle_request( > } > =20 > let env_type =3D api.env_type(); > - let mut rpcenv =3D RestEnvironment::new(env_type); > + let mut rpcenv =3D RestEnvironment::new(env_type, Arc::clone(&api)); > =20 > rpcenv.set_client_ip(Some(*peer)); > =20 > @@ -675,11 +658,8 @@ async fn handle_request( > format_err!("no authentication credentia= ls provided.") > } > }; > - let peer =3D peer.ip(); > - auth_logger()?.log(format!( > - "authentication failure; rhost=3D{} msg=3D{}= ", > - peer, err > - )); > + // fixme: log Username?? > + rpcenv.log_failed_auth(None, &err.to_string()); > =20 > // always delay unauthorized calls by 3 seconds = (from start of request) > let err =3D http_err!(UNAUTHORIZED, "authenticat= ion failed - {}", err); > --=20 > 2.30.2 >=20 >=20 >=20 > _______________________________________________ > pbs-devel mailing list > pbs-devel@lists.proxmox.com > https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel >=20 >=20 >=20