]> git.proxmox.com Git - pve-access-control.git/blame - src/PVE/CLI/pveum.pm
bump version to 8.1.4
[pve-access-control.git] / src / PVE / CLI / pveum.pm
CommitLineData
09281ad7
DM
1package PVE::CLI::pveum;
2
3use strict;
4use warnings;
042eaa3d 5
66d1b615 6use PVE::AccessControl;
09281ad7
DM
7use PVE::RPCEnvironment;
8use PVE::API2::User;
9use PVE::API2::Group;
10use PVE::API2::Role;
11use PVE::API2::ACL;
12use PVE::API2::AccessControl;
f28a69a0 13use PVE::API2::Domains;
dc547a13 14use PVE::API2::TFA;
9d06f603 15use PVE::Cluster qw(cfs_read_file cfs_write_file);
369851ac 16use PVE::CLIFormatter;
09281ad7 17use PVE::CLIHandler;
66d1b615 18use PVE::JSONSchema qw(get_standard_option);
b34d76e7 19use PVE::PTY;
369851ac 20use PVE::RESTHandler;
66d1b615 21use PVE::Tools qw(extract_param);
09281ad7
DM
22
23use base qw(PVE::CLIHandler);
24
e623414a
DM
25sub setup_environment {
26 PVE::RPCEnvironment->setup_default_cli_env();
27}
28
b34d76e7
DC
29sub param_mapping {
30 my ($name) = @_;
98007830 31
b34d76e7
DC
32 my $mapping = {
33 'change_password' => [
34 PVE::CLIHandler::get_standard_mapping('pve-password'),
35 ],
36 'create_ticket' => [
37 PVE::CLIHandler::get_standard_mapping('pve-password', {
38 func => sub {
39 # do not accept values given on cmdline
40 return PVE::PTY::read_password('Enter password: ');
41 },
42 }),
43 ]
44 };
45
46 return $mapping->{$name};
98007830
DM
47}
48
369851ac
FG
49my $print_api_result = sub {
50 my ($data, $schema, $options) = @_;
51 PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
52};
53
66d1b615
FG
54my $print_perm_result = sub {
55 my ($data, $schema, $options) = @_;
56
57 if (!defined($options->{'output-format'}) || $options->{'output-format'} eq 'text') {
58 my $table_schema = {
59 type => 'array',
60 items => {
61 type => 'object',
62 properties => {
63 'path' => { type => 'string', title => 'ACL path' },
64 'permissions' => { type => 'string', title => 'Permissions' },
65 },
66 },
67 };
68 my $table_data = [];
69 foreach my $path (sort keys %$data) {
70 my $value = '';
71 my $curr = $data->{$path};
72 foreach my $perm (sort keys %$curr) {
73 $value .= "\n" if $value;
74 $value .= $perm;
75 $value .= " (*)" if $curr->{$perm};
76 }
77 push @$table_data, { path => $path, permissions => $value };
78 }
79 PVE::CLIFormatter::print_api_result($table_data, $table_schema, undef, $options);
80 print "Permissions marked with '(*)' have the 'propagate' flag set.\n";
81 } else {
82 PVE::CLIFormatter::print_api_result($data, $schema, undef, $options);
83 }
84};
85
86__PACKAGE__->register_method({
87 name => 'token_permissions',
88 path => 'token_permissions',
89 method => 'GET',
90 description => 'Retrieve effective permissions of given token.',
91 parameters => {
92 additionalProperties => 0,
93 properties => {
94 userid => get_standard_option('userid'),
95 tokenid => get_standard_option('token-subid'),
96 path => get_standard_option('acl-path', {
97 description => "Only dump this specific path, not the whole tree.",
98 optional => 1,
99 }),
100 },
101 },
102 returns => {
103 type => 'object',
104 description => 'Hash of structure "path" => "privilege" => "propagate boolean".',
105 },
106 code => sub {
107 my ($param) = @_;
108
109 my $token_subid = extract_param($param, "tokenid");
110 $param->{userid} = PVE::AccessControl::join_tokenid($param->{userid}, $token_subid);
111
112 return PVE::API2::AccessControl->permissions($param);
113 }});
114
9d06f603
WB
115__PACKAGE__->register_method({
116 name => 'delete_tfa',
117 path => 'delete_tfa',
118 method => 'PUT',
119 description => 'Delete TFA entries from a user.',
120 parameters => {
121 additionalProperties => 0,
122 properties => {
123 userid => get_standard_option('userid'),
124 id => {
125 description => "The TFA ID, if none provided, all TFA entries will be deleted.",
126 type => 'string',
127 optional => 1,
128 },
129 },
130 },
131 returns => { type => 'null' },
132 code => sub {
133 my ($param) = @_;
134
135 my $userid = extract_param($param, "userid");
136 my $tfa_id = extract_param($param, "id");
137
9d06f603
WB
138 PVE::AccessControl::lock_tfa_config(sub {
139 my $tfa_cfg = cfs_read_file('priv/tfa.cfg');
140 if (defined($tfa_id)) {
141 $tfa_cfg->api_delete_tfa($userid, $tfa_id);
142 } else {
143 $tfa_cfg->remove_user($userid);
144 }
145 cfs_write_file('priv/tfa.cfg', $tfa_cfg);
146 });
147 return;
148 }});
149
9d299603
WB
150__PACKAGE__->register_method({
151 name => 'list_tfa',
152 path => 'list_tfa',
153 method => 'GET',
154 description => "List TFA entries.",
155 parameters => {
156 additionalProperties => 0,
157 properties => {
158 userid => get_standard_option('userid', { optional => 1 }),
159 },
160 },
161 returns => { type => 'null' },
162 code => sub {
163 my ($param) = @_;
164
165 my $userid = extract_param($param, "userid");
166
9d299603
WB
167 my sub format_tfa_entries : prototype($;$) {
168 my ($entries, $indent) = @_;
169
170 $indent //= '';
171
172 my $nl = '';
173 for my $entry (@$entries) {
174 my ($id, $ty, $desc) = ($entry->@{qw/id type description/});
c200d9fd 175 printf("${nl}${indent}%-9s %s\n${indent} %s\n", "$ty:", $id, $desc // '');
9d299603
WB
176 $nl = "\n";
177 }
178 };
179
180 my $tfa_cfg = cfs_read_file('priv/tfa.cfg');
181 if (defined($userid)) {
182 format_tfa_entries($tfa_cfg->api_list_user_tfa($userid));
183 } else {
184 my $result = $tfa_cfg->api_list_tfa('', 1);
185 my $nl = '';
aba03c96 186 for my $entry (sort { $a->{userid} cmp $b->{userid} } @$result) {
9d299603
WB
187 print "${nl}$entry->{userid}:\n";
188 format_tfa_entries($entry->{entries}, ' ');
189 $nl = "\n";
190 }
191 }
192 return;
193 }});
194
09281ad7 195our $cmddef = {
1e41cdc9
PA
196 user => {
197 add => [ 'PVE::API2::User', 'create_user', ['userid'] ],
198 modify => [ 'PVE::API2::User', 'update_user', ['userid'] ],
199 delete => [ 'PVE::API2::User', 'delete_user', ['userid'] ],
369851ac 200 list => [ 'PVE::API2::User', 'index', [], {}, $print_api_result, $PVE::RESTHandler::standard_output_options],
66d1b615 201 permissions => [ 'PVE::API2::AccessControl', 'permissions', ['userid'], {}, $print_perm_result, $PVE::RESTHandler::standard_output_options],
618d112b 202 tfa => {
9d06f603 203 delete => [ __PACKAGE__, 'delete_tfa', ['userid'] ],
9d299603 204 list => [ __PACKAGE__, 'list_tfa', ['userid'] ],
ddf78dfb 205 unlock => [ 'PVE::API2::User', 'unlock_tfa', ['userid'] ],
618d112b 206 },
084c149a
FG
207 token => {
208 add => [ 'PVE::API2::User', 'generate_token', ['userid', 'tokenid'], {}, $print_api_result, $PVE::RESTHandler::standard_output_options ],
ccaecac1 209 modify => [ 'PVE::API2::User', 'update_token_info', ['userid', 'tokenid'], {}, $print_api_result, $PVE::RESTHandler::standard_output_options ],
084c149a
FG
210 remove => [ 'PVE::API2::User', 'remove_token', ['userid', 'tokenid'], {}, $print_api_result, $PVE::RESTHandler::standard_output_options ],
211 list => [ 'PVE::API2::User', 'token_index', ['userid'], {}, $print_api_result, $PVE::RESTHandler::standard_output_options],
66d1b615 212 permissions => [ __PACKAGE__, 'token_permissions', ['userid', 'tokenid'], {}, $print_perm_result, $PVE::RESTHandler::standard_output_options],
084c149a 213 }
1e41cdc9
PA
214 },
215 group => {
216 add => [ 'PVE::API2::Group', 'create_group', ['groupid'] ],
217 modify => [ 'PVE::API2::Group', 'update_group', ['groupid'] ],
218 delete => [ 'PVE::API2::Group', 'delete_group', ['groupid'] ],
369851ac 219 list => [ 'PVE::API2::Group', 'index', [], {}, $print_api_result, $PVE::RESTHandler::standard_output_options],
1e41cdc9
PA
220 },
221 role => {
222 add => [ 'PVE::API2::Role', 'create_role', ['roleid'] ],
223 modify => [ 'PVE::API2::Role', 'update_role', ['roleid'] ],
224 delete => [ 'PVE::API2::Role', 'delete_role', ['roleid'] ],
369851ac 225 list => [ 'PVE::API2::Role', 'index', [], {}, $print_api_result, $PVE::RESTHandler::standard_output_options],
1e41cdc9
PA
226 },
227 acl => {
228 modify => [ 'PVE::API2::ACL', 'update_acl', ['path'], { delete => 0 }],
229 delete => [ 'PVE::API2::ACL', 'update_acl', ['path'], { delete => 1 }],
369851ac 230 list => [ 'PVE::API2::ACL', 'read_acl', [], {}, $print_api_result, $PVE::RESTHandler::standard_output_options],
1e41cdc9 231 },
f28a69a0
DC
232 realm => {
233 add => [ 'PVE::API2::Domains', 'create', ['realm'] ],
234 modify => [ 'PVE::API2::Domains', 'update', ['realm'] ],
235 delete => [ 'PVE::API2::Domains', 'delete', ['realm'] ],
236 list => [ 'PVE::API2::Domains', 'index', [], {}, $print_api_result, $PVE::RESTHandler::standard_output_options],
673d2bf2 237 sync => [ 'PVE::API2::Domains', 'sync', ['realm'], ],
f28a69a0
DC
238 },
239
09281ad7
DM
240 ticket => [ 'PVE::API2::AccessControl', 'create_ticket', ['username'], undef,
241 sub {
242 my ($res) = @_;
243 print "$res->{ticket}\n";
244 }],
245
765305e2 246 passwd => [ 'PVE::API2::AccessControl', 'change_password', ['userid'] ],
09281ad7 247
1e41cdc9
PA
248 useradd => { alias => 'user add' },
249 usermod => { alias => 'user modify' },
250 userdel => { alias => 'user delete' },
09281ad7 251
1e41cdc9
PA
252 groupadd => { alias => 'group add' },
253 groupmod => { alias => 'group modify' },
254 groupdel => { alias => 'group delete' },
09281ad7 255
1e41cdc9
PA
256 roleadd => { alias => 'role add' },
257 rolemod => { alias => 'role modify' },
258 roledel => { alias => 'role delete' },
09281ad7 259
1e41cdc9
PA
260 aclmod => { alias => 'acl modify' },
261 acldel => { alias => 'acl delete' },
09281ad7
DM
262};
263
3470fad8
TL
264# FIXME: HACK! The pool API is in pve-manager as it needs access to storage guest and RRD stats,
265# so we only add the pool commands if the API module is available (required for boots-trapping)
266my $have_pool_api;
267eval {
268 require PVE::API2::Pool;
269 PVE::API2::Pool->import();
270 $have_pool_api = 1;
271};
272
273if ($have_pool_api) {
274 $cmddef->{pool} = {
275 add => [ 'PVE::API2::Pool', 'create_pool', ['poolid'] ],
276 modify => [ 'PVE::API2::Pool', 'update_pool', ['poolid'] ],
277 delete => [ 'PVE::API2::Pool', 'delete_pool', ['poolid'] ],
278 list => [ 'PVE::API2::Pool', 'index', [], {}, $print_api_result, $PVE::RESTHandler::standard_output_options],
279 };
280}
281
09281ad7 2821;