]> git.proxmox.com Git - pve-access-control.git/blob - PVE/API2/Role.pm
fix #2575: die when trying to edit built-in roles
[pve-access-control.git] / PVE / API2 / Role.pm
1 package PVE::API2::Role;
2
3 use strict;
4 use warnings;
5 use PVE::Cluster qw (cfs_read_file cfs_write_file);
6 use PVE::AccessControl;
7 use PVE::JSONSchema qw(get_standard_option register_standard_option);
8
9 use PVE::SafeSyslog;
10
11 use PVE::RESTHandler;
12
13 use base qw(PVE::RESTHandler);
14
15 register_standard_option('role-id', {
16 type => 'string',
17 format => 'pve-roleid',
18 });
19 register_standard_option('role-privs', {
20 type => 'string' ,
21 format => 'pve-priv-list',
22 optional => 1,
23 });
24
25 __PACKAGE__->register_method ({
26 name => 'index',
27 path => '',
28 method => 'GET',
29 description => "Role index.",
30 permissions => {
31 user => 'all',
32 },
33 parameters => {
34 additionalProperties => 0,
35 properties => {},
36 },
37 returns => {
38 type => 'array',
39 items => {
40 type => "object",
41 properties => {
42 roleid => get_standard_option('role-id'),
43 privs => get_standard_option('role-privs'),
44 special => { type => 'boolean', optional => 1, default => 0 },
45 },
46 },
47 links => [ { rel => 'child', href => "{roleid}" } ],
48 },
49 code => sub {
50 my ($param) = @_;
51
52 my $res = [];
53
54 my $usercfg = cfs_read_file("user.cfg");
55
56 foreach my $role (keys %{$usercfg->{roles}}) {
57 my $privs = join(',', sort keys %{$usercfg->{roles}->{$role}});
58 push @$res, {
59 roleid => $role,
60 privs => $privs,
61 special => PVE::AccessControl::role_is_special($role),
62 };
63 }
64
65 return $res;
66 }});
67
68 __PACKAGE__->register_method ({
69 name => 'create_role',
70 protected => 1,
71 path => '',
72 method => 'POST',
73 permissions => {
74 check => ['perm', '/access', ['Sys.Modify']],
75 },
76 description => "Create new role.",
77 parameters => {
78 additionalProperties => 0,
79 properties => {
80 roleid => get_standard_option('role-id'),
81 privs => get_standard_option('role-privs'),
82 },
83 },
84 returns => { type => 'null' },
85 code => sub {
86 my ($param) = @_;
87
88 PVE::AccessControl::lock_user_config(
89 sub {
90
91 my $usercfg = cfs_read_file("user.cfg");
92
93 my $role = $param->{roleid};
94
95 die "role '$role' already exists\n"
96 if $usercfg->{roles}->{$role};
97
98 $usercfg->{roles}->{$role} = {};
99
100 PVE::AccessControl::add_role_privs($role, $usercfg, $param->{privs});
101
102 cfs_write_file("user.cfg", $usercfg);
103 }, "create role failed");
104
105 return undef;
106 }});
107
108 __PACKAGE__->register_method ({
109 name => 'update_role',
110 protected => 1,
111 path => '{roleid}',
112 method => 'PUT',
113 permissions => {
114 check => ['perm', '/access', ['Sys.Modify']],
115 },
116 description => "Update an existing role.",
117 parameters => {
118 additionalProperties => 0,
119 properties => {
120 roleid => get_standard_option('role-id'),
121 privs => get_standard_option('role-privs'),
122 append => { type => 'boolean', optional => 1, requires => 'privs' },
123 },
124 },
125 returns => { type => 'null' },
126 code => sub {
127 my ($param) = @_;
128
129 my $role = $param->{roleid};
130
131 die "auto-generated role '$role' cannot be modified\n"
132 if PVE::AccessControl::role_is_special($role);
133
134 PVE::AccessControl::lock_user_config(
135 sub {
136
137 my $usercfg = cfs_read_file("user.cfg");
138
139 die "role '$role' does not exist\n"
140 if !$usercfg->{roles}->{$role};
141
142 $usercfg->{roles}->{$role} = {} if !$param->{append};
143
144 PVE::AccessControl::add_role_privs($role, $usercfg, $param->{privs});
145
146 cfs_write_file("user.cfg", $usercfg);
147 }, "update role failed");
148
149 return undef;
150 }});
151
152 __PACKAGE__->register_method ({
153 name => 'read_role',
154 path => '{roleid}',
155 method => 'GET',
156 permissions => {
157 user => 'all',
158 },
159 description => "Get role configuration.",
160 parameters => {
161 additionalProperties => 0,
162 properties => {
163 roleid => get_standard_option('role-id'),
164 },
165 },
166 returns => {
167 type => "object",
168 additionalProperties => 0,
169 properties => PVE::AccessControl::create_priv_properties(),
170 },
171 code => sub {
172 my ($param) = @_;
173
174 my $usercfg = cfs_read_file("user.cfg");
175
176 my $role = $param->{roleid};
177
178 my $data = $usercfg->{roles}->{$role};
179
180 die "role '$role' does not exist\n" if !$data;
181
182 return $data;
183 }
184 });
185
186 __PACKAGE__->register_method ({
187 name => 'delete_role',
188 protected => 1,
189 path => '{roleid}',
190 method => 'DELETE',
191 permissions => {
192 check => ['perm', '/access', ['Sys.Modify']],
193 },
194 description => "Delete role.",
195 parameters => {
196 additionalProperties => 0,
197 properties => {
198 roleid => get_standard_option('role-id'),
199 },
200 },
201 returns => { type => 'null' },
202 code => sub {
203 my ($param) = @_;
204
205 my $role = $param->{roleid};
206
207 die "auto-generated role '$role' cannot be deleted\n"
208 if PVE::AccessControl::role_is_special($role);
209
210 PVE::AccessControl::lock_user_config(
211 sub {
212 my $usercfg = cfs_read_file("user.cfg");
213
214 die "role '$role' does not exist\n"
215 if !$usercfg->{roles}->{$role};
216
217 delete ($usercfg->{roles}->{$role});
218
219 # fixme: delete role from acl?
220
221 cfs_write_file("user.cfg", $usercfg);
222 }, "delete role failed");
223
224 return undef;
225 }
226 });
227
228 1;