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