File Coverage

blib/lib/Net/Proxmox/VE/Access.pm
Criterion Covered Total %
statement 12 194 6.1
branch 0 186 0.0
condition 0 24 0.0
subroutine 4 31 12.9
pod 27 27 100.0
total 43 462 9.3


line stmt bran cond sub pod time code
1             #!/bin/false
2             # PODNAME: Net::Proxmox::VE::Access
3             # ABSTRACT: Functions for the 'access' portion of the API
4              
5 1     1   8 use strict;
  1         1  
  1         26  
6 1     1   5 use warnings;
  1         2  
  1         41  
7              
8             package Net::Proxmox::VE::Access;
9             $Net::Proxmox::VE::Access::VERSION = '0.36';
10 1     1   4 use parent 'Exporter';
  1         2  
  1         6  
11              
12 1     1   47 use JSON qw(decode_json);
  1         12  
  1         22  
13              
14             our @EXPORT =
15             qw(
16             access
17             access_domains access_groups access_roles
18             create_access_domains create_access_groups create_access_roles create_access_users
19             delete_access_domains delete_access_groups delete_access_roles delete_access_users
20             get_access_domains get_access_groups get_access_roles get_access_users
21             update_access_domains update_access_groups update_access_roles update_access_users
22             login check_login_ticket clear_login_ticket
23             get_access_acl update_access_acl
24             update_access_password
25             );
26              
27              
28             my $base = '/access';
29              
30             sub access {
31              
32 0 0   0 1   my $self = shift or return;
33              
34 0           return $self->get($base);
35              
36             }
37              
38              
39             sub access_domains {
40              
41 0 0   0 1   my $self = shift or return;
42              
43 0           return $self->get( $base, 'domains' )
44              
45             }
46              
47              
48             sub create_access_domains {
49              
50 0 0   0 1   my $self = shift or return;
51 0           my @p = @_;
52              
53 0 0         die 'No arguments for create_access_domains()' unless @p;
54 0           my %args;
55              
56 0 0         if ( @p == 1 ) {
57 0 0         die 'Single argument not a hash for create_access_domains()'
58             unless ref $a eq 'HASH';
59 0           %args = %{ $p[0] };
  0            
60             }
61             else {
62 0 0         die 'Odd number of arguments for create_access_domains()'
63             if ( scalar @p % 2 != 0 );
64 0           %args = @p;
65             }
66              
67 0           return $self->post( $base, 'domains', \%args )
68              
69             }
70              
71              
72             sub get_access_domains {
73              
74 0 0   0 1   my $self = shift or return;
75              
76 0 0         my $a = shift or die 'No realm for get_access_domains()';
77 0 0         die 'realm must be a scalar for get_access_domains()' if ref $a;
78              
79 0           return $self->get( $base, 'domains', $a )
80              
81             }
82              
83              
84             sub update_access_domains {
85              
86 0 0   0 1   my $self = shift or return;
87 0 0         my $realm = shift or die 'No realm provided for update_access_domains()';
88 0 0         die 'realm must be a scalar for update_access_domains()' if ref $realm;
89 0           my @p = @_;
90              
91 0 0         die 'No arguments for update_access_domains()' unless @p;
92 0           my %args;
93              
94 0 0         if ( @p == 1 ) {
95 0 0         die 'Single argument not a hash for update_access_domains()'
96             unless ref $a eq 'HASH';
97 0           %args = %{ $p[0] };
  0            
98             }
99             else {
100 0 0         die 'Odd number of arguments for update_access_domains()'
101             if ( scalar @p % 2 != 0 );
102 0           %args = @p;
103             }
104              
105 0           return $self->put( $base, 'domains', $realm, \%args )
106              
107             }
108              
109              
110             sub delete_access_domains {
111              
112 0 0   0 1   my $self = shift or return;
113 0 0         my $a = shift or die 'No argument given for delete_access_domains()';
114              
115 0           return $self->delete( $base, 'domains', $a )
116              
117             }
118              
119              
120             sub access_groups {
121              
122 0 0   0 1   my $self = shift or return;
123              
124 0           return $self->get( $base, 'groups' )
125              
126             }
127              
128              
129             sub create_access_groups {
130              
131 0 0   0 1   my $self = shift or return;
132 0           my @p = @_;
133              
134 0 0         die 'No arguments for create_access_groups()' unless @p;
135 0           my %args;
136              
137 0 0         if ( @p == 1 ) {
138 0 0         die 'Single argument not a hash for create_access_groups()'
139             unless ref $a eq 'HASH';
140 0           %args = %{ $p[0] };
  0            
141             }
142             else {
143 0 0         die 'Odd number of arguments for create_access_groups()'
144             if ( scalar @p % 2 != 0 );
145 0           %args = @p;
146             }
147              
148 0           return $self->post( $base, 'groups', \%args )
149              
150             }
151              
152              
153             sub get_access_groups {
154              
155 0 0   0 1   my $self = shift or return;
156              
157 0 0         my $a = shift or die 'No groupid for get_access_groups()';
158 0 0         die 'groupid must be a scalar for get_access_groups()' if ref $a;
159              
160 0           return $self->get( $base, 'groups', $a )
161              
162             }
163              
164              
165             sub update_access_groups {
166              
167 0 0   0 1   my $self = shift or return;
168 0 0         my $realm = shift or die 'No realm provided for update_access_groups()';
169 0 0         die 'realm must be a scalar for update_access_groups()' if ref $realm;
170 0           my @p = @_;
171              
172 0 0         die 'No arguments for update_access_groups()' unless @p;
173 0           my %args;
174              
175 0 0         if ( @p == 1 ) {
176 0 0         die 'Single argument not a hash for update_access_groups()'
177             unless ref $a eq 'HASH';
178 0           %args = %{ $p[0] };
  0            
179             }
180             else {
181 0 0         die 'Odd number of arguments for update_access_groups()'
182             if ( scalar @p % 2 != 0 );
183 0           %args = @p;
184             }
185              
186 0           return $self->put( $base, 'groups', $realm, \%args )
187              
188             }
189              
190              
191             sub delete_access_groups {
192              
193 0 0   0 1   my $self = shift or return;
194 0 0         my $a = shift or die 'No argument given for delete_access_groups()';
195              
196 0           return $self->delete( $base, 'groups', $a )
197              
198             }
199              
200              
201              
202             sub access_roles {
203              
204 0 0   0 1   my $self = shift or return;
205              
206 0           return $self->get( $base, 'roles' )
207              
208             }
209              
210              
211             sub create_access_roles {
212              
213 0 0   0 1   my $self = shift or return;
214 0           my @p = @_;
215              
216 0 0         die 'No arguments for create_access_roles()' unless @p;
217 0           my %args;
218              
219 0 0         if ( @p == 1 ) {
220 0 0         die 'Single argument not a hash for create_access_roles()'
221             unless ref $a eq 'HASH';
222 0           %args = %{ $p[0] };
  0            
223             }
224             else {
225 0 0         die 'Odd number of arguments for create_access_roles()'
226             if ( scalar @p % 2 != 0 );
227 0           %args = @p;
228             }
229              
230 0           return $self->post( $base, 'roles', \%args )
231              
232             }
233              
234              
235             sub get_access_roles {
236              
237 0 0   0 1   my $self = shift or return;
238              
239 0 0         my $a = shift or die 'No roleid for get_access_roles()';
240 0 0         die 'roleid must be a scalar for get_access_roles()' if ref $a;
241              
242 0           return $self->get( $base, 'roles', $a )
243              
244             }
245              
246              
247             sub update_access_roles {
248              
249 0 0   0 1   my $self = shift or return;
250 0 0         my $realm = shift or die 'No realm provided for update_access_roles()';
251 0 0         die 'realm must be a scalar for update_access_roles()' if ref $realm;
252 0           my @p = @_;
253              
254 0 0         die 'No arguments for update_access_roles()' unless @p;
255 0           my %args;
256              
257 0 0         if ( @p == 1 ) {
258 0 0         die 'Single argument not a hash for update_access_roles()'
259             unless ref $a eq 'HASH';
260 0           %args = %{ $p[0] };
  0            
261             }
262             else {
263 0 0         die 'Odd number of arguments for update_access_roles()'
264             if ( scalar @p % 2 != 0 );
265 0           %args = @p;
266             }
267              
268 0           return $self->put( $base, 'roles', $realm, \%args )
269              
270             }
271              
272              
273             sub delete_access_roles {
274              
275 0 0   0 1   my $self = shift or return;
276 0 0         my $a = shift or die 'No argument given for delete_access_roles()';
277              
278 0           return $self->delete( $base, 'roles', $a )
279              
280             }
281              
282              
283              
284             sub access_users {
285              
286 0 0   0 1   my $self = shift or return;
287              
288 0           return $self->get( $base, 'users' )
289              
290             }
291              
292              
293             sub create_access_users {
294              
295 0 0   0 1   my $self = shift or return;
296 0           my @p = @_;
297              
298 0 0         die 'No arguments for create_access_users()' unless @p;
299 0           my %args;
300              
301 0 0         if ( @p == 1 ) {
302 0 0         die 'Single argument not a hash for create_access_users()'
303             unless ref $a eq 'HASH';
304 0           %args = %{ $p[0] };
  0            
305             }
306             else {
307 0 0         die 'Odd number of arguments for create_access_users()'
308             if ( scalar @p % 2 != 0 );
309 0           %args = @p;
310             }
311              
312 0           return $self->post( $base, 'users', \%args )
313              
314             }
315              
316              
317             sub get_access_users {
318              
319 0 0   0 1   my $self = shift or return;
320              
321 0 0         my $a = shift or die 'No userid for get_access_users()';
322 0 0         die 'userid must be a scalar for get_access_users()' if ref $a;
323              
324 0           return $self->get( $base, 'users', $a )
325              
326             }
327              
328              
329             sub update_access_users {
330              
331 0 0   0 1   my $self = shift or return;
332 0 0         my $realm = shift or die 'No realm provided for update_access_users()';
333 0 0         die 'realm must be a scalar for update_access_users()' if ref $realm;
334 0           my @p = @_;
335              
336 0 0         die 'No arguments for update_access_users()' unless @p;
337 0           my %args;
338              
339 0 0         if ( @p == 1 ) {
340 0 0         die 'Single argument not a hash for update_access_users()'
341             unless ref $a eq 'HASH';
342 0           %args = %{ $p[0] };
  0            
343             }
344             else {
345 0 0         die 'Odd number of arguments for update_access_users()'
346             if ( scalar @p % 2 != 0 );
347 0           %args = @p;
348             }
349              
350 0           return $self->put( $base, 'users', $realm, \%args )
351              
352             }
353              
354              
355             sub delete_access_users {
356              
357 0 0   0 1   my $self = shift or return;
358 0 0         my $a = shift or die 'No argument given for delete_access_users()';
359              
360 0           return $self->delete( $base, 'users', $a )
361              
362             }
363              
364              
365             sub check_login_ticket {
366              
367 0 0   0 1   my $self = shift or return;
368              
369 0 0 0       if ( $self->{ticket}
      0        
      0        
      0        
      0        
      0        
      0        
370             && ref $self->{ticket} eq 'HASH'
371             && $self->{ticket}
372             && $self->{ticket}->{ticket}
373             && $self->{ticket}->{CSRFPreventionToken}
374             && $self->{ticket}->{username} eq $self->{params}->{username} . '@'
375             . $self->{params}->{realm}
376             && $self->{ticket_timestamp}
377             && ( $self->{ticket_timestamp} + $self->{ticket_life} ) > time() )
378             {
379 0           return 1;
380             }
381             else {
382 0           $self->clear_login_ticket;
383             }
384              
385             return
386              
387 0           }
388              
389              
390             sub clear_login_ticket {
391              
392 0 0   0 1   my $self = shift or return;
393              
394 0 0 0       if ( $self->{ticket} or $self->{timestamp} ) {
395 0           $self->{ticket} = undef;
396 0           $self->{ticket_timestamp} = undef;
397 0           return 1;
398             }
399              
400             return
401              
402 0           }
403              
404              
405             sub get_access_acl {
406              
407 0 0   0 1   my $self = shift or return;
408              
409 0           return $self->get( $base, 'acl' );
410              
411             }
412              
413              
414             sub login {
415 0 0   0 1   my $self = shift or return;
416              
417             # Prepare login request
418 0           my $url = $self->url_prefix . '/api2/json/access/ticket';
419              
420             # Perform login request
421 0           my $request_time = time();
422             my $response = $self->{ua}->post(
423             $url,
424             {
425             'username' => $self->{params}->{username} . '@'
426             . $self->{params}->{realm},
427             'password' => $self->{params}->{password},
428             },
429 0           );
430              
431 0 0         if ( $response->is_success ) {
432             # my $content = $response->decoded_content;
433 0           my $login_ticket_data = decode_json( $response->decoded_content );
434 0           $self->{ticket} = $login_ticket_data->{data};
435              
436             # We use request time as the time to get the json ticket is undetermined,
437             # id rather have a ticket a few seconds shorter than have a ticket that incorrectly
438             # says its valid for a couple more
439 0           $self->{ticket_timestamp} = $request_time;
440             print "DEBUG: login successful\n"
441 0 0         if $self->{params}->{debug};
442 0           return 1;
443             }
444             else {
445              
446             print "DEBUG: login not successful\n"
447 0 0         if $self->{params}->{debug};
448             print "DEBUG: " . $response->status_line . "\n"
449 0 0         if $self->{params}->{debug};
450              
451             }
452              
453 0           return;
454             }
455              
456              
457             sub update_access_acl {
458              
459 0 0   0 1   my $self = shift or return;
460 0           my @p = @_;
461              
462 0 0         die 'No arguments for update_acl()' unless @p;
463 0           my %args;
464              
465 0 0         if ( @p == 1 ) {
466 0 0         die 'Single argument not a hash for update_acl()'
467             unless ref $a eq 'HASH';
468 0           %args = %{ $p[0] };
  0            
469             }
470             else {
471 0 0         die 'Odd number of arguments for update_acl()'
472             if ( scalar @p % 2 != 0 );
473 0           %args = @p;
474             }
475              
476 0           return $self->put( $base, 'acl', \%args )
477              
478             }
479              
480              
481             sub update_access_password {
482              
483 0 0   0 1   my $self = shift or return;
484 0           my @p = @_;
485              
486 0 0         die 'No arguments for update_password()' unless @p;
487 0           my %args;
488              
489 0 0         if ( @p == 1 ) {
490 0 0         die 'Single argument not a hash for update_password()'
491             unless ref $a eq 'HASH';
492 0           %args = %{ $p[0] };
  0            
493             }
494             else {
495 0 0         die 'Odd number of arguments for update_password()'
496             if ( scalar @p % 2 != 0 );
497 0           %args = @p;
498             }
499              
500 0           return $self->put( $base, 'password', \%args )
501              
502             }
503              
504              
505             1;
506              
507             =pod
508              
509             =encoding UTF-8
510              
511             =head1 NAME
512              
513             Net::Proxmox::VE::Access - Functions for the 'access' portion of the API
514              
515             =head1 VERSION
516              
517             version 0.36
518              
519             =head1 SYNOPSIS
520              
521             # assuming $obj is a Net::Proxmox::VE object
522              
523             my @dir_index = $obj->access();
524              
525             my @domain_index = $obj->access_domains();
526             my $domain = $obj->access_domains($realm);
527              
528             =head1 METHODS
529              
530             =head2 access
531              
532             Without arguments, returns the 'Directory index':
533              
534             Note: Accessible by all authententicated users.
535              
536             =head2 access_domains
537              
538             Gets a list of access domains (aka the Authentication domain index)
539              
540             @pools = $obj->access_domains();
541              
542             Note: Anyone can access that, because we need that list for the login box (before the user is authenticated).
543              
544             FIXME: currently this isn't implemented in this library.
545              
546             =head2 create_access_domains
547              
548             Creates a new access domain
549              
550             $ok = $obj->create_access_domains( %args );
551             $ok = $obj->create_access_domains( \%args );
552              
553             I<%args> may items contain from the following list
554              
555             =over 4
556              
557             =item realm
558              
559             String. The id of the authentication domain you wish to add, in pve-realm format. This is required.
560              
561             =item type
562              
563             Enum. This is the server type and is either 'ad' or 'ldap'. This is required.
564              
565             =item base_dn
566              
567             String. LDAP base domain name. Optional.
568              
569             =item comment
570              
571             String. This is a comment associated with the new domain, this is optional.
572              
573             =item default
574              
575             Boolean. Use this domain as the default. Optional.
576              
577             =item domain
578              
579             String. AD domain name. Optional.
580              
581             =item port
582              
583             Integer. Server port, user '0' if you want to use the default setting. Optional.
584              
585             =item secure
586              
587             Boolean. Use secure LDAPS protocol. Optional.
588              
589             =item user_attr
590              
591             String. LDAP user attribute name. Optional.
592              
593             =back
594              
595             =head2 get_access_domains
596              
597             Gets a single access domain
598              
599             $ok = $obj->get_access_domains('realm')
600              
601             realm is a string in pve-realm format
602              
603             =head2 update_access_domains
604              
605             Updates (sets) a access domain's data
606              
607             $ok = $obj->update_access_domains( 'realm', %args );
608             $ok = $obj->update_access_domains( 'realm', \%args );
609              
610             realm is a string in pve-realm format
611              
612             I<%args> may items contain from the following list
613              
614             =over 4
615              
616             =item base_dn
617              
618             String. LDAP base domain name. Optional.
619              
620             =item comment
621              
622             String. This is a comment associated with the domain, this is optional.
623              
624             =item default
625              
626             Boolean. Use this domain as the default. Optional.
627              
628             =item domain
629              
630             String. AD domain name. Optional.
631              
632             =item port
633              
634             Integer. Server port, user '0' if you want to use the default setting. Optional.
635              
636             =item secure
637              
638             Boolean. Use secure LDAPS protocol. Optional.
639              
640             =item user_attr
641              
642             String. LDAP user attribute name. Optional.
643              
644             =back
645              
646             =head2 delete_access_domains
647              
648             Deletes a single access domain
649              
650             $ok = $obj->delete_access_domains('realm')
651              
652             realm is a string in pve-realm format
653              
654             =head2 access_groups
655              
656             Gets a list of access groups (aka the Group index)
657              
658             @pools = $obj->access_groups();
659              
660             Note: The returned list is restricted to groups where you have 'User.Modify', 'Sys.Audit' or 'Group.Allocate' permissions on /access/groups/<>.
661              
662             =head2 create_access_groups
663              
664             Creates a new access group
665              
666             $ok = $obj->create_access_groups( %args );
667             $ok = $obj->create_access_groups( \%args );
668              
669             I<%args> may items contain from the following list
670              
671             =over 4
672              
673             =item groupid
674              
675             String. The id of the access group you wish to add, in pve-groupid format. This is required.
676              
677             =item comment
678              
679             String. This is a comment associated with the new group, this is optional.
680              
681             =back
682              
683             =head2 get_access_groups
684              
685             Gets a single access group
686              
687             $ok = $obj->get_access_groups('groupid')
688              
689             groupid is a string in pve-groupid format
690              
691             =head2 update_access_groups
692              
693             Updates (sets) a access group's data
694              
695             $ok = $obj->update_access_groups( 'groupid', %args );
696             $ok = $obj->update_access_groups( 'groupid', \%args );
697              
698             groupid is a string in pve-groupid format
699              
700             I<%args> may items contain from the following list
701              
702             =over 4
703              
704             =item comment
705              
706             String. This is a comment associated with the group, this is optional.
707              
708             =back
709              
710             =head2 delete_access_groups
711              
712             Deletes a single access group
713              
714             $ok = $obj->delete_access_groups('groupid')
715              
716             groupid is a string in pve-groupid format
717              
718             =head2 access_roles
719              
720             Gets a list of access roles (aka the Role index)
721              
722             @pools = $obj->access_roles();
723              
724             Note: Accessible by all authententicated users.
725              
726             =head2 create_access_roles
727              
728             Creates a new access role
729              
730             $ok = $obj->create_access_roles( %args );
731             $ok = $obj->create_access_roles( \%args );
732              
733             I<%args> may items contain from the following list
734              
735             =over 4
736              
737             =item roleid
738              
739             String. The id of the access role you wish to add, in pve-roleid format. This is required.
740              
741             =item privs
742              
743             String. A string in pve-string-list format. Optional.
744              
745             =back
746              
747             =head2 get_access_roles
748              
749             Gets a single access role
750              
751             $ok = $obj->get_access_roles('roleid')
752              
753             roleid is a string in pve-roleid format
754              
755             =head2 update_access_roles
756              
757             Updates (sets) a access role's data
758              
759             $ok = $obj->update_access_roles( 'roleid', %args );
760             $ok = $obj->update_access_roles( 'roleid', \%args );
761              
762             roleid is a string in pve-roleid format
763              
764             I<%args> may items contain from the following list
765              
766             =over 4
767              
768             =item privs
769              
770             String. A string in pve-priv-list format, this is required.
771              
772             =item append
773              
774             Booelean. Append privileges to existing. Optional.
775              
776             =back
777              
778             =head2 delete_access_roles
779              
780             Deletes a single access role
781              
782             $ok = $obj->delete_access_roles('roleid')
783              
784             roleid is a string in pve-roleid format
785              
786             =head2 access_users
787              
788             Gets a list of users (aka the User index)
789              
790             @pools = $obj->access_users();
791              
792             Note: You need 'Realm.AllocateUser' on '/access/realm/<>' on the realm of user <>, and 'User.Modify' permissions to '/access/groups/<>' for any group specified (or 'User.Modify' on '/access/groups' if you pass no groups.
793              
794             =head2 create_access_users
795              
796             Creates a new user
797              
798             $ok = $obj->create_access_users( %args );
799             $ok = $obj->create_access_users( \%args );
800              
801             I<%args> may items contain from the following list
802              
803             =over 4
804              
805             =item userid
806              
807             String. The id of the user you wish to add, in pve-userid format. This is required.
808              
809             =item comment
810              
811             String. This is a comment associated with the new user, this is optional.
812              
813             =item email
814              
815             String. The users email address in email-opt format. Optional.
816              
817             =item enable
818              
819             Boolean. If the user is enabled where the default is to be enabled. Disable with a 0 value. Optional.
820              
821             =item expire
822              
823             Integer. Account expiration date in seconds since epoch. 0 means never expire. Optional.
824              
825             =item firstname
826              
827             String. Optional.
828              
829             =item groups
830              
831             String. A string in pve-groupid-list format. Optional.
832              
833             =item lastname
834              
835             String. Optional.
836              
837             =item password
838              
839             String. The users initial passowrd. Optional.
840              
841             =back
842              
843             =head2 get_access_users
844              
845             Gets a single user
846              
847             $ok = $obj->get_access_users('userid')
848              
849             userid is a string in pve-userid format
850              
851             =head2 update_access_users
852              
853             Updates (sets) a user's configuration
854              
855             $ok = $obj->update_access_users( 'userid', %args );
856             $ok = $obj->update_access_users( 'userid', \%args );
857              
858             userid is a string in pve-userid format
859              
860             I<%args> may items contain from the following list
861              
862             =over 4
863              
864             =item append
865              
866             Boolean. Optional.
867              
868             =item comment
869              
870             String. This is a comment associated with the user, this is optional.
871              
872             =item email
873              
874             String. The users email address in email-opt format. Optional.
875              
876             =item enable
877              
878             Boolean. If the user is enabled where the default is to be enabled. Disable with a 0 value. Optional.
879              
880             =item expire
881              
882             Integer. Account expiration date in seconds since epoch. 0 means never expire. Optional.
883              
884             =item firstname
885              
886             String. Optional.
887              
888             =item groups
889              
890             String. A string in pve-groupid-list format. Optional.
891              
892             =item lastname
893              
894             String. Optional.
895              
896             =back
897              
898             =head2 delete_access_users
899              
900             Deletes a single user
901              
902             $ok = $obj->delete_access_users('userid')
903              
904             userid is a string in pve-userid format
905              
906             =head2 check_login_ticket
907              
908             Verifies if the objects login ticket is valid and not expired
909              
910             Returns true if valid
911             Returns false and clears the the login ticket details inside the object if invalid
912              
913             =head2 clear_login_ticket
914              
915             Clears the login ticket inside the object
916              
917             =head2 get_access_acl
918              
919             The returned list is restricted to objects where you have rights to modify permissions
920              
921             $pool = $obj->get_access_acl();
922              
923             Note: The returned list is restricted to objects where you have rights to modify permissions.
924              
925             =head2 login
926              
927             Initiates the log in to the PVE Server using JSON API, and potentially obtains an Access Ticket.
928              
929             Returns true if success
930              
931             =head2 update_access_acl
932              
933             Updates (sets) an acl's data
934              
935             $ok = $obj->update_access_acl( %args );
936             $ok = $obj->update_access_acl( \%args );
937              
938             I<%args> may items contain from the following list
939              
940             =over 4
941              
942             =item path
943              
944             String. Access control path. Required.
945              
946             =item roles
947              
948             String. List of roles. Required.
949              
950             =item delete
951              
952             Boolean. Removes the access rather than adding it. Optional.
953              
954             =item groups
955              
956             String. List of groups. Optional.
957              
958             =item propagate
959              
960             Boolean. Allow to propagate (inherit) permissions. Optional.
961              
962             =item users
963              
964             String. List of users. Optional.
965              
966             =back
967              
968             =head2 update_access_password
969              
970             Updates a users password
971              
972             $ok = $obj->update_password( %args );
973             $ok = $obj->update_password( \%args );
974              
975             Each user is allowed to change his own password. See proxmox api document for which permissions are needed to change the passwords of other people.
976              
977             I<%args> may items contain from the following list
978              
979             =over 4
980              
981             =item password
982              
983             String. The new password. Required.
984              
985             =item userid
986              
987             String. User ID. Required.
988              
989             =back
990              
991             Note: Each user is allowed to change his own password. A user can change the password of another user if he has 'Realm.AllocateUser' (on the realm of user <>) and 'User.Modify' permission on /access/groups/<> on a group where user <> is member of.
992              
993             =head1 SEE ALSO
994              
995             L
996              
997             =head1 AUTHOR
998              
999             Brendan Beveridge , Dean Hamstead
1000              
1001             =head1 COPYRIGHT AND LICENSE
1002              
1003             This software is Copyright (c) 2022 by Dean Hamstad.
1004              
1005             This is free software, licensed under:
1006              
1007             The MIT (X11) License
1008              
1009             =cut
1010              
1011             __END__