start impl. access permissions
This commit is contained in:
		@ -2,7 +2,7 @@ use failure::*;
 | 
			
		||||
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
 | 
			
		||||
use proxmox::api::{api, RpcEnvironment};
 | 
			
		||||
use proxmox::api::{api, RpcEnvironment, Permission};
 | 
			
		||||
use proxmox::api::router::{Router, SubdirMap};
 | 
			
		||||
use proxmox::{sortable, identity};
 | 
			
		||||
use proxmox::{http_err, list_subdirs_api_method};
 | 
			
		||||
@ -11,6 +11,7 @@ use crate::tools;
 | 
			
		||||
use crate::tools::ticket::*;
 | 
			
		||||
use crate::auth_helpers::*;
 | 
			
		||||
use crate::api2::types::*;
 | 
			
		||||
use crate::config::cached_user_info::CachedUserInfo;
 | 
			
		||||
 | 
			
		||||
pub mod user;
 | 
			
		||||
pub mod domain;
 | 
			
		||||
@ -18,6 +19,12 @@ pub mod acl;
 | 
			
		||||
 | 
			
		||||
fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
 | 
			
		||||
 | 
			
		||||
    let user_info = CachedUserInfo::new()?;
 | 
			
		||||
 | 
			
		||||
    if !user_info.is_active_user(&username) {
 | 
			
		||||
        bail!("user account disabled or expired.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let ticket_lifetime = tools::ticket::TICKET_LIFETIME;
 | 
			
		||||
 | 
			
		||||
    if password.starts_with("PBS:") {
 | 
			
		||||
@ -61,6 +68,9 @@ fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    protected: true,
 | 
			
		||||
    access: {
 | 
			
		||||
        permission: &Permission::World,
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Create or verify authentication ticket.
 | 
			
		||||
///
 | 
			
		||||
@ -100,6 +110,11 @@ fn create_ticket(username: String, password: String) -> Result<Value, Error> {
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    access: {
 | 
			
		||||
        description: "Anybody is allowed to change there own password. The Superuser may change any password.",
 | 
			
		||||
        permission: &Permission::Anybody,
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
)]
 | 
			
		||||
/// Change user password
 | 
			
		||||
///
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,7 @@ use failure::*;
 | 
			
		||||
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
 | 
			
		||||
use proxmox::api::api;
 | 
			
		||||
use proxmox::api::{api, Permission};
 | 
			
		||||
use proxmox::api::router::Router;
 | 
			
		||||
 | 
			
		||||
use crate::api2::types::*;
 | 
			
		||||
@ -29,12 +29,13 @@ use crate::api2::types::*;
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    access: {
 | 
			
		||||
        description: "Anyone can access this, because we need that list for the login box (before the user is authenticated).",
 | 
			
		||||
        permission: &Permission::World,
 | 
			
		||||
    }
 | 
			
		||||
)]
 | 
			
		||||
/// Authentication domain/realm index.
 | 
			
		||||
///
 | 
			
		||||
/// Anyone can access this, because we need that list for the login
 | 
			
		||||
/// box (before the user is authenticated).
 | 
			
		||||
fn list_domains() -> Result<Value, Error> {
 | 
			
		||||
    let mut list = Vec::new();
 | 
			
		||||
    list.push(json!({ "realm": "pam", "comment": "Linux PAM standard authentication", "default": true }));
 | 
			
		||||
 | 
			
		||||
@ -6,11 +6,12 @@ use openssl::sha;
 | 
			
		||||
use regex::Regex;
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
 | 
			
		||||
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment};
 | 
			
		||||
use proxmox::api::{api, ApiMethod, Router, RpcEnvironment, Permission};
 | 
			
		||||
use proxmox::tools::fs::{file_get_contents, replace_file, CreateOptions};
 | 
			
		||||
use proxmox::{IPRE, IPV4RE, IPV6RE, IPV4OCTET, IPV6H16, IPV6LS32};
 | 
			
		||||
 | 
			
		||||
use crate::api2::types::*;
 | 
			
		||||
use crate::config::acl::{PRIV_SYS_AUDIT, PRIV_SYS_MODIFY};
 | 
			
		||||
 | 
			
		||||
static RESOLV_CONF_FN: &str = "/etc/resolv.conf";
 | 
			
		||||
 | 
			
		||||
@ -77,6 +78,9 @@ pub fn read_etc_resolv_conf() -> Result<Value, Error> {
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    access: {
 | 
			
		||||
        permission: &Permission::Privilege(&[], PRIV_SYS_MODIFY, false),
 | 
			
		||||
    }
 | 
			
		||||
)]
 | 
			
		||||
/// Update DNS settings
 | 
			
		||||
fn update_dns(
 | 
			
		||||
@ -158,6 +162,9 @@ fn update_dns(
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    access: {
 | 
			
		||||
        permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
 | 
			
		||||
    }
 | 
			
		||||
)]
 | 
			
		||||
/// Read DNS settings.
 | 
			
		||||
fn get_dns(
 | 
			
		||||
 | 
			
		||||
@ -1,28 +1,37 @@
 | 
			
		||||
use failure::*;
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
 | 
			
		||||
use proxmox::api::{ApiHandler, ApiMethod, Router, RpcEnvironment};
 | 
			
		||||
use proxmox::api::schema::ObjectSchema;
 | 
			
		||||
use proxmox::api::{api, Router, Permission};
 | 
			
		||||
 | 
			
		||||
use crate::api2::types::*;
 | 
			
		||||
use crate::config::acl::{PRIV_SYS_AUDIT};
 | 
			
		||||
 | 
			
		||||
#[api(
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {
 | 
			
		||||
            node: {
 | 
			
		||||
                schema: NODE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    returns: {
 | 
			
		||||
        description: "The network configuration from /etc/network/interfaces.",
 | 
			
		||||
        properties: {
 | 
			
		||||
            // fixme
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    access: {
 | 
			
		||||
        permission: &Permission::Privilege(&[], PRIV_SYS_AUDIT, false),
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Read network configuration.
 | 
			
		||||
fn get_network_config(
 | 
			
		||||
    _param: Value,
 | 
			
		||||
    _info: &ApiMethod,
 | 
			
		||||
    _rpcenv: &mut dyn RpcEnvironment,
 | 
			
		||||
) -> Result<Value, Error> {
 | 
			
		||||
 | 
			
		||||
    Ok(json!({}))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub const ROUTER: Router = Router::new()
 | 
			
		||||
    .get(
 | 
			
		||||
        &ApiMethod::new(
 | 
			
		||||
            &ApiHandler::Sync(&get_network_config),
 | 
			
		||||
            &ObjectSchema::new(
 | 
			
		||||
                "Read network configuration.",
 | 
			
		||||
                &[ ("node", false, &NODE_SCHEMA) ],
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    );
 | 
			
		||||
    .get(&API_METHOD_GET_NETWORK_CONFIG);
 | 
			
		||||
  
 | 
			
		||||
 | 
			
		||||
@ -4,9 +4,7 @@ use chrono::prelude::*;
 | 
			
		||||
use failure::*;
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
 | 
			
		||||
use proxmox::{sortable, identity};
 | 
			
		||||
use proxmox::api::{ApiHandler, ApiMethod, Router, RpcEnvironment};
 | 
			
		||||
use proxmox::api::schema::*;
 | 
			
		||||
use proxmox::api::{api, Router, Permission};
 | 
			
		||||
use proxmox::tools::fs::{file_read_firstline, replace_file, CreateOptions};
 | 
			
		||||
 | 
			
		||||
use crate::api2::types::*;
 | 
			
		||||
@ -41,11 +39,38 @@ fn read_etc_localtime() -> Result<String, Error> {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_time(
 | 
			
		||||
    _param: Value,
 | 
			
		||||
    _info: &ApiMethod,
 | 
			
		||||
    _rpcenv: &mut dyn RpcEnvironment,
 | 
			
		||||
) -> Result<Value, Error> {
 | 
			
		||||
#[api(
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {
 | 
			
		||||
            node: {
 | 
			
		||||
                schema: NODE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
    returns: {
 | 
			
		||||
        description: "Returns server time and timezone.",
 | 
			
		||||
        properties: {
 | 
			
		||||
            timezone: {
 | 
			
		||||
                schema: TIME_ZONE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
            time: {
 | 
			
		||||
                type: i64,
 | 
			
		||||
                description: "Seconds since 1970-01-01 00:00:00 UTC.",
 | 
			
		||||
                minimum: 1_297_163_644,
 | 
			
		||||
            },
 | 
			
		||||
            localtime: {
 | 
			
		||||
                type: i64,
 | 
			
		||||
                description: "Seconds since 1970-01-01 00:00:00 UTC. (local time)",
 | 
			
		||||
                minimum: 1_297_163_644,
 | 
			
		||||
            },
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    access: {
 | 
			
		||||
        permission: &Permission::Anybody,
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Read server time and time zone settings.
 | 
			
		||||
fn get_time(_param: Value) -> Result<Value, Error> {
 | 
			
		||||
    let datetime = Local::now();
 | 
			
		||||
    let offset = datetime.offset();
 | 
			
		||||
    let time = datetime.timestamp();
 | 
			
		||||
@ -58,13 +83,25 @@ fn get_time(
 | 
			
		||||
    }))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[api(
 | 
			
		||||
    protected: true,
 | 
			
		||||
    reload_timezone: true,
 | 
			
		||||
    input: {
 | 
			
		||||
        properties: {
 | 
			
		||||
            node: {
 | 
			
		||||
                schema: NODE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
            timezone: {
 | 
			
		||||
                schema: TIME_ZONE_SCHEMA,
 | 
			
		||||
            },
 | 
			
		||||
        },
 | 
			
		||||
    },
 | 
			
		||||
)]
 | 
			
		||||
/// Set time zone
 | 
			
		||||
fn set_timezone(
 | 
			
		||||
    param: Value,
 | 
			
		||||
    _info: &ApiMethod,
 | 
			
		||||
    _rpcenv: &mut dyn RpcEnvironment,
 | 
			
		||||
    timezone: String,
 | 
			
		||||
    _param: Value,
 | 
			
		||||
) -> Result<Value, Error> {
 | 
			
		||||
    let timezone = crate::tools::required_string_param(¶m, "timezone")?;
 | 
			
		||||
 | 
			
		||||
    let path = std::path::PathBuf::from(format!("/usr/share/zoneinfo/{}", timezone));
 | 
			
		||||
 | 
			
		||||
    if !path.exists() {
 | 
			
		||||
@ -81,45 +118,6 @@ fn set_timezone(
 | 
			
		||||
    Ok(Value::Null)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[sortable]
 | 
			
		||||
pub const ROUTER: Router = Router::new()
 | 
			
		||||
    .get(
 | 
			
		||||
        &ApiMethod::new(
 | 
			
		||||
            &ApiHandler::Sync(&get_time),
 | 
			
		||||
            &ObjectSchema::new(
 | 
			
		||||
                "Read server time and time zone settings.",
 | 
			
		||||
                &sorted!([ ("node", false, &NODE_SCHEMA) ]),
 | 
			
		||||
            )
 | 
			
		||||
        ).returns(
 | 
			
		||||
            &ObjectSchema::new(
 | 
			
		||||
                "Returns server time and timezone.",
 | 
			
		||||
                &sorted!([
 | 
			
		||||
                    ("timezone", false, &StringSchema::new("Time zone").schema()),
 | 
			
		||||
                    ("time", false, &IntegerSchema::new("Seconds since 1970-01-01 00:00:00 UTC.")
 | 
			
		||||
                     .minimum(1_297_163_644)
 | 
			
		||||
                     .schema()
 | 
			
		||||
                    ),
 | 
			
		||||
                    ("localtime", false, &IntegerSchema::new("Seconds since 1970-01-01 00:00:00 UTC. (local time)")
 | 
			
		||||
                     .minimum(1_297_163_644)
 | 
			
		||||
                     .schema()
 | 
			
		||||
                    ),
 | 
			
		||||
                ]),
 | 
			
		||||
            ).schema()
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
    .put(
 | 
			
		||||
        &ApiMethod::new(
 | 
			
		||||
            &ApiHandler::Sync(&set_timezone),
 | 
			
		||||
            &ObjectSchema::new(
 | 
			
		||||
                "Set time zone.",
 | 
			
		||||
                &sorted!([
 | 
			
		||||
                    ("node", false, &NODE_SCHEMA),
 | 
			
		||||
                    ("timezone", false, &StringSchema::new(
 | 
			
		||||
                        "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
 | 
			
		||||
                     .schema()
 | 
			
		||||
                    ),
 | 
			
		||||
                ]),
 | 
			
		||||
            )
 | 
			
		||||
        ).protected(true).reload_timezone(true)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    .get(&API_METHOD_GET_TIME)
 | 
			
		||||
    .put(&API_METHOD_SET_TIMEZONE);
 | 
			
		||||
 | 
			
		||||
@ -164,6 +164,13 @@ pub const THIRD_DNS_SERVER_SCHEMA: Schema =
 | 
			
		||||
    .format(&IP_FORMAT)
 | 
			
		||||
    .schema();
 | 
			
		||||
 | 
			
		||||
pub const TIME_ZONE_SCHEMA: Schema = StringSchema::new(
 | 
			
		||||
    "Time zone. The file '/usr/share/zoneinfo/zone.tab' contains the list of valid names.")
 | 
			
		||||
    .format(&SINGLE_LINE_COMMENT_FORMAT)
 | 
			
		||||
    .min_length(2)
 | 
			
		||||
    .max_length(64)
 | 
			
		||||
    .schema();
 | 
			
		||||
 | 
			
		||||
pub const BACKUP_ARCHIVE_NAME_SCHEMA: Schema =
 | 
			
		||||
    StringSchema::new("Backup archive name.")
 | 
			
		||||
    .format(&PROXMOX_SAFE_ID_FORMAT)
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
use failure::*;
 | 
			
		||||
use serde_json::{json, Value};
 | 
			
		||||
 | 
			
		||||
use proxmox::api::{ApiHandler, ApiMethod, Router, RpcEnvironment};
 | 
			
		||||
use proxmox::api::{ApiHandler, ApiMethod, Router, RpcEnvironment, Permission};
 | 
			
		||||
use proxmox::api::schema::ObjectSchema;
 | 
			
		||||
 | 
			
		||||
pub const PROXMOX_PKG_VERSION: &str =
 | 
			
		||||
@ -31,6 +31,6 @@ pub const ROUTER: Router = Router::new()
 | 
			
		||||
        &ApiMethod::new(
 | 
			
		||||
            &ApiHandler::Sync(&get_version),
 | 
			
		||||
            &ObjectSchema::new("Proxmox Backup Server API version.", &[])
 | 
			
		||||
        )
 | 
			
		||||
        ).access(None, &Permission::Anybody)
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										21
									
								
								src/auth.rs
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								src/auth.rs
									
									
									
									
									
								
							@ -130,6 +130,7 @@ pub fn parse_userid(userid: &str) -> Result<(String, String), Error> {
 | 
			
		||||
    Ok((data[1].to_owned(), data[0].to_owned()))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Lookup the autenticator for the specified realm
 | 
			
		||||
pub fn lookup_authenticator(realm: &str) -> Result<Box<dyn ProxmoxAuthenticator>, Error> {
 | 
			
		||||
    match realm {
 | 
			
		||||
        "pam" => Ok(Box::new(PAM())),
 | 
			
		||||
@ -138,28 +139,10 @@ pub fn lookup_authenticator(realm: &str) -> Result<Box<dyn ProxmoxAuthenticator>
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Authenticate users
 | 
			
		||||
pub fn authenticate_user(userid: &str, password: &str) -> Result<(), Error> {
 | 
			
		||||
    let (username, realm) = parse_userid(userid)?;
 | 
			
		||||
 | 
			
		||||
    let (user_config, _digest) = crate::config::user::config()?;
 | 
			
		||||
    let user: Result<crate::config::user::User, Error> = user_config.lookup("user", userid);
 | 
			
		||||
    match user {
 | 
			
		||||
        Ok(user) => {
 | 
			
		||||
            if let Some(false) = user.enable {
 | 
			
		||||
                bail!("account disabled");
 | 
			
		||||
            }
 | 
			
		||||
            if let Some(expire) = user.expire {
 | 
			
		||||
                if expire > 0 {
 | 
			
		||||
                    let now = unsafe { libc::time(std::ptr::null_mut()) };
 | 
			
		||||
                    if expire <= now {
 | 
			
		||||
                        bail!("account expired");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        },
 | 
			
		||||
        Err(_) => bail!("no such user"),
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lookup_authenticator(&realm)?
 | 
			
		||||
    .authenticate_user(&username, password)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ use url::form_urlencoded;
 | 
			
		||||
 | 
			
		||||
use proxmox::http_err;
 | 
			
		||||
use proxmox::api::{ApiHandler, ApiMethod, HttpError};
 | 
			
		||||
use proxmox::api::{RpcEnvironment, RpcEnvironmentType};
 | 
			
		||||
use proxmox::api::{RpcEnvironment, RpcEnvironmentType, check_api_permission};
 | 
			
		||||
use proxmox::api::schema::{ObjectSchema, parse_simple_value, verify_json_object, parse_parameter_strings};
 | 
			
		||||
 | 
			
		||||
use super::environment::RestEnvironment;
 | 
			
		||||
@ -28,6 +28,7 @@ use super::ApiConfig;
 | 
			
		||||
 | 
			
		||||
use crate::auth_helpers::*;
 | 
			
		||||
use crate::tools;
 | 
			
		||||
use crate::config::cached_user_info::CachedUserInfo;
 | 
			
		||||
 | 
			
		||||
extern "C"  { fn tzset(); }
 | 
			
		||||
 | 
			
		||||
@ -468,7 +469,12 @@ fn extract_auth_data(headers: &http::HeaderMap) -> (Option<String>, Option<Strin
 | 
			
		||||
    (ticket, token)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn check_auth(method: &hyper::Method, ticket: &Option<String>, token: &Option<String>) -> Result<String, Error> {
 | 
			
		||||
fn check_auth(
 | 
			
		||||
    method: &hyper::Method,
 | 
			
		||||
    ticket: &Option<String>,
 | 
			
		||||
    token: &Option<String>,
 | 
			
		||||
    user_info: &CachedUserInfo,
 | 
			
		||||
) -> Result<String, Error> {
 | 
			
		||||
 | 
			
		||||
    let ticket_lifetime = tools::ticket::TICKET_LIFETIME;
 | 
			
		||||
 | 
			
		||||
@ -481,6 +487,10 @@ fn check_auth(method: &hyper::Method, ticket: &Option<String>, token: &Option<St
 | 
			
		||||
        None => bail!("missing ticket"),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if !user_info.is_active_user(&username) {
 | 
			
		||||
        bail!("user account disabled or expired.");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if method != hyper::Method::GET {
 | 
			
		||||
        if let Some(token) = token {
 | 
			
		||||
            println!("CSRF prevention token: {:?}", token);
 | 
			
		||||
@ -508,6 +518,8 @@ pub async fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> Result<R
 | 
			
		||||
    let env_type = api.env_type();
 | 
			
		||||
    let mut rpcenv = RestEnvironment::new(env_type);
 | 
			
		||||
 | 
			
		||||
    let user_info = CachedUserInfo::new()?;
 | 
			
		||||
 | 
			
		||||
    let delay_unauth_time = std::time::Instant::now() + std::time::Duration::from_millis(3000);
 | 
			
		||||
 | 
			
		||||
    if comp_len >= 1 && components[0] == "api2" {
 | 
			
		||||
@ -531,16 +543,11 @@ pub async fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> Result<R
 | 
			
		||||
                // explicitly allow those calls without auth
 | 
			
		||||
            } else {
 | 
			
		||||
                let (ticket, token) = extract_auth_data(&parts.headers);
 | 
			
		||||
                match check_auth(&method, &ticket, &token) {
 | 
			
		||||
                    Ok(username) => {
 | 
			
		||||
 | 
			
		||||
                        // fixme: check permissions
 | 
			
		||||
 | 
			
		||||
                        rpcenv.set_user(Some(username));
 | 
			
		||||
                    }
 | 
			
		||||
                match check_auth(&method, &ticket, &token, &user_info) {
 | 
			
		||||
                    Ok(username) => rpcenv.set_user(Some(username)),
 | 
			
		||||
                    Err(err) => {
 | 
			
		||||
                        // always delay unauthorized calls by 3 seconds (from start of request)
 | 
			
		||||
                        let err = http_err!(UNAUTHORIZED, format!("permission check failed - {}", err));
 | 
			
		||||
                        let err = http_err!(UNAUTHORIZED, format!("authentication failed - {}", err));
 | 
			
		||||
                        tokio::time::delay_until(Instant::from_std(delay_unauth_time)).await;
 | 
			
		||||
                        return Ok((formatter.format_error)(err));
 | 
			
		||||
                    }
 | 
			
		||||
@ -553,6 +560,13 @@ pub async fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> Result<R
 | 
			
		||||
                    return Ok((formatter.format_error)(err));
 | 
			
		||||
                }
 | 
			
		||||
                Some(api_method) => {
 | 
			
		||||
                    let user = rpcenv.get_user();
 | 
			
		||||
                    if !check_api_permission(api_method.access.permission, user.as_deref(), &uri_param, &user_info) {
 | 
			
		||||
                        let err = http_err!(FORBIDDEN, format!("permission check failed"));
 | 
			
		||||
                        tokio::time::delay_until(Instant::from_std(delay_unauth_time)).await;
 | 
			
		||||
                        return Ok((formatter.format_error)(err));
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    let result = if api_method.protected && env_type == RpcEnvironmentType::PUBLIC {
 | 
			
		||||
                        proxy_protected_request(api_method, parts, body).await
 | 
			
		||||
                    } else {
 | 
			
		||||
@ -577,7 +591,7 @@ pub async fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> Result<R
 | 
			
		||||
        if comp_len == 0 {
 | 
			
		||||
            let (ticket, token) = extract_auth_data(&parts.headers);
 | 
			
		||||
            if ticket != None {
 | 
			
		||||
                match check_auth(&method, &ticket, &token) {
 | 
			
		||||
                match check_auth(&method, &ticket, &token, &user_info) {
 | 
			
		||||
                    Ok(username) => {
 | 
			
		||||
                        let new_token = assemble_csrf_prevention_token(csrf_secret(), &username);
 | 
			
		||||
                        return Ok(get_index(Some(username), Some(new_token)));
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user