diff --git a/proxmox-rest-server/examples/minimal-rest-server.rs b/proxmox-rest-server/examples/minimal-rest-server.rs index b1ef9335..6400fdbf 100644 --- a/proxmox-rest-server/examples/minimal-rest-server.rs +++ b/proxmox-rest-server/examples/minimal-rest-server.rs @@ -1,20 +1,24 @@ -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use std::collections::HashMap; use std::future::Future; use std::pin::Pin; use anyhow::{bail, format_err, Error}; use lazy_static::lazy_static; +use hyper::{Body, Response, Method}; +use http::request::Parts; +use http::HeaderMap; use proxmox::api::{api, router::SubdirMap, Router, RpcEnvironmentType, UserInformation}; use proxmox::list_subdirs_api_method; -use proxmox_rest_server::{ApiAuth, ApiConfig, AuthError, RestServer, RestEnvironment}; -// Create a Dummy User info and auth system -// Normally this would check and authenticate the user +use proxmox_rest_server::{ServerAdapter, ApiConfig, AuthError, RestServer, RestEnvironment}; + +// Create a Dummy User information system struct DummyUserInfo; impl UserInformation for DummyUserInfo { fn is_superuser(&self, _userid: &str) -> bool { + // Always return true here, so we have access to everthing true } fn is_group_member(&self, _userid: &str, group: &str) -> bool { @@ -25,14 +29,17 @@ impl UserInformation for DummyUserInfo { } } -struct DummyAuth; +struct MinimalServer; -impl ApiAuth for DummyAuth { - fn check_auth<'a>( - &'a self, - _headers: &'a http::HeaderMap, - _method: &'a hyper::Method, - ) -> Pin), AuthError>> + Send + 'a>> { +// implement the server adapter +impl ServerAdapter for MinimalServer { + + // normally this would check and authenticate the user + fn check_auth( + &self, + _headers: &HeaderMap, + _method: &Method, + ) -> Pin), AuthError>> + Send>> { Box::pin(async move { // get some global/cached userinfo let userinfo: Box = Box::new(DummyUserInfo); @@ -40,21 +47,21 @@ impl ApiAuth for DummyAuth { Ok(("User".to_string(), userinfo)) }) } -} -// this should return the index page of the webserver -// iow. what the user browses to - -fn get_index<'a>( - _env: RestEnvironment, - _parts: http::request::Parts, -) -> Pin> + Send + 'a>> { - Box::pin(async move { - // build an index page - http::Response::builder() - .body("hello world".into()) - .unwrap() - }) + // this should return the index page of the webserver + // iow. what the user browses to + fn get_index( + &self, + _env: RestEnvironment, + _parts: Parts, + ) -> Pin> + Send>> { + Box::pin(async move { + // build an index page + http::Response::builder() + .body("hello world".into()) + .unwrap() + }) + } } // a few examples on how to do api calls with the Router @@ -190,8 +197,7 @@ async fn run() -> Result<(), Error> { "/var/tmp/", &ROUTER, RpcEnvironmentType::PUBLIC, - Arc::new(DummyAuth {}), - &get_index, + MinimalServer, )?; let rest_server = RestServer::new(config); diff --git a/proxmox-rest-server/src/api_config.rs b/proxmox-rest-server/src/api_config.rs index c7c71ec0..99990114 100644 --- a/proxmox-rest-server/src/api_config.rs +++ b/proxmox-rest-server/src/api_config.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use std::time::SystemTime; use std::fs::metadata; use std::sync::{Arc, Mutex, RwLock}; -use std::future::Future; use std::pin::Pin; use anyhow::{bail, Error, format_err}; @@ -16,9 +15,8 @@ use serde::Serialize; use proxmox::api::{ApiMethod, Router, RpcEnvironmentType, UserInformation}; use proxmox::tools::fs::{create_path, CreateOptions}; -use crate::{ApiAuth, AuthError, FileLogger, FileLogOptions, CommandSocket, RestEnvironment}; +use crate::{ServerAdapter, AuthError, FileLogger, FileLogOptions, CommandSocket, RestEnvironment}; -pub type GetIndexFn = &'static (dyn Fn(RestEnvironment, Parts) -> Pin> + Send>> + Send + Sync); /// REST server configuration pub struct ApiConfig { @@ -30,8 +28,7 @@ pub struct ApiConfig { template_files: RwLock>, request_log: Option>>, auth_log: Option>>, - api_auth: Arc, - get_index_fn: GetIndexFn, + adapter: Pin>, } impl ApiConfig { @@ -53,8 +50,7 @@ impl ApiConfig { basedir: B, router: &'static Router, env_type: RpcEnvironmentType, - api_auth: Arc, - get_index_fn: GetIndexFn, + adapter: impl ServerAdapter + 'static, ) -> Result { Ok(Self { basedir: basedir.into(), @@ -65,8 +61,7 @@ impl ApiConfig { template_files: RwLock::new(HashMap::new()), request_log: None, auth_log: None, - api_auth, - get_index_fn, + adapter: Box::pin(adapter), }) } @@ -75,7 +70,7 @@ impl ApiConfig { rest_env: RestEnvironment, parts: Parts, ) -> Response { - (self.get_index_fn)(rest_env, parts).await + self.adapter.get_index(rest_env, parts).await } pub(crate) async fn check_auth( @@ -83,7 +78,7 @@ impl ApiConfig { headers: &http::HeaderMap, method: &hyper::Method, ) -> Result<(String, Box), AuthError> { - self.api_auth.check_auth(headers, method).await + self.adapter.check_auth(headers, method).await } pub(crate) fn find_method( diff --git a/proxmox-rest-server/src/lib.rs b/proxmox-rest-server/src/lib.rs index bb29295c..d72936c2 100644 --- a/proxmox-rest-server/src/lib.rs +++ b/proxmox-rest-server/src/lib.rs @@ -21,6 +21,9 @@ use std::pin::Pin; use anyhow::{bail, format_err, Error}; use nix::unistd::Pid; +use hyper::{Body, Response, Method}; +use http::request::Parts; +use http::HeaderMap; use proxmox::tools::fd::Fd; use proxmox::sys::linux::procfs::PidStat; @@ -70,17 +73,26 @@ impl From for AuthError { } } -/// User Authentication trait -pub trait ApiAuth { +/// User Authentication and index/root page generation methods +pub trait ServerAdapter: Send + Sync { + + /// Returns the index/root page + fn get_index( + &self, + rest_env: RestEnvironment, + parts: Parts, + ) -> Pin> + Send>>; + /// Extract user credentials from headers and check them. /// /// If credenthials are valid, returns the username and a /// [UserInformation] object to query additional user data. fn check_auth<'a>( &'a self, - headers: &'a http::HeaderMap, - method: &'a hyper::Method, + headers: &'a HeaderMap, + method: &'a Method, ) -> Pin), AuthError>> + Send + 'a>>; + } lazy_static::lazy_static!{