1 use anyhow
::{bail, format_err, Error}
;
3 use serde_json
::{json, Value}
;
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}
;
11 use crate::tools
::ticket
::*;
12 use crate::auth_helpers
::*;
13 use crate::api2
::types
::*;
15 use crate::config
::cached_user_info
::CachedUserInfo
;
16 use crate::config
::acl
::PRIV_PERMISSIONS_MODIFY
;
23 fn authenticate_user(username
: &str, password
: &str) -> Result
<(), Error
> {
25 let user_info
= CachedUserInfo
::new()?
;
27 if !user_info
.is_active_user(&username
) {
28 bail
!("user account disabled or expired.");
31 let ticket_lifetime
= tools
::ticket
::TICKET_LIFETIME
;
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
{
38 bail
!("ticket login failed - wrong username");
43 crate::auth
::authenticate_user(username
, password
)
50 schema
: PROXMOX_USER_ID_SCHEMA
,
53 schema
: PASSWORD_SCHEMA
,
61 description
: "User name.",
65 description
: "Auth ticket.",
67 CSRFPreventionToken
: {
69 description
: "Cross Site Request Forgery Prevention Token.",
75 permission
: &Permission
::World
,
78 /// Create or verify authentication ticket.
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
) {
85 let ticket
= assemble_rsa_ticket( private_auth_key(), "PBS", Some(&username
), None
)?
;
87 let token
= assemble_csrf_prevention_token(csrf_secret(), &username
);
89 log
::info
!("successful auth for user '{}'", username
);
94 "CSRFPreventionToken": token
,
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()))
109 schema
: PROXMOX_USER_ID_SCHEMA
,
112 schema
: PASSWORD_SCHEMA
,
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
,
122 /// Change user password
124 /// Each user is allowed to change his own password. Superuser
125 /// can change all passwords.
129 rpcenv
: &mut dyn RpcEnvironment
,
130 ) -> Result
<Value
, Error
> {
132 let current_user
= rpcenv
.get_user()
133 .ok_or_else(|| format_err
!("unknown user"))?
;
135 let mut allowed
= userid
== current_user
;
137 if userid
== "root@pam" { allowed = true; }
140 use crate::config
::cached_user_info
::CachedUserInfo
;
142 let user_info
= CachedUserInfo
::new()?
;
143 let privs
= user_info
.lookup_privs(¤t_user
, &[]);
144 if (privs
& PRIV_PERMISSIONS_MODIFY
) != 0 { allowed = true; }
148 bail
!("you are not authorized to change the password.");
151 let (username
, realm
) = crate::auth
::parse_userid(&userid
)?
;
152 let authenticator
= crate::auth
::lookup_authenticator(&realm
)?
;
153 authenticator
.store_password(&username
, &password
)?
;
159 const SUBDIRS
: SubdirMap
= &sorted
!([
160 ("acl", &acl
::ROUTER
),
162 "password", &Router
::new()
163 .put(&API_METHOD_CHANGE_PASSWORD
)
166 "ticket", &Router
::new()
167 .post(&API_METHOD_CREATE_TICKET
)
169 ("domains", &domain
::ROUTER
),
170 ("roles", &role
::ROUTER
),
171 ("users", &user
::ROUTER
),
174 pub const ROUTER
: Router
= Router
::new()
175 .get(&list_subdirs_api_method
!(SUBDIRS
))