]> git.proxmox.com Git - proxmox-backup.git/blob - src/api2/access.rs
start ACL api
[proxmox-backup.git] / src / api2 / access.rs
1 use failure::*;
2
3 use serde_json::{json, Value};
4
5 use proxmox::api::{api, RpcEnvironment};
6 use proxmox::api::router::{Router, SubdirMap};
7 use proxmox::{sortable, identity};
8 use proxmox::{http_err, list_subdirs_api_method};
9
10 use crate::tools;
11 use crate::tools::ticket::*;
12 use crate::auth_helpers::*;
13 use crate::api2::types::*;
14
15 pub mod user;
16 pub mod domain;
17 pub mod acl;
18
19 fn authenticate_user(username: &str, password: &str) -> Result<(), Error> {
20
21 let ticket_lifetime = tools::ticket::TICKET_LIFETIME;
22
23 if password.starts_with("PBS:") {
24 if let Ok((_age, Some(ticket_username))) = tools::ticket::verify_rsa_ticket(public_auth_key(), "PBS", password, None, -300, ticket_lifetime) {
25 if ticket_username == username {
26 return Ok(());
27 } else {
28 bail!("ticket login failed - wrong username");
29 }
30 }
31 }
32
33 crate::auth::authenticate_user(username, password)
34 }
35
36 #[api(
37 input: {
38 properties: {
39 username: {
40 schema: PROXMOX_USER_ID_SCHEMA,
41 },
42 password: {
43 schema: PASSWORD_SCHEMA,
44 },
45 },
46 },
47 returns: {
48 properties: {
49 username: {
50 type: String,
51 description: "User name.",
52 },
53 ticket: {
54 type: String,
55 description: "Auth ticket.",
56 },
57 CSRFPreventionToken: {
58 type: String,
59 description: "Cross Site Request Forgery Prevention Token.",
60 },
61 },
62 },
63 protected: true,
64 )]
65 /// Create or verify authentication ticket.
66 ///
67 /// Returns: An authentication ticket with additional infos.
68 fn create_ticket(username: String, password: String) -> Result<Value, Error> {
69 match authenticate_user(&username, &password) {
70 Ok(_) => {
71
72 let ticket = assemble_rsa_ticket( private_auth_key(), "PBS", Some(&username), None)?;
73
74 let token = assemble_csrf_prevention_token(csrf_secret(), &username);
75
76 log::info!("successful auth for user '{}'", username);
77
78 Ok(json!({
79 "username": username,
80 "ticket": ticket,
81 "CSRFPreventionToken": token,
82 }))
83 }
84 Err(err) => {
85 let client_ip = "unknown"; // $rpcenv->get_client_ip() || '';
86 log::error!("authentication failure; rhost={} user={} msg={}", client_ip, username, err.to_string());
87 Err(http_err!(UNAUTHORIZED, "permission check failed.".into()))
88 }
89 }
90 }
91
92 #[api(
93 input: {
94 properties: {
95 userid: {
96 schema: PROXMOX_USER_ID_SCHEMA,
97 },
98 password: {
99 schema: PASSWORD_SCHEMA,
100 },
101 },
102 },
103 )]
104 /// Change user password
105 ///
106 /// Each user is allowed to change his own password. Superuser
107 /// can change all passwords.
108 fn change_password(
109 userid: String,
110 password: String,
111 rpcenv: &mut dyn RpcEnvironment,
112 ) -> Result<Value, Error> {
113
114 let current_user = rpcenv.get_user()
115 .ok_or_else(|| format_err!("unknown user"))?;
116
117 let mut allowed = userid == current_user;
118
119 if userid == "root@pam" { allowed = true; }
120
121 if !allowed {
122 bail!("you are not authorized to change the password.");
123 }
124
125 let (username, realm) = crate::auth::parse_userid(&userid)?;
126 let authenticator = crate::auth::lookup_authenticator(&realm)?;
127 authenticator.store_password(&username, &password)?;
128
129 Ok(Value::Null)
130 }
131
132 #[sortable]
133 const SUBDIRS: SubdirMap = &sorted!([
134 ("acl", &acl::ROUTER),
135 (
136 "password", &Router::new()
137 .put(&API_METHOD_CHANGE_PASSWORD)
138 ),
139 (
140 "ticket", &Router::new()
141 .post(&API_METHOD_CREATE_TICKET)
142 ),
143 ("domains", &domain::ROUTER),
144 ("users", &user::ROUTER),
145 ]);
146
147 pub const ROUTER: Router = Router::new()
148 .get(&list_subdirs_api_method!(SUBDIRS))
149 .subdirs(SUBDIRS);