api: move config/user to access/users, implement change_password

To make it similar to the pve api
This commit is contained in:
Dietmar Maurer 2020-04-09 10:19:38 +02:00
parent 7d817b0358
commit 685e13347e
6 changed files with 69 additions and 15 deletions

View File

@ -1,4 +1,4 @@
mod access; pub mod access;
pub mod admin; pub mod admin;
pub mod backup; pub mod backup;
pub mod config; pub mod config;

View File

@ -2,7 +2,7 @@ use failure::*;
use serde_json::{json, Value}; use serde_json::{json, Value};
use proxmox::api::api; use proxmox::api::{api, RpcEnvironment};
use proxmox::api::router::{Router, SubdirMap}; use proxmox::api::router::{Router, SubdirMap};
use proxmox::sortable; use proxmox::sortable;
use proxmox::{http_err, list_subdirs_api_method}; use proxmox::{http_err, list_subdirs_api_method};
@ -10,6 +10,9 @@ use proxmox::{http_err, list_subdirs_api_method};
use crate::tools; use crate::tools;
use crate::tools::ticket::*; use crate::tools::ticket::*;
use crate::auth_helpers::*; use crate::auth_helpers::*;
use crate::api2::types::*;
pub mod user;
fn authenticate_user(username: &str, password: &str) -> Result<(), Error> { fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
@ -32,13 +35,10 @@ fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
input: { input: {
properties: { properties: {
username: { username: {
type: String, schema: PROXMOX_USER_ID_SCHEMA,
description: "User name.",
max_length: 64,
}, },
password: { password: {
type: String, schema: PASSWORD_SCHEMA,
description: "The secret password. This can also be a valid ticket.",
}, },
}, },
}, },
@ -87,12 +87,57 @@ fn create_ticket(username: String, password: String) -> Result<Value, Error> {
} }
} }
#[api(
input: {
properties: {
userid: {
schema: PROXMOX_USER_ID_SCHEMA,
},
password: {
schema: PASSWORD_SCHEMA,
},
},
},
)]
/// Change user password
///
/// Each user is allowed to change his own password. Superuser
/// can change all passwords.
fn change_password(
userid: String,
password: String,
rpcenv: &mut dyn RpcEnvironment,
) -> Result<Value, Error> {
let current_user = rpcenv.get_user()
.ok_or_else(|| format_err!("unknown user"))?;
let mut allowed = userid == current_user;
if userid == "root@pam" { allowed = true; }
if !allowed {
bail!("you are not authorized to change the password.");
}
let (username, realm) = crate::auth::parse_userid(&userid)?;
let authenticator = crate::auth::lookup_authenticator(&realm)?;
authenticator.store_password(&username, &password)?;
Ok(Value::Null)
}
#[sortable] #[sortable]
const SUBDIRS: SubdirMap = &[ const SUBDIRS: SubdirMap = &[
(
"password", &Router::new()
.put(&API_METHOD_CHANGE_PASSWORD)
),
( (
"ticket", &Router::new() "ticket", &Router::new()
.post(&API_METHOD_CREATE_TICKET) .post(&API_METHOD_CREATE_TICKET)
) ),
("users", &user::ROUTER),
]; ];
pub const ROUTER: Router = Router::new() pub const ROUTER: Router = Router::new()

View File

@ -140,7 +140,7 @@ pub fn create_user(userid: String, password: Option<String>, param: Value) -> Re
userid: { userid: {
schema: PROXMOX_USER_ID_SCHEMA, schema: PROXMOX_USER_ID_SCHEMA,
}, },
}, },
}, },
returns: { returns: {
description: "The user configuration (with config digest).", description: "The user configuration (with config digest).",

View File

@ -3,12 +3,10 @@ use proxmox::list_subdirs_api_method;
pub mod datastore; pub mod datastore;
pub mod remote; pub mod remote;
pub mod user;
const SUBDIRS: SubdirMap = &[ const SUBDIRS: SubdirMap = &[
("datastore", &datastore::ROUTER), ("datastore", &datastore::ROUTER),
("remote", &remote::ROUTER), ("remote", &remote::ROUTER),
("user", &user::ROUTER),
]; ];
pub const ROUTER: Router = Router::new() pub const ROUTER: Router = Router::new()

View File

@ -91,6 +91,17 @@ pub const PASSWORD_FORMAT: ApiStringFormat =
ApiStringFormat::Pattern(&PASSWORD_REGEX); ApiStringFormat::Pattern(&PASSWORD_REGEX);
pub const PASSWORD_SCHEMA: Schema = StringSchema::new("Password.")
.format(&PASSWORD_FORMAT)
.min_length(1)
.max_length(64)
.schema();
pub const PBS_PASSWORD_SCHEMA: Schema = StringSchema::new("User Password.")
.format(&PASSWORD_FORMAT)
.min_length(5)
.max_length(64)
.schema();
pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema = StringSchema::new( pub const CERT_FINGERPRINT_SHA256_SCHEMA: Schema = StringSchema::new(
"X509 certificate fingerprint (sha256)." "X509 certificate fingerprint (sha256)."

View File

@ -125,7 +125,7 @@ fn list_users(param: Value, rpcenv: &mut dyn RpcEnvironment) -> Result<Value, Er
let output_format = get_output_format(&param); let output_format = get_output_format(&param);
let info = &api2::config::user::API_METHOD_LIST_USERS; let info = &api2::access::user::API_METHOD_LIST_USERS;
let mut data = match info.handler { let mut data = match info.handler {
ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?, ApiHandler::Sync(handler) => (handler)(param, info, rpcenv)?,
_ => unreachable!(), _ => unreachable!(),
@ -152,18 +152,18 @@ fn user_commands() -> CommandLineInterface {
.insert( .insert(
"create", "create",
// fixme: howto handle password parameter? // fixme: howto handle password parameter?
CliCommand::new(&api2::config::user::API_METHOD_CREATE_USER) CliCommand::new(&api2::access::user::API_METHOD_CREATE_USER)
.arg_param(&["userid"]) .arg_param(&["userid"])
) )
.insert( .insert(
"update", "update",
CliCommand::new(&api2::config::user::API_METHOD_UPDATE_USER) CliCommand::new(&api2::access::user::API_METHOD_UPDATE_USER)
.arg_param(&["userid"]) .arg_param(&["userid"])
.completion_cb("userid", config::user::complete_user_name) .completion_cb("userid", config::user::complete_user_name)
) )
.insert( .insert(
"remove", "remove",
CliCommand::new(&api2::config::user::API_METHOD_DELETE_USER) CliCommand::new(&api2::access::user::API_METHOD_DELETE_USER)
.arg_param(&["userid"]) .arg_param(&["userid"])
.completion_cb("userid", config::user::complete_user_name) .completion_cb("userid", config::user::complete_user_name)
); );