File Coverage

blib/lib/Net/Amazon/IAM.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package Net::Amazon::IAM;
2 1     1   12810 use Moose;
  1         286586  
  1         6  
3              
4 1     1   5277 use URI;
  1         2798  
  1         24  
5 1     1   5 use Carp;
  1         5  
  1         54  
6 1     1   585 use JSON;
  1         7442  
  1         3  
7 1     1   480 use URI::Encode;
  1         14540  
  1         40  
8 1     1   183 use XML::Simple;
  0            
  0            
9             use POSIX qw(strftime);
10             use LWP::UserAgent;
11             use LWP::Protocol::https;
12             use Data::Dumper qw(Dumper);
13             use Params::Validate qw(validate SCALAR ARRAYREF HASHREF);
14             use HTTP::Request::Common;
15             use AWS::Signature4;
16              
17             use Net::Amazon::IAM::Error;
18             use Net::Amazon::IAM::Errors;
19             use Net::Amazon::IAM::User;
20             use Net::Amazon::IAM::Users;
21             use Net::Amazon::IAM::Policy;
22             use Net::Amazon::IAM::Policies;
23             use Net::Amazon::IAM::UserPolicy;
24             use Net::Amazon::IAM::Group;
25             use Net::Amazon::IAM::Groups;
26             use Net::Amazon::IAM::GetGroupResult;
27             use Net::Amazon::IAM::AccessKey;
28             use Net::Amazon::IAM::AccessKeyMetadata;
29             use Net::Amazon::IAM::AccessKeysList;
30             use Net::Amazon::IAM::Role;
31             use Net::Amazon::IAM::Roles;
32             use Net::Amazon::IAM::VirtualMFADevice;
33             use Net::Amazon::IAM::VirtualMFADevices;
34             use Net::Amazon::IAM::MFADevice;
35             use Net::Amazon::IAM::MFADevices;
36             use Net::Amazon::IAM::InstanceProfile;
37             use Net::Amazon::IAM::InstanceProfiles;
38             use Net::Amazon::IAM::LoginProfile;
39              
40             our $VERSION = '0.04';
41              
42             =head1 NAME
43              
44             Net::Amazon::IAM - Perl interface to the Amazon Identity and Access Management.
45              
46             =head1 VERSION
47              
48             This is Net::Amazon::IAM version 0.04
49              
50             IAM Query API version: '2010-05-08'
51              
52             =head1 SYNOPSIS
53              
54             use Net::Amazon::IAM;
55              
56             my $iam = Net::Amazon::IAM->new(
57             AWSAccessKeyId => 'PUBLIC_KEY_HERE',
58             SecretAccessKey => 'SECRET_KEY_HERE'
59             );
60              
61             # create new user
62             my $user = $iam->create_user (
63             UserName => 'testuser',
64             Path => '/path/to/test/user/',
65             );
66              
67             # delete user
68             my $delete = $iam->delete_user(UserName => 'testuser');
69             if($delete->isa("Net::Amazon::IAM::Error")) {
70             print Dumper $delete;
71             }else{
72             print "User was successfuly deleted\n";
73             }
74              
75             # prepare user policy document
76             my $policy_document = {
77             Version => '2012-10-17',
78             Statement => [
79             {
80             Effect => 'Allow',
81             Action => [
82             's3:Get*',
83             's3:List*',
84             ],
85             Resource => [
86             'arn:aws:s3:::sometestbucket',
87             'arn:aws:s3:::sometestbucket/*',
88             ],
89             },
90             ],
91             };
92              
93             # attach the document to the user
94             my $policy = $iam->put_user_policy (
95             PolicyName => 'somtestpolicy',
96             UserName => 'sometestuser',
97             PolicyDocument => $policy_document,
98             );
99              
100             if($policy->isa("Net::Amazon::IAM::Error")) {
101             print Dumper $policy;
102             }else{
103             print "Policy was added\n";
104             }
105              
106              
107             If an error occurs while communicating with IAM, these methods will
108             throw a L<Net::Amazon::IAM::Error> exception.
109              
110             =head1 DESCRIPTION
111              
112             This module is a Perl interface to Amazon's Identity and Access Management (IAM). It uses the Query API to
113             communicate with Amazon's Web Services framework.
114              
115             =head1 CLASS METHODS
116              
117             =head2 new(%params)
118              
119             This is the constructor, it will return you a Net::Amazon::IAM object to work with. It takes
120             these parameters:
121              
122             =over
123              
124             =item AWSAccessKeyId (required)
125              
126             Your AWS access key.
127              
128             =item SecretAccessKey (required)
129              
130             Your secret key, B<WARNING!> don't give this out or someone will be able to use your account
131             and incur charges on your behalf.
132              
133             =item debug (optional)
134              
135             A flag to turn on debugging. Among other useful things, it will make the failing api calls print
136             a stack trace. It is turned off by default.
137              
138             =item return_errors (optional)
139              
140             A flag to enable returning errors as objects instead of throwing them as exceptions.
141              
142             =back
143              
144             =cut
145              
146             has 'AWSAccessKeyId' => (
147             is => 'ro',
148             isa => 'Str',
149             lazy => 1,
150             default => sub {
151             if (defined($_[0]->temp_creds)) {
152             return $_[0]->temp_creds->{'AccessKeyId'};
153             } else {
154             return undef;
155             }
156             }
157             );
158              
159             has 'SecretAccessKey' => (
160             is => 'ro',
161             isa => 'Str',
162             lazy => 1,
163             default => sub {
164             if (defined($_[0]->temp_creds)) {
165             return $_[0]->temp_creds->{'SecretAccessKey'};
166             } else {
167             return undef;
168             }
169             }
170             );
171              
172             has 'SecurityToken' => (
173             is => 'ro',
174             isa => 'Str',
175             lazy => 1,
176             predicate => 'has_SecurityToken',
177             default => sub {
178             if (defined($_[0]->temp_creds)) {
179             return $_[0]->temp_creds->{'Token'};
180             } else {
181             return undef;
182             }
183             }
184             );
185              
186             has 'base_url' => (
187             is => 'ro',
188             isa => 'Str',
189             lazy => 1,
190             default => sub {
191             return 'http' . ($_[0]->ssl ? 's' : '') . '://iam.amazonaws.com';
192             }
193             );
194              
195             has 'temp_creds' => (
196             is => 'ro',
197             lazy => 1,
198             predicate => 'has_temp_creds',
199             default => sub {
200             my $ret;
201             $ret = $_[0]->_fetch_iam_security_credentials();
202             },
203             );
204              
205             has 'debug' => ( is => 'ro', isa => 'Str', default => 0 );
206             has 'version' => ( is => 'ro', isa => 'Str', default => '2010-05-08' );
207             has 'ssl' => ( is => 'ro', isa => 'Bool', default => 1 );
208             has 'return_errors' => ( is => 'ro', isa => 'Bool', default => 0 );
209              
210             sub _timestamp {
211             return strftime("%Y-%m-%dT%H:%M:%SZ",gmtime);
212             }
213              
214             sub _fetch_iam_security_credentials {
215             my $self = shift;
216             my $retval = {};
217              
218             my $ua = LWP::UserAgent->new();
219             # Fail quickly if this is not running on an EC2 instance
220             $ua->timeout(2);
221              
222             my $url = 'http://169.254.169.254/latest/meta-data/iam/security-credentials/';
223              
224             $self->_debug("Attempting to fetch instance credentials");
225              
226             my $res = $ua->get($url);
227             if ($res->code == 200) {
228             # Assumes the first profile is the only profile
229             my $profile = (split /\n/, $res->content())[0];
230              
231             $res = $ua->get($url . $profile);
232              
233             if ($res->code == 200) {
234             $retval->{'Profile'} = $profile;
235             foreach (split /\n/, $res->content()) {
236             return undef if /Code/ && !/Success/;
237             if (m/.*"([^"]+)"\s+:\s+"([^"]+)",/) {
238             $retval->{$1} = $2;
239             }
240             }
241              
242             return $retval if (keys %{$retval});
243             }
244             }
245              
246             return undef;
247             }
248              
249             sub _sign {
250             my $self = shift;
251             my %args = @_;
252             my $action = delete $args{'Action'};
253             my %sign_hash = %args;
254             my $timestamp = $self->_timestamp;
255              
256             $sign_hash{'Action'} = $action;
257             $sign_hash{'Version'} = $self->version;
258              
259             if ($self->has_temp_creds || $self->has_SecurityToken) {
260             $sign_hash{'SecurityToken'} = $self->SecurityToken;
261             }
262              
263             my $signer = AWS::Signature4->new(
264             -access_key => $self->{'AWSAccessKeyId'},
265             -secret_key => $self->{'SecretAccessKey'},
266             );
267              
268             my $ua = LWP::UserAgent->new();
269              
270             my $request = POST(
271             $self->base_url,
272             [
273             %sign_hash,
274             ],
275             );
276              
277             $signer->sign($request);
278              
279             my $res = $ua->request($request);
280              
281             # We should force <item> elements to be in an array
282             my $xs = XML::Simple->new(
283             ForceArray => qr/(?:item|Errors)/i, # Always want item elements unpacked to arrays
284             KeyAttr => '', # Turn off folding for 'id', 'name', 'key' elements
285             SuppressEmpty => undef, # Turn empty values into explicit undefs
286             );
287             my $xml;
288              
289             # Check the result for connectivity problems, if so throw an error
290             if ($res->code >= 500) {
291             my $message = $res->status_line;
292             $xml = <<EOXML;
293             <xml>
294             <RequestID>N/A</RequestID>
295             <Errors>
296             <Error>
297             <Code>HTTP POST FAILURE</Code>
298             <Message>$message</Message>
299             </Error>
300             </Errors>
301             </xml>
302             EOXML
303              
304             } else {
305             $xml = $res->content();
306             }
307              
308             my $ref = $xs->XMLin($xml);
309             warn Dumper($ref) . "\n\n" if $self->debug == 1;
310              
311             return $ref;
312             }
313              
314             sub _parse_errors {
315             my $self = shift;
316             my $errors_xml = shift;
317              
318             my $es;
319             my $request_id = $errors_xml->{'RequestId'};
320              
321             my $error = Net::Amazon::IAM::Error->new(
322             code => $errors_xml->{'Error'}{'Code'},
323             message => $errors_xml->{'Error'}{'Message'},
324             request_id => $request_id,
325             );
326              
327             if ($self->return_errors) {
328             return $error;
329             }
330              
331             # Print a stack trace if debugging is enabled
332             if ($self->debug) {
333             confess 'Last error was: ' . $error->message;
334             }else{
335             croak $error;
336             }
337             }
338              
339             sub _debug {
340             my $self = shift;
341             my $message = shift;
342              
343             if ((grep { defined && length} $self->debug) && $self->debug == 1) {
344             print "$message\n\n\n\n";
345             }
346             }
347              
348             sub _build_filters {
349             my ($self, $args) = @_;
350              
351             my $filters = delete $args->{Filter};
352              
353             return unless $filters && ref($filters) eq 'ARRAY';
354              
355             $filters = [ $filters ] unless ref($filters->[0]) eq 'ARRAY';
356             my $count = 1;
357             foreach my $filter (@{$filters}) {
358             my ($name, @args) = @$filter;
359             $args->{"Filter." . $count.".Name"} = $name;
360             $args->{"Filter." . $count.".Value.".$_} = $args[$_-1] for 1..scalar @args;
361             $count++;
362             }
363             }
364              
365             sub _parse_attributes {
366             my $self = shift;
367             my $single_object = shift;
368             my $list_objects = shift;
369             my %result = @_;
370              
371             my $attributes;
372             if ( grep { defined && length } $result{$list_objects}{'member'} ) {
373             if(ref($result{$list_objects}{'member'}) eq 'ARRAY') {
374             for my $attr(@{$result{$list_objects}{'member'}}) {
375             my $a = "Net::Amazon::IAM::$single_object"->new(
376             $attr,
377             );
378             push @$attributes, $a;
379             }
380             }else{
381             my $a = "Net::Amazon::IAM::$single_object"->new(
382             $result{$list_objects}{'member'},
383             );
384             push @$attributes, $a;
385             }
386             }else{
387             $attributes = [];
388             }
389              
390             return $attributes;
391             }
392              
393             =head2 create_user(%params)
394              
395             Create new IAM user
396              
397             =over
398              
399             =item UserName (required)
400              
401             New user username
402              
403             =item Path (optional)
404              
405             Where to create new user
406              
407             =back
408              
409             Returns a Net::Amazon::IAM::User object on success or Net::Amazon::IAM::Error on fail.
410              
411             =cut
412              
413             sub create_user {
414             my $self = shift;
415              
416             my %args = validate(@_, {
417             UserName => { type => SCALAR },
418             Path => { type => SCALAR, optional => 1 },
419             });
420              
421             my $xml = $self->_sign(Action => 'CreateUser', %args);
422              
423             if ( grep { defined && length } $xml->{'Error'} ) {
424             return $self->_parse_errors($xml);
425             } else {
426             return Net::Amazon::IAM::User->new(
427             $xml->{'CreateUserResult'}{'User'},
428             );
429             }
430             }
431              
432             =head2 delete_user(%params)
433              
434             Delete IAM User
435              
436             =over
437              
438             =item UserName (required)
439              
440             What user should be deleted
441              
442             =back
443              
444             Returns true on success or Net::Amazon::IAM::Error on fail.
445              
446             =cut
447              
448             sub delete_user {
449             my $self = shift;
450              
451             my %args = validate(@_, {
452             UserName => { type => SCALAR },
453             });
454              
455             my $xml = $self->_sign(Action => 'DeleteUser', %args);
456              
457             if ( grep { defined && length } $xml->{'Error'} ) {
458             return $self->_parse_errors($xml);
459             } else {
460             return 1;
461             }
462             }
463              
464             =head2 get_user(%params)
465              
466             Get IAM user details
467              
468             =over
469              
470             =item UserName (required)
471              
472             New user username
473              
474             =back
475              
476             Returns a Net::Amazon::IAM::User object on success or Net::Amazon::IAM::Error on fail.
477              
478             =cut
479              
480             sub get_user {
481             my $self = shift;
482              
483             my %args = validate(@_, {
484             UserName => { type => SCALAR },
485             });
486              
487             my $xml = $self->_sign(Action => 'GetUser', %args);
488              
489             if ( grep { defined && length } $xml->{'Error'} ) {
490             return $self->_parse_errors($xml);
491             } else {
492             return Net::Amazon::IAM::User->new(
493             $xml->{'GetUserResult'}{'User'},
494             );
495             }
496             }
497              
498             =head2 update_user(%params)
499              
500             Updates the name and/or the path of the specified user.
501              
502             =over
503              
504             =item UserName (required)
505              
506             Name of the user to update. If you're changing the name of the user, this is the original user name.
507              
508             =item NewPath (optional)
509              
510             New path for the user. Include this parameter only if you're changing the user's path.
511              
512             =item NewUserName (optional)
513              
514             New name for the user. Include this parameter only if you're changing the user's name.
515              
516             =back
517              
518             Returns true on success or Net::Amazon::IAM::Error on fail.
519              
520             =cut
521              
522             sub update_user {
523             my $self = shift;
524              
525             my %args = validate(@_, {
526             UserName => { type => SCALAR },
527             NewPath => { type => SCALAR, optional => 1 },
528             NewUserName => { type => SCALAR, optional => 1 },
529             });
530              
531             my $xml = $self->_sign(Action => 'UpdateUser', %args);
532              
533             if ( grep { defined && length } $xml->{'Error'} ) {
534             return $self->_parse_errors($xml);
535             } else {
536             return 1;
537             }
538             }
539              
540             =head2 list_users(%params)
541              
542             Lists the IAM users that have the specified path prefix.
543             If no path prefix is specified, the action returns all users in the AWS account.
544              
545             =over
546              
547             =item Marker (required)
548              
549             Use this parameter only when paginating results, and only in a subsequent request
550             after you've received a response where the results are truncated. Set it to the
551             value of the Marker element in the response you just received.
552              
553             =item MaxItems (optional)
554              
555             Use this parameter only when paginating results to indicate the maximum number of
556             user names you want in the response. If there are additional user names beyond the
557             maximum you specify, the IsTruncated response element is true. This parameter is
558             optional. If you do not include it, it defaults to 100.
559              
560             =item PathPrefix (optional)
561              
562             The path prefix for filtering the results. For example:
563             /division_abc/subdivision_xyz/, which would get all user
564             names whose path starts with /division_abc/subdivision_xyz/.
565              
566             =back
567              
568             Returns Net::Amazon::IAM::Users object on success or Net::Amazon::IAM::Error on fail.
569              
570             =cut
571              
572             sub list_users {
573             my $self = shift;
574              
575             my %args = validate(@_, {
576             Marker => { type => SCALAR, optional => 1 },
577             MaxItems => { type => SCALAR, optional => 1 },
578             PathPrefix => { type => SCALAR, optional => 1 },
579             });
580              
581             my $xml = $self->_sign(Action => 'ListUsers', %args);
582              
583             if ( grep { defined && length } $xml->{'Error'} ) {
584             return $self->_parse_errors($xml);
585             } else {
586             my %result = %{$xml->{'ListUsersResult'}};
587             my $users = $self->_parse_attributes('User', 'Users', %result);
588              
589             return Net::Amazon::IAM::Users->new(
590             Users => $users,
591             IsTruncated => $result{'IsTruncated'},
592             Marker => $result{'Marker'},
593             );
594             }
595             }
596              
597             =head2 add_user_to_group(%params)
598              
599             Adds the specified user to the specified group.
600              
601             =over
602              
603             =item GroupName (required)
604              
605             The name of the group to update.
606              
607             =item UserName (required)
608              
609             The name of the user to add.
610              
611             =back
612              
613             Returns true on success or Net::Amazon::IAM::Error on fail.
614              
615             =cut
616              
617             sub add_user_to_group {
618             my $self = shift;
619              
620             my %args = validate(@_, {
621             GroupName => { type => SCALAR },
622             UserName => { type => SCALAR },
623             });
624              
625             my $xml = $self->_sign(Action => 'AddUserToGroup', %args);
626              
627             if ( grep { defined && length } $xml->{'Error'} ) {
628             return $self->_parse_errors($xml);
629             } else {
630             return 1;
631             }
632             }
633              
634             =head2 remove_user_from_group(%params)
635              
636             Removes the specified user from the specified group.
637              
638             =over
639              
640             =item GroupName (required)
641              
642             The name of the group to update.
643              
644             =item UserName (required)
645              
646             The name of the user to remove.
647              
648             =back
649              
650             Returns true on success or Net::Amazon::IAM::Error on fail.
651              
652             =cut
653              
654             sub remove_user_from_group {
655             my $self = shift;
656              
657             my %args = validate(@_, {
658             GroupName => { type => SCALAR },
659             UserName => { type => SCALAR },
660             });
661              
662             my $xml = $self->_sign(Action => 'RemoveUserFromGroup', %args);
663              
664             if ( grep { defined && length } $xml->{'Error'} ) {
665             return $self->_parse_errors($xml);
666             } else {
667             return 1;
668             }
669             }
670              
671             =head2 create_group(%params)
672              
673             Creates a new group.
674              
675             =over
676              
677             =item GroupName (required)
678              
679             The name of the group to create.
680              
681             =item Path (optional)
682              
683             The path to the group.
684              
685             =back
686              
687             Returns Net::Amazon::IAM::Group object on success or Net::Amazon::IAM::Error on fail.
688              
689             =cut
690              
691             sub create_group {
692             my $self = shift;
693              
694             my %args = validate(@_, {
695             GroupName => { type => SCALAR },
696             Path => { type => SCALAR, optional => 1 },
697             });
698              
699             my $xml = $self->_sign(Action => 'CreateGroup', %args);
700              
701             if ( grep { defined && length } $xml->{'Error'} ) {
702             return $self->_parse_errors($xml);
703             } else {
704             return Net::Amazon::IAM::Group->new(
705             $xml->{'CreateGroupResult'}{'User'},
706             );
707             }
708             }
709              
710             =head2 get_group(%params)
711              
712             Returns group details and list of users that are in the specified group.
713              
714             =over
715              
716             =item GroupName (required)
717              
718             The name of the group.
719              
720             =item MaxItems (optional)
721              
722             Use this only when paginating results to indicate the maximum number of
723             groups you want in the response. If there are additional groups beyond the
724             maximum you specify, the IsTruncated response element is true. This parameter is optional.
725             If you do not include it, it defaults to 100.
726              
727             =item Marker (optional)
728              
729             Use this only when paginating results, and only in a subsequent request
730             after you've received a response where the results are truncated.
731             Set it to the value of the Marker element in the response you just received.
732              
733             =back
734              
735             Returns Net::Amazon::IAM::GetGroupResult object on success or Net::Amazon::IAM::Error on fail.
736              
737             =cut
738              
739             sub get_group {
740             my $self = shift;
741              
742             my %args = validate(@_, {
743             GroupName => { type => SCALAR },
744             Marker => { type => SCALAR, optional => 1 },
745             MaxItems => { type => SCALAR, optional => 1 },
746             });
747              
748             my $xml = $self->_sign(Action => 'GetGroup', %args);
749              
750             if ( grep { defined && length } $xml->{'Error'} ) {
751             return $self->_parse_errors($xml);
752             } else {
753             my %result = %{$xml->{'GetGroupResult'}};
754             my $users = $self->_parse_attributes('User', 'Users', %result);
755              
756             my $group = Net::Amazon::IAM::Group->new(
757             %{$result{'Group'}},
758             );
759              
760             return Net::Amazon::IAM::GetGroupResult->new(
761             IsTruncated => $result{'IsTruncated'},
762             Marker => $result{'Marker'},
763             Users => $users,
764             Group => $group,
765             );
766             }
767             }
768              
769             =head2 delete_group(%params)
770              
771             Deletes the specified group. The group must not contain any users or have any attached policies.
772              
773             =over
774              
775             =item GroupName (required)
776              
777             The name of the group to delete.
778              
779             =back
780              
781             Returns true on success or Net::Amazon::IAM::Error on fail.
782              
783             =cut
784              
785             sub delete_group {
786             my $self = shift;
787              
788             my %args = validate(@_, {
789             GroupName => { type => SCALAR },
790             });
791              
792             my $xml = $self->_sign(Action => 'DeleteGroup', %args);
793              
794             if ( grep { defined && length } $xml->{'Error'} ) {
795             return $self->_parse_errors($xml);
796             } else {
797             return 1;
798             }
799             }
800              
801             =head2 list_groups(%params)
802              
803             Lists the groups that have the specified path prefix.
804              
805             =over
806              
807             =item Marker (optional)
808              
809             Use this only when paginating results, and only in a subsequent request after
810             you've received a response where the results are truncated. Set it to the value
811             of the Marker element in the response you just received.
812              
813             =item MaxItems (optional)
814              
815             Use this only when paginating results to indicate the maximum number of groups
816             you want in the response. If there are additional groups beyond the maximum you specify,
817             the IsTruncated response element is true. This parameter is optional. If you do not include
818             it, it defaults to 100.
819              
820             =item PathPrefix (optional)
821              
822             The path prefix for filtering the results. For example, the prefix /division_abc/subdivision_xyz/
823             gets all groups whose path starts with /division_abc/subdivision_xyz/.
824              
825             =back
826              
827             Returns Net::Amazon::IAM::Groups object on success or Net::Amazon::IAM::Error on fail.
828              
829             =cut
830              
831             sub list_groups {
832             my $self = shift;
833              
834             my %args = validate(@_, {
835             Marker => { type => SCALAR, optional => 1 },
836             MaxItems => { type => SCALAR, optional => 1 },
837             PathPrefix => { type => SCALAR, optional => 1 },
838             });
839              
840             my $xml = $self->_sign(Action => 'ListGroups', %args);
841              
842             if ( grep { defined && length } $xml->{'Error'} ) {
843             return $self->_parse_errors($xml);
844             } else {
845             my %result = %{$xml->{'ListGroupsResult'}};
846             my $groups = $self->_parse_attributes('Group', 'Groups', %result);
847              
848             return Net::Amazon::IAM::Groups->new(
849             Groups => $groups,
850             IsTruncated => $result{'IsTruncated'},
851             Marker => $result{'Marker'},
852             );
853             }
854             }
855              
856             =head2 create_policy(%params)
857              
858             Creates a new managed policy for your AWS account.
859              
860             =over
861              
862             =item PolicyName (required)
863              
864             The name of the policy document.
865              
866             =item PolicyDocument (required)
867              
868             The policy document.
869              
870             =item Description (optional)
871              
872             A friendly description of the policy.
873              
874             =item Path (optional)
875              
876             The path for the policy.
877              
878             =back
879              
880             Returns Net::Amazon::IAM::Policy object on success or Net::Amazon::IAM::Error on fail.
881              
882             =cut
883              
884             sub create_policy {
885             my $self = shift;
886              
887             my %args = validate(@_, {
888             PolicyName => { type => SCALAR },
889             PolicyDocument => { type => HASHREF },
890             Description => { type => SCALAR, optional => 1 },
891             Path => { type => SCALAR, optional => 1 },
892             });
893              
894             $args{'PolicyDocument'} = encode_json delete $args{'PolicyDocument'};
895              
896             my $xml = $self->_sign(Action => 'CreatePolicy', %args);
897              
898             if ( grep { defined && length } $xml->{'Error'} ) {
899             return $self->_parse_errors($xml);
900             } else {
901             return Net::Amazon::IAM::Policy->new(
902             $xml->{'CreatePolicyResult'}{'Policy'},
903             );
904             }
905             }
906              
907             =head2 get_policy(%params)
908              
909             Retrieves information about the specified managed policy.
910              
911             =over
912              
913             =item PolicyArn (required)
914              
915             The Amazon Resource Name (ARN). ARNs are unique identifiers for AWS resources.
916              
917             =back
918              
919             Returns Net::Amazon::IAM::Policy object on success or Net::Amazon::IAM::Error on fail.
920              
921             =cut
922              
923             sub get_policy {
924             my $self = shift;
925              
926             my %args = validate(@_, {
927             PolicyArn => { type => SCALAR },
928             });
929              
930             my $xml = $self->_sign(Action => 'GetPolicy', %args);
931              
932             if ( grep { defined && length } $xml->{'Error'} ) {
933             return $self->_parse_errors($xml);
934             } else {
935             return Net::Amazon::IAM::Policy->new(
936             $xml->{'GetPolicyResult'}{'Policy'},
937             );
938             }
939             }
940              
941             =head2 delete_policy(%params)
942              
943             Deletes the specified managed policy.
944              
945             =over
946              
947             =item PolicyArn (required)
948              
949             The Amazon Resource Name (ARN). ARNs are unique identifiers for AWS resources.
950              
951             =back
952              
953             Returns true on success or Net::Amazon::IAM::Error on fail.
954              
955             =cut
956              
957             sub delete_policy {
958             my $self = shift;
959              
960             my %args = validate(@_, {
961             PolicyArn => { type => SCALAR },
962             });
963              
964             my $xml = $self->_sign(Action => 'DeletePolicy', %args);
965              
966             if ( grep { defined && length } $xml->{'Error'} ) {
967             return $self->_parse_errors($xml);
968             } else {
969             return 1;
970             }
971             }
972              
973             =head2 list_policies(%params)
974              
975             Lists all the managed policies that are available to your account,
976             including your own customer managed policies and all AWS managed policies.
977              
978             You can filter the list of policies that is returned using the optional
979             OnlyAttached, Scope, and PathPrefix parameters. For example, to list only the
980             customer managed policies in your AWS account, set Scope to Local.
981             To list only AWS managed policies, set Scope to AWS.
982              
983             =over
984              
985             =item OnlyAttached (optional)
986              
987             A flag to filter the results to only the attached policies.
988             When OnlyAttached is true, the returned list contains only the
989             policies that are attached to a user, group, or role.
990             When OnlyAttached is false, or when the parameter is not
991             included, all policies are returned.
992              
993             =item PathPrefix (optional)
994              
995             The path prefix for filtering the results.
996             If it is not included, it defaults to a slash (/), listing all policies.
997              
998             =item Scope (optional)
999              
1000             The scope to use for filtering the results.
1001              
1002             To list only AWS managed policies, set Scope to AWS.
1003             To list only the customer managed policies in your AWS account, set Scope to Local.
1004             If it is not included, or if it is set to All, all policies are returned.
1005              
1006             =item MaxItems (optional)
1007              
1008             Maximum number of policies to retrieve.
1009              
1010             =item Marker (optional)
1011              
1012             If IsTruncated is true, this element is present and contains the value to use for the
1013             Marker parameter in a subsequent pagination request.
1014              
1015             Example:
1016             my $policies = $iam->list_policies(
1017             MaxItems => 1
1018             );
1019              
1020             while($policies->IsTruncated eq 'true') {
1021             for my $policy(@{$policies->{'Policies'}}) {
1022             print $policy->PolicyId . "\n";
1023             }
1024              
1025             $policies = $iam->list_policies(
1026             MaxItems => 50,
1027             Marker => $policies->Marker,
1028             );
1029             }
1030              
1031             =back
1032              
1033             Returns Net::Amazon::IAM::Policies on success or Net::Amazon::IAM::Error on fail.
1034             When no policies found, the Policies attribute will be just empty array.
1035              
1036             =cut
1037              
1038             sub list_policies {
1039             my $self = shift;
1040              
1041             my %args = validate(@_, {
1042             Marker => { type => SCALAR, optional => 1 },
1043             MaxItems => { type => SCALAR, optional => 1 },
1044             PathPrefix => { type => SCALAR, optional => 1, default => '/' },
1045             OnlyAttached => { regex => qr/true|false/, optional => 1, default => 'false' },
1046             Scope => { regex => qr/AWS|Local|All/, optional => 1, default => 'All' },
1047             });
1048              
1049             my $xml = $self->_sign(Action => 'ListPolicies', %args);
1050              
1051             if ( grep { defined && length } $xml->{'Error'} ) {
1052             return $self->_parse_errors($xml);
1053             } else {
1054             my %result = %{$xml->{'ListPoliciesResult'}};
1055             my $policies = $self->_parse_attributes('Policy', 'Policies', %result);
1056              
1057             return Net::Amazon::IAM::Policies->new(
1058             Policies => $policies,
1059             IsTruncated => $result{'IsTruncated'},
1060             Marker => $result{'Marker'},
1061             );
1062             }
1063             }
1064              
1065             =head2 put_user_policy(%params)
1066              
1067             Deletes the specified managed policy.
1068              
1069             =over
1070              
1071             =item PolicyDocument (required)
1072              
1073             The policy document. Must be HashRef.
1074              
1075             =item PolicyName (required)
1076              
1077             The name of the policy document.
1078              
1079             =item UserName (required)
1080              
1081             The name of the user to associate the policy with.
1082              
1083             =back
1084              
1085             Returns true on success or Net::Amazon::IAM::Error on fail.
1086              
1087             =cut
1088              
1089             sub put_user_policy {
1090             my $self = shift;
1091              
1092             my %args = validate(@_, {
1093             PolicyDocument => { type => HASHREF },
1094             PolicyName => { type => SCALAR },
1095             UserName => { type => SCALAR },
1096             });
1097              
1098             $args{'PolicyDocument'} = encode_json delete $args{'PolicyDocument'};
1099              
1100             my $xml = $self->_sign(Action => 'PutUserPolicy', %args);
1101              
1102             if ( grep { defined && length } $xml->{'Error'} ) {
1103             return $self->_parse_errors($xml);
1104             } else {
1105             return 1;
1106             }
1107             }
1108              
1109             =head2 get_user_policy(%params)
1110              
1111             Retrieves the specified inline policy document that is embedded in the specified user.
1112              
1113             =over
1114              
1115             =item PolicyName (required)
1116              
1117             The name of the policy document to get.
1118              
1119             =item UserName (required)
1120              
1121             The name of the user who the policy is associated with.
1122              
1123             =back
1124              
1125             Returns Net::Amazon::IAM::UserPolicy object on success or Net::Amazon::IAM::Error on fail.
1126              
1127             =cut
1128              
1129             sub get_user_policy {
1130             my $self = shift;
1131              
1132             my %args = validate(@_, {
1133             PolicyName => { type => SCALAR },
1134             UserName => { type => SCALAR },
1135             });
1136              
1137             my $xml = $self->_sign(Action => 'GetUserPolicy', %args);
1138              
1139             if ( grep { defined && length } $xml->{'Error'} ) {
1140             return $self->_parse_errors($xml);
1141             } else {
1142             my $user_policy = Net::Amazon::IAM::UserPolicy->new(
1143             $xml->{'GetUserPolicyResult'}
1144             );
1145             $user_policy->{'PolicyDocument'} = decode_json(URI::Encode->new()->decode($user_policy->PolicyDocument));
1146             return $user_policy;
1147             }
1148             }
1149              
1150             =head2 delete_user_policy(%params)
1151              
1152             Deletes the specified inline policy that is embedded in the specified user.
1153              
1154             =over
1155              
1156             =item PolicyName (required)
1157              
1158             The name identifying the policy document to delete.
1159              
1160             =item UserName (required)
1161              
1162             The name (friendly name, not ARN) identifying the user that the policy is embedded in.
1163              
1164             =back
1165              
1166             Returns true on success or Net::Amazon::IAM::Error on fail.
1167              
1168             =cut
1169              
1170             sub delete_user_policy {
1171             my $self = shift;
1172              
1173             my %args = validate(@_, {
1174             PolicyName => { type => SCALAR },
1175             UserName => { type => SCALAR },
1176             });
1177              
1178             my $xml = $self->_sign(Action => 'DeleteUserPolicy', %args);
1179              
1180             if ( grep { defined && length } $xml->{'Error'} ) {
1181             return $self->_parse_errors($xml);
1182             } else {
1183             return 1;
1184             }
1185             }
1186              
1187             =head2 list_user_policies(%params)
1188              
1189             Lists the names of the inline policies embedded in the specified user.
1190              
1191             =over
1192              
1193             =item UserName (required)
1194              
1195             The name of the user to list policies for.
1196              
1197             =back
1198              
1199             When found one or more policies, this method will return ArrayRef with policy names.
1200             Once no policies found, will return undef;
1201             Net::Amazon::IAM::Error will be returned on error
1202              
1203             =cut
1204              
1205             sub list_user_policies {
1206             my $self = shift;
1207              
1208             my %args = validate(@_, {
1209             UserName => { type => SCALAR },
1210             Marker => { type => SCALAR, optional => 1 },
1211             MaxItems => { type => SCALAR, optional => 1 },
1212             });
1213              
1214             my $xml = $self->_sign(Action => 'ListUserPolicies', %args);
1215              
1216             if ( grep { defined && length } $xml->{'Error'} ) {
1217             return $self->_parse_errors($xml);
1218             } else {
1219             my $policies;
1220              
1221             my %result = %{$xml->{'ListUserPoliciesResult'}};
1222              
1223             if ( grep { defined && length } $result{'PolicyNames'} ) {
1224             if(ref($result{'PolicyNames'}{'member'}) eq 'ARRAY') {
1225             $policies = $result{'PolicyNames'}{'member'};
1226             }else{
1227             push @$policies, $result{'PolicyNames'}{'member'};
1228             }
1229             } else {
1230             $policies = undef;
1231             }
1232              
1233             return $policies;
1234             }
1235             }
1236              
1237             =head2 create_access_key(%params)
1238              
1239             Creates a new AWS secret access key and corresponding AWS access key ID for the specified user.
1240             The default status for new keys is Active.
1241             If you do not specify a user name, IAM determines the user name implicitly based on the AWS access
1242             key ID signing the request. Because this action works for access keys under the AWS account, you can use
1243             this action to manage root credentials even if the AWS account has no associated users.
1244              
1245             B<Important>:
1246              
1247             To ensure the security of your AWS account, the secret access key is accessible only during
1248             key and user creation. You must save the key (for example, in a text file) if you want to be
1249             able to access it again. If a secret key is lost, you can delete the access keys for the associated
1250             user and then create new keys.
1251              
1252             =over
1253              
1254             =item UserName (optional)
1255              
1256             The user name that the new key will belong to.
1257              
1258             =back
1259              
1260             Returns Net::Amazon::IAM::AccessKey object on success or Net::Amazon::IAM::Error on fail.
1261              
1262             =cut
1263              
1264             sub create_access_key {
1265             my $self = shift;
1266              
1267             my %args = validate(@_, {
1268             UserName => { type => SCALAR, optional => 1 },
1269             });
1270              
1271             my $xml = $self->_sign(Action => 'CreateAccessKey', %args);
1272              
1273             if ( grep { defined && length } $xml->{'Error'} ) {
1274             return $self->_parse_errors($xml);
1275             } else {
1276             return Net::Amazon::IAM::AccessKey->new(
1277             $xml->{'CreateAccessKeyResult'}{'AccessKey'},
1278             );
1279             }
1280             }
1281              
1282             =head2 delete_access_key(%params)
1283              
1284             Deletes the access key associated with the specified user.
1285              
1286             If you do not specify a user name, IAM determines the user name implicitly based
1287             on the AWS access key ID signing the request. Because this action works for access
1288             keys under the AWS account, you can use this action to manage root credentials even
1289             if the AWS account has no associated users.
1290              
1291             =over
1292              
1293             =item AccessKeyId (required)
1294              
1295             The access key ID for the access key ID and secret access key you want to delete.
1296              
1297             =item UserName (optional)
1298              
1299             The name of the user whose key you want to delete.
1300              
1301             =back
1302              
1303             Returns true on success or Net::Amazon::IAM::Error on fail.
1304              
1305             =cut
1306              
1307             sub delete_access_key {
1308             my $self = shift;
1309              
1310             my %args = validate(@_, {
1311             AccessKeyId => { type => SCALAR },
1312             UserName => { type => SCALAR, optional => 1 },
1313             });
1314              
1315             my $xml = $self->_sign(Action => 'DeleteAccessKey', %args);
1316              
1317             if ( grep { defined && length } $xml->{'Error'} ) {
1318             return $self->_parse_errors($xml);
1319             } else {
1320             return 1;
1321             }
1322             }
1323              
1324             =head2 update_access_key(%params)
1325              
1326             Changes the status of the specified access key from Active to Inactive, or vice versa.
1327             This action can be used to disable a user's key as part of a key rotation work flow.
1328              
1329             If the UserName field is not specified, the UserName is determined implicitly based
1330             on the AWS access key ID used to sign the request. Because this action works for access
1331             keys under the AWS account, you can use this action to manage root credentials even if
1332             the AWS account has no associated users.
1333              
1334             =over
1335              
1336             =item AccessKeyId (required)
1337              
1338             The access key ID of the secret access key you want to update.
1339              
1340             =item Status (required)
1341              
1342             The status you want to assign to the secret access key.
1343             Active means the key can be used for API calls to AWS, while Inactive
1344             means the key cannot be used.
1345              
1346             =item UserName (optional)
1347              
1348             The name of the user whose key you want to update.
1349              
1350             =back
1351              
1352             Returns true on success or Net::Amazon::IAM::Error on fail.
1353              
1354             =cut
1355              
1356             sub update_access_key {
1357             my $self = shift;
1358              
1359             my %args = validate(@_, {
1360             AccessKeyId => { type => SCALAR },
1361             Status => { regex => qr/Active|Inactive/ },
1362             UserName => { type => SCALAR, optional => 1 },
1363             });
1364              
1365             my $xml = $self->_sign(Action => 'UpdateAccessKey', %args);
1366              
1367             if ( grep { defined && length } $xml->{'Error'} ) {
1368             return $self->_parse_errors($xml);
1369             } else {
1370             return 1;
1371             }
1372             }
1373              
1374             =head2 list_access_keys(%params)
1375              
1376             Returns information about the access key IDs associated with the specified user.
1377             If the UserName field is not specified, the UserName is determined implicitly based on the AWS access
1378             key ID used to sign the request. Because this action works for access keys under the AWS account,
1379             you can use this action to manage root credentials even if the AWS account has no associated users.
1380              
1381             =over
1382              
1383             =item UserName (optional)
1384              
1385             The name of the user.
1386              
1387             =back
1388              
1389             Returns Net::Amazon::IAM::AccessKeysList on success.
1390             If specified user has no keys, "Keys" attribute of Net::Amazon::IAM::AccessKeysList object
1391             will be just empty array.
1392             Returns Net::Amazon::IAM::Error on fail.
1393              
1394             =cut
1395              
1396             sub list_access_keys {
1397             my $self = shift;
1398              
1399             my %args = validate(@_, {
1400             UserName => { type => SCALAR, optional => 1 },
1401             });
1402              
1403             my $xml = $self->_sign(Action => 'ListAccessKeys', %args);
1404              
1405             if ( grep { defined && length } $xml->{'Error'} ) {
1406             return $self->_parse_errors($xml);
1407             } else {
1408             my %result = %{$xml->{'ListAccessKeysResult'}};
1409             my $keys = $self->_parse_attributes('AccessKeyMetadata', 'AccessKeyMetadata', %result);
1410              
1411             return Net::Amazon::IAM::AccessKeysList->new(
1412             Keys => $keys,
1413             );
1414             }
1415             }
1416              
1417             =head2 create_role(%params)
1418              
1419             Creates a new role for your AWS account.
1420              
1421             The example policy grants permission to an EC2 instance to assume the role.
1422             {
1423             "Version": "2012-10-17",
1424             "Statement": [{
1425             "Effect": "Allow",
1426             "Principal": {
1427             "Service": ["ec2.amazonaws.com"]
1428             },
1429             "Action": ["sts:AssumeRole"]
1430             }]
1431             }
1432              
1433             =over
1434              
1435             =item AssumeRolePolicyDocument (required)
1436              
1437             The policy that grants an entity permission to assume the role.
1438              
1439             =item RoleName (required)
1440              
1441             The name of the role to create.
1442              
1443             =item Path (optional)
1444              
1445             The path to the role.
1446              
1447             =back
1448              
1449             Returns Net::Amazon::IAM::Role object on success or Net::Amazon::IAM::Error on fail.
1450              
1451             =cut
1452              
1453             sub create_role {
1454             my $self = shift;
1455              
1456             my %args = validate(@_, {
1457             AssumeRolePolicyDocument => { type => HASHREF },
1458             RoleName => { type => SCALAR },
1459             Path => { type => SCALAR, optional => 1 },
1460             });
1461              
1462             $args{'AssumeRolePolicyDocument'} = encode_json delete $args{'AssumeRolePolicyDocument'};
1463              
1464             my $xml = $self->_sign(Action => 'CreateRole', %args);
1465              
1466             if ( grep { defined && length } $xml->{'Error'} ) {
1467             return $self->_parse_errors($xml);
1468             } else {
1469             return Net::Amazon::IAM::Role->new(
1470             $xml->{'CreateRoleResult'}{'Role'},
1471             );
1472             }
1473             }
1474              
1475             =head2 get_role(%params)
1476              
1477             Retrieves information about the specified role.
1478              
1479             =over
1480              
1481             =item RoleName (required)
1482              
1483             The name of the role to get information about.
1484              
1485             =back
1486              
1487             Returns Net::Amazon::IAM::Role object on success or Net::Amazon::IAM::Error on fail.
1488              
1489             =cut
1490              
1491             sub get_role {
1492             my $self = shift;
1493              
1494             my %args = validate(@_, {
1495             RoleName => { type => SCALAR },
1496             });
1497              
1498             my $xml = $self->_sign(Action => 'GetRole', %args);
1499              
1500             if( grep { defined && length } $xml->{'Error'} ) {
1501             return $self->_parse_errors($xml);
1502             }else{
1503             my $role = Net::Amazon::IAM::Role->new(
1504             $xml->{'GetRoleResult'}{'Role'},
1505             );
1506              
1507             $role->{'AssumeRolePolicyDocument'} = decode_json(
1508             URI::Encode->new()->decode($role->AssumeRolePolicyDocument)
1509             );
1510              
1511             return $role;
1512             }
1513             }
1514              
1515             =head2 list_roles(%params)
1516              
1517             Retrieves information about the specified role.
1518              
1519             =over
1520              
1521             =item Marker (optional)
1522              
1523             Use this parameter only when paginating results, and only in a subsequent
1524             request after you've received a response where the results are truncated.
1525             Set it to the value of the Marker element in the response you just received.
1526              
1527             =item MaxItems (optional)
1528              
1529             Use this parameter only when paginating results to indicate the maximum number
1530             of roles you want in the response. If there are additional roles beyond the maximum
1531             you specify, the IsTruncated response element is true. This parameter is optional.
1532             If you do not include it, it defaults to 100.
1533              
1534             =item PathPrefix (optional)
1535              
1536             The path prefix for filtering the results. For example, the prefix /application_abc/component_xyz/
1537             gets all roles whose path starts with /application_abc/component_xyz/.
1538              
1539             This parameter is optional. If it is not included, it defaults to a slash (/), listing all roles.
1540              
1541             =back
1542              
1543             Returns Net::Amazon::IAM::Roles object on success or Net::Amazon::IAM::Error on fail.
1544              
1545             =cut
1546              
1547             sub list_roles {
1548             my $self = shift;
1549              
1550             my %args = validate(@_, {
1551             Marker => { type => SCALAR, optional => 1 },
1552             MaxItems => { type => SCALAR, optional => 1 },
1553             PathPrefix => { type => SCALAR, optional => 1 },
1554             });
1555              
1556             my $xml = $self->_sign(Action => 'ListRoles', %args);
1557              
1558             if ( grep { defined && length } $xml->{'Error'} ) {
1559             return $self->_parse_errors($xml);
1560             } else {
1561             my %result = %{$xml->{'ListRolesResult'}};
1562             my $roles = $self->_parse_attributes('Role', 'Roles', %result);
1563              
1564             return Net::Amazon::IAM::Roles->new(
1565             Roles => $roles,
1566             Marker => $result{'Marker'},
1567             IsTruncated => $result{'IsTruncated'},
1568             );
1569             }
1570             }
1571              
1572             =head2 delete_role(%params)
1573              
1574             Deletes the specified role. The role must not have any policies attached.
1575              
1576             B<Important>:
1577              
1578             Make sure you do not have any Amazon EC2 instances running with the role you are about to delete.
1579             Deleting a role or instance profile that is associated with a running instance will break any
1580             applications running on the instance.
1581              
1582             =over
1583              
1584             =item RoleName (required)
1585              
1586             The name of the role to delete.
1587              
1588             =back
1589              
1590             Returns true on success or Net::Amazon::IAM::Error on fail.
1591              
1592             =cut
1593              
1594             sub delete_role {
1595             my $self = shift;
1596              
1597             my %args = validate(@_, {
1598             RoleName => { type => SCALAR },
1599             });
1600              
1601             my $xml = $self->_sign(Action => 'DeleteRole', %args);
1602              
1603             if ( grep { defined && length } $xml->{'Error'} ) {
1604             return $self->_parse_errors($xml);
1605             } else {
1606             return 1;
1607             }
1608             }
1609              
1610             =head2 create_virtual_MFA_device(%params)
1611              
1612             Creates a new virtual MFA device for the AWS account.
1613             After creating the virtual MFA, use EnableMFADevice to
1614             attach the MFA device to an IAM user.
1615              
1616             B<Important>:
1617              
1618             The seed information contained in the QR code and the Base32 string
1619             should be treated like any other secret access information, such as
1620             your AWS access keys or your passwords. After you provision your virtual
1621             device, you should ensure that the information is destroyed following
1622             secure procedures.
1623              
1624             =over
1625              
1626             =item VirtualMFADeviceName (required)
1627              
1628             The name of the virtual MFA device. Use with path to uniquely identify a virtual MFA device.
1629              
1630             =item Path (required)
1631              
1632             The path for the virtual MFA device.
1633              
1634             =back
1635              
1636             Returns Net::Amazon::IAM::VirtualMFADevice object on success or Net::Amazon::IAM::Error on fail.
1637              
1638             B<This method wasn't tested>
1639              
1640             =cut
1641              
1642             sub create_virtual_MFA_device {
1643             my $self = shift;
1644              
1645             my %args = validate(@_, {
1646             VirtualMFADeviceName => { type => SCALAR },
1647             Path => { type => SCALAR, optional => 1 },
1648             });
1649              
1650             my $xml = $self->_sign(Action => 'CreateVirtualMFADevice', %args);
1651              
1652             if ( grep { defined && length } $xml->{'Error'} ) {
1653             return $self->_parse_errors($xml);
1654             } else {
1655             return Net::Amazon::IAM::VirtualMFADevice->new(
1656             $xml->{'CreateVirtualMFADeviceResult'}{'VirtualMFADevice'},
1657             );
1658             }
1659             }
1660              
1661             =head2 delete_virtual_MFA_device(%params)
1662              
1663             Deletes a virtual MFA device.
1664              
1665             B<Note>:
1666              
1667             You must deactivate a user's virtual MFA device before you can delete it.
1668              
1669             =over
1670              
1671             =item SerialNumber (required)
1672              
1673             The serial number that uniquely identifies the MFA device.
1674             For virtual MFA devices, the serial number is the same as the ARN.
1675              
1676             =back
1677              
1678             Returns true on success or Net::Amazon::IAM::Error on fail.
1679              
1680             B<This method wasn't tested>
1681              
1682             =cut
1683              
1684             sub delete_virtual_MFA_device {
1685             my $self = shift;
1686              
1687             my %args = validate(@_, {
1688             SerialNumber => { type => SCALAR },
1689             });
1690              
1691             my $xml = $self->_sign(Action => 'DeleteVirtualMFADevice', %args);
1692              
1693             if ( grep { defined && length } $xml->{'Error'} ) {
1694             return $self->_parse_errors($xml);
1695             } else {
1696             return 1;
1697             }
1698             }
1699              
1700             =head2 list_virtual_MFA_devices(%params)
1701              
1702             Lists the virtual MFA devices under the AWS account by assignment status.
1703              
1704             =over
1705              
1706             =item Marker (optional)
1707              
1708             Use this parameter only when paginating results, and only in a subsequent
1709             request after you've received a response where the results are truncated.
1710             Set it to the value of the Marker element in the response you just received.
1711              
1712             =item MaxItems (optional)
1713              
1714             Use this parameter only when paginating results to indicate the maximum number
1715             of VirtualMFADevices you want in the response. If there are additional devices beyond the maximum
1716             you specify, the IsTruncated response element is true. This parameter is optional.
1717             If you do not include it, it defaults to 100.
1718              
1719             =item AssignmentStatus (optional)
1720              
1721             The status (unassigned or assigned) of the devices to list.
1722             If you do not specify an AssignmentStatus, the action defaults to Any
1723             which lists both assigned and unassigned virtual MFA devices.
1724              
1725             Valid Values: Assigned | Unassigned | Any
1726              
1727             =back
1728              
1729             Returns Net::Amazon::IAM::MFADevices object on success or Net::Amazon::IAM::Error on fail.
1730              
1731             =cut
1732              
1733             sub list_virtual_MFA_devices {
1734             my $self = shift;
1735              
1736             my %args = validate(@_, {
1737             AssignmentStatus => { regex => qr/Assigned|Unassigned|Any/, optional => 1 },
1738             Marker => { type => SCALAR, optional => 1 },
1739             MaxItems => { type => SCALAR, optional => 1 },
1740             });
1741              
1742             my $xml = $self->_sign(Action => 'ListVirtualMFADevices', %args);
1743              
1744             if ( grep { defined && length } $xml->{'Error'} ) {
1745             return $self->_parse_errors($xml);
1746             } else {
1747             my $devices;
1748              
1749             my %result = %{$xml->{'ListVirtualMFADevicesResult'}};
1750              
1751             if ( grep { defined && length } $result{'MFADevices'} ) {
1752             if(ref($result{'VirtualMFADevices'}{'member'}) eq 'ARRAY') {
1753             for my $device(@{$result{'VirtualMFADevices'}{'member'}}) {
1754             my $d = Net::Amazon::IAM::VirtualMFADevice->new(
1755             $device,
1756             );
1757             push @$devices, $d;
1758             }
1759             }else{
1760             my $d = Net::Amazon::IAM::VirtualMFADevice->new(
1761             $result{'VirtualMFADevices'}{'member'},
1762             );
1763             push @$devices, $d;
1764             }
1765             }else{
1766             $devices = [];
1767             }
1768              
1769             return Net::Amazon::IAM::VirtualMFADevices->new(
1770             VirtualMFADevices => $devices,
1771             Marker => $result{'Marker'},
1772             IsTruncated => $result{'IsTruncated'},
1773             );
1774             }
1775             }
1776              
1777             =head2 enable_MFA_device(%params)
1778              
1779             Enables the specified MFA device and associates it with the specified user name.
1780             When enabled, the MFA device is required for every subsequent login by the user
1781             name associated with the device.
1782              
1783             =over
1784              
1785             =item AuthenticationCode1 (required)
1786              
1787             An authentication code emitted by the device.
1788              
1789             =item AuthenticationCode2 (required)
1790              
1791             A subsequent authentication code emitted by the device.
1792              
1793             =item SerialNumber (required)
1794              
1795             The serial number that uniquely identifies the MFA device.
1796             For virtual MFA devices, the serial number is the device ARN.
1797              
1798             =item UserName (required)
1799              
1800             The name of the user for whom you want to enable the MFA device.
1801              
1802             =back
1803              
1804             Returns true on success or Net::Amazon::IAM::Error on fail.
1805              
1806             B<This method wasn't tested>
1807              
1808             =cut
1809              
1810             sub enable_MFA_device {
1811             my $self = shift;
1812              
1813             my %args = validate(@_, {
1814             AuthenticationCode1 => { type => SCALAR },
1815             AuthenticationCode2 => { type => SCALAR },
1816             SerialNumber => { type => SCALAR },
1817             UserName => { type => SCALAR },
1818             });
1819              
1820             my $xml = $self->_sign(Action => 'EnableMFADevice', %args);
1821              
1822             if ( grep { defined && length } $xml->{'Error'} ) {
1823             return $self->_parse_errors($xml);
1824             } else {
1825             return 1;
1826             }
1827             }
1828              
1829             =head2 deactivate_MFA_device(%params)
1830              
1831             Enables the specified MFA device and associates it with the specified user name.
1832             When enabled, the MFA device is required for every subsequent login by the user
1833             name associated with the device.
1834              
1835             =over
1836              
1837             =item SerialNumber (required)
1838              
1839             The serial number that uniquely identifies the MFA device.
1840             For virtual MFA devices, the serial number is the device ARN.
1841              
1842             =item UserName (required)
1843              
1844             The name of the user whose MFA device you want to deactivate.
1845              
1846             =back
1847              
1848             Returns true on success or Net::Amazon::IAM::Error on fail.
1849              
1850             B<This method wasn't tested>
1851              
1852             =cut
1853              
1854             sub deactivate_MFA_device {
1855             my $self = shift;
1856              
1857             my %args = validate(@_, {
1858             SerialNumber => { type => SCALAR },
1859             UserName => { type => SCALAR },
1860             });
1861              
1862             my $xml = $self->_sign(Action => 'DeactivateMFADevice', %args);
1863              
1864             if ( grep { defined && length } $xml->{'Error'} ) {
1865             return $self->_parse_errors($xml);
1866             } else {
1867             return 1;
1868             }
1869             }
1870              
1871             =head2 list_MFA_devices(%params)
1872              
1873             Retrieves information about the specified role.
1874              
1875             =over
1876              
1877             =item Marker (optional)
1878              
1879             Use this parameter only when paginating results, and only in a subsequent
1880             request after you've received a response where the results are truncated.
1881             Set it to the value of the Marker element in the response you just received.
1882              
1883             =item MaxItems (optional)
1884              
1885             Use this parameter only when paginating results to indicate the maximum number
1886             of MFADevices you want in the response. If there are additional devices beyond the maximum
1887             you specify, the IsTruncated response element is true. This parameter is optional.
1888             If you do not include it, it defaults to 100.
1889              
1890             =item UserName (optional)
1891              
1892             The name of the user whose MFA devices you want to list.
1893              
1894             =back
1895              
1896             Returns Net::Amazon::IAM::MFADevices object on success or Net::Amazon::IAM::Error on fail.
1897              
1898             =cut
1899              
1900             sub list_MFA_devices {
1901             my $self = shift;
1902              
1903             my %args = validate(@_, {
1904             Marker => { type => SCALAR, optional => 1 },
1905             MaxItems => { type => SCALAR, optional => 1 },
1906             UserName => { type => SCALAR, optional => 1 },
1907             });
1908              
1909             my $xml = $self->_sign(Action => 'ListMFADevices', %args);
1910              
1911             if ( grep { defined && length } $xml->{'Error'} ) {
1912             return $self->_parse_errors($xml);
1913             } else {
1914             my $devices;
1915              
1916             my %result = %{$xml->{'ListMFADevicesResult'}};
1917              
1918             if ( grep { defined && length } $result{'MFADevices'} ) {
1919             if(ref($result{'MFADevices'}{'member'}) eq 'ARRAY') {
1920             for my $device(@{$result{'MFADevices'}{'member'}}) {
1921             my $d = Net::Amazon::IAM::MFADevice->new(
1922             $device,
1923             );
1924             push @$devices, $d;
1925             }
1926             }else{
1927             my $d = Net::Amazon::IAM::MFADevice->new(
1928             $result{'MFADevices'}{'member'},
1929             );
1930             push @$devices, $d;
1931             }
1932             }else{
1933             $devices = [];
1934             }
1935              
1936             return Net::Amazon::IAM::MFADevices->new(
1937             MFADevices => $devices,
1938             Marker => $result{'Marker'},
1939             IsTruncated => $result{'IsTruncated'},
1940             );
1941             }
1942             }
1943              
1944             =head2 create_instance_profile(%params)
1945              
1946             Creates a new instance profile.
1947              
1948             =over
1949              
1950             =item InstanceProfileName (required)
1951              
1952             The name of the instance profile to create.
1953              
1954             =item Path (optional)
1955              
1956             The path to the instance profile.
1957              
1958             =back
1959              
1960             Returns Net::Amazon::IAM::InstanceProfile object on success or Net::Amazon::IAM::Error on fail.
1961             The Roles attribute of Net::Amazon::IAM::InstanceProfile object will be undef.
1962              
1963             =cut
1964              
1965              
1966             sub create_instance_profile {
1967             my $self = shift;
1968              
1969             my %args = validate(@_, {
1970             InstanceProfileName => { type => SCALAR },
1971             Path => { type => SCALAR, optional => 1 },
1972             });
1973              
1974             my $xml = $self->_sign(Action => 'CreateInstanceProfile', %args);
1975              
1976             if ( grep { defined && length } $xml->{'Error'} ) {
1977             return $self->_parse_errors($xml);
1978             } else {
1979             return Net::Amazon::IAM::InstanceProfile->new(
1980             $xml->{'CreateInstanceProfileResult'}{'InstanceProfile'},
1981             );
1982             }
1983             }
1984              
1985             =head2 get_instance_profile(%params)
1986              
1987             Retrieves information about the specified instance profile,
1988             including the instance profile's path, GUID, ARN, and role.
1989              
1990             =over
1991              
1992             =item InstanceProfileName (required)
1993              
1994             The name of the instance profile to get information about.
1995              
1996             =back
1997              
1998             Returns Net::Amazon::IAM::InstanceProfile object on success or Net::Amazon::IAM::Error on fail.
1999              
2000             =cut
2001              
2002             sub get_instance_profile {
2003             my $self = shift;
2004              
2005             my %args = validate(@_, {
2006             InstanceProfileName => { type => SCALAR },
2007             });
2008              
2009             my $xml = $self->_sign(Action => 'GetInstanceProfile', %args);
2010              
2011             if ( grep { defined && length } $xml->{'Error'} ) {
2012             return $self->_parse_errors($xml);
2013             } else {
2014             my %result = %{$xml->{'GetInstanceProfileResult'}{'InstanceProfile'}};
2015             my $roles = $self->_parse_attributes('Role', 'Roles', %result);
2016              
2017             my $roles_obj = Net::Amazon::IAM::Roles->new(
2018             Roles => $roles,
2019             );
2020              
2021             return Net::Amazon::IAM::InstanceProfile->new(
2022             Arn => $result{'Arn'},
2023             CreateDate => $result{'CreateDate'},
2024             InstanceProfileId => $result{'InstanceProfileId'},
2025             InstanceProfileName => $result{'InstanceProfileName'},
2026             Path => $result{'Path'},
2027             Roles => $roles_obj,
2028             );
2029             }
2030             }
2031              
2032             =head2 list_instance_profiles(%params)
2033              
2034             Lists the instance profiles that have the specified path prefix.
2035              
2036             =over
2037              
2038             =item Marker (optional)
2039              
2040             Use this parameter only when paginating results, and only in a subsequent
2041             request after you've received a response where the results are truncated.
2042             Set it to the value of the Marker element in the response you just received.
2043              
2044             =item MaxItems (optional)
2045              
2046             Use this parameter only when paginating results to indicate the maximum number
2047             of instance profiles you want in the response. If there are additional instance
2048             profiles beyond the maximum you specify, the IsTruncated response element is true.
2049             This parameter is optional. If you do not include it, it defaults to 100.
2050              
2051             =item PathPrefix (optional)
2052              
2053             The path prefix for filtering the results. For example, the prefix
2054             /application_abc/component_xyz/ gets all instance profiles whose path
2055             starts with /application_abc/component_xyz/.
2056              
2057             =back
2058              
2059             Returns Net::Amazon::IAM::InstanceProfiles object on success or Net::Amazon::IAM::Error on fail.
2060              
2061             =cut
2062              
2063             sub list_instance_profiles {
2064             my $self = shift;
2065              
2066             my %args = validate(@_, {
2067             Marker => { type => SCALAR, optional => 1 },
2068             MaxItems => { type => SCALAR, optional => 1 },
2069             PathPrefix => { type => SCALAR, optional => 1 },
2070             });
2071              
2072             my $xml = $self->_sign(Action => 'ListInstanceProfiles', %args);
2073              
2074             if ( grep { defined && length } $xml->{'Error'} ) {
2075             return $self->_parse_errors($xml);
2076             } else {
2077             my %result = %{$xml->{'ListInstanceProfilesResult'}};
2078             my $instance_profiles = $self->_parse_attributes('InstanceProfile', 'InstanceProfiles', %result);
2079              
2080             for my $profile (@{$instance_profiles}) {
2081             my %roles;
2082             $roles{'Roles'} = $profile->{'Roles'};
2083             my $roles = $self->_parse_attributes('Role', 'Roles', %roles);
2084              
2085             my $roles_obj = Net::Amazon::IAM::Roles->new(
2086             Roles => $roles,
2087             );
2088              
2089             $profile->{'Roles'} = $roles_obj;
2090             }
2091              
2092             return Net::Amazon::IAM::InstanceProfiles->new(
2093             InstanceProfiles => $instance_profiles,
2094             Marker => $result{'Marker'},
2095             IsTruncated => $result{'IsTruncated'},
2096             );
2097             }
2098             }
2099              
2100             =head2 delete_instance_profile(%params)
2101              
2102             Deletes the specified instance profile. The instance profile must not have an associated role.
2103              
2104             =over
2105              
2106             =item InstanceProfileName (required)
2107              
2108             The name of the instance profile to delete.
2109              
2110             =back
2111              
2112             Returns true on success or Net::Amazon::IAM::Error on fail.
2113              
2114             =cut
2115              
2116             sub delete_instance_profile {
2117             my $self = shift;
2118              
2119             my %args = validate(@_, {
2120             InstanceProfileName => { type => SCALAR },
2121             });
2122              
2123             my $xml = $self->_sign(Action => 'DeleteInstanceProfile', %args);
2124              
2125             if ( grep { defined && length } $xml->{'Error'} ) {
2126             return $self->_parse_errors($xml);
2127             } else {
2128             return 1;
2129             }
2130             }
2131              
2132             =head2 add_role_to_instance_profile(%params)
2133              
2134             Adds the specified role to the specified instance profile.
2135              
2136             =over
2137              
2138             =item InstanceProfileName (required)
2139              
2140             The name of the instance profile to update.
2141              
2142             =item RoleName (required)
2143              
2144             The name of the role to add.
2145              
2146             =back
2147              
2148             Returns true on success or Net::Amazon::IAM::Error on fail.
2149              
2150             =cut
2151              
2152             sub add_role_to_instance_profile {
2153             my $self = shift;
2154              
2155             my %args = validate(@_, {
2156             InstanceProfileName => { type => SCALAR },
2157             RoleName => { type => SCALAR },
2158             });
2159              
2160             my $xml = $self->_sign(Action => 'AddRoleToInstanceProfile', %args);
2161              
2162             if ( grep { defined && length } $xml->{'Error'} ) {
2163             return $self->_parse_errors($xml);
2164             } else {
2165             return 1;
2166             }
2167             }
2168              
2169             =head2 remove_role_from_instance_profile(%params)
2170              
2171             Removes the specified role from the specified instance profile.
2172              
2173             B<Important>:
2174              
2175             Make sure you do not have any Amazon EC2 instances running with the role
2176             you are about to remove from the instance profile. Removing a role from an
2177             instance profile that is associated with a running instance will break any
2178             applications running on the instance.
2179              
2180             =over
2181              
2182             =item InstanceProfileName (required)
2183              
2184             The name of the instance profile to update.
2185              
2186             =item RoleName (required)
2187              
2188             The name of the role to remove.
2189              
2190             =back
2191              
2192             Returns true on success or Net::Amazon::IAM::Error on fail.
2193              
2194             =cut
2195              
2196             sub remove_role_from_instance_profile {
2197             my $self = shift;
2198              
2199             my %args = validate(@_, {
2200             InstanceProfileName => { type => SCALAR },
2201             RoleName => { type => SCALAR },
2202             });
2203              
2204             my $xml = $self->_sign(Action => 'RemoveRoleFromInstanceProfile', %args);
2205              
2206             if ( grep { defined && length } $xml->{'Error'} ) {
2207             return $self->_parse_errors($xml);
2208             } else {
2209             return 1;
2210             }
2211             }
2212              
2213             =head2 list_instance_profiles_for_role(%params)
2214              
2215             Lists the instance profiles that have the specified associated role.
2216              
2217             =over
2218              
2219             =item RoleName (required)
2220              
2221             The name of the role to list instance profiles for.
2222              
2223             =item MaxItems (optional)
2224              
2225             Use this parameter only when paginating results to indicate the maximum number of
2226             instance profiles you want in the response. If there are additional instance profiles
2227             beyond the maximum you specify, the IsTruncated response element is true. This parameter
2228             is optional. If you do not include it, it defaults to 100.
2229              
2230             =item Marker (optional)
2231              
2232             Use this parameter only when paginating results, and only in a subsequent request
2233             after you've received a response where the results are truncated. Set it to the
2234             value of the Marker element in the response you just received.
2235              
2236             =back
2237              
2238             Returns Net::Amazon::IAM::InstanceProfiles object on success or Net::Amazon::IAM::Error on fail.
2239              
2240             =cut
2241              
2242             sub list_instance_profiles_for_role {
2243             my $self = shift;
2244              
2245             my %args = validate(@_, {
2246             RoleName => { type => SCALAR },
2247             Marker => { type => SCALAR, optional => 1 },
2248             MaxItems => { type => SCALAR, optional => 1 },
2249             });
2250              
2251             my $xml = $self->_sign(Action => 'ListInstanceProfilesForRole', %args);
2252              
2253             if ( grep { defined && length } $xml->{'Error'} ) {
2254             return $self->_parse_errors($xml);
2255             } else {
2256             my %result = %{$xml->{'ListInstanceProfilesForRoleResult'}};
2257             my $instance_profiles = $self->_parse_attributes('InstanceProfile', 'InstanceProfiles', %result);
2258              
2259             for my $profile (@{$instance_profiles}) {
2260             my %roles;
2261             $roles{'Roles'} = $profile->{'Roles'};
2262             my $roles = $self->_parse_attributes('Role', 'Roles', %roles);
2263              
2264             my $roles_obj = Net::Amazon::IAM::Roles->new(
2265             Roles => $roles,
2266             );
2267              
2268             $profile->{'Roles'} = $roles_obj;
2269             }
2270              
2271             return Net::Amazon::IAM::InstanceProfiles->new(
2272             InstanceProfiles => $instance_profiles,
2273             Marker => $result{'Marker'},
2274             IsTruncated => $result{'IsTruncated'},
2275             );
2276             }
2277             }
2278              
2279             =head2 create_login_profile(%params)
2280              
2281             Lists the instance profiles that have the specified associated role.
2282              
2283             =over
2284              
2285             =item UserName (required)
2286              
2287             The name of the user to create a password for.
2288              
2289             =item Password (required)
2290              
2291             The new password for the user.
2292              
2293             =item PasswordResetRequired (optional)
2294              
2295             Specifies whether the user is required to set a new password on next sign-in.
2296              
2297             =back
2298              
2299             Returns Net::Amazon::IAM::LoginProfile object on success or Net::Amazon::IAM::Error on fail.
2300              
2301             =cut
2302              
2303             sub create_login_profile {
2304             my $self = shift;
2305              
2306             my %args = validate(@_, {
2307             Password => { type => SCALAR },
2308             UserName => { type => SCALAR },
2309             PasswordResetRequired => { type => SCALAR, optional => 1 },
2310             });
2311              
2312             my $xml = $self->_sign(Action => 'CreateLoginProfile', %args);
2313              
2314             if ( grep { defined && length } $xml->{'Error'} ) {
2315             return $self->_parse_errors($xml);
2316             } else {
2317             return Net::Amazon::IAM::LoginProfile->new(
2318             $xml->{'CreateLoginProfileResult'}{'LoginProfile'},
2319             );
2320             }
2321             }
2322              
2323             =head2 delete_login_profile(%params)
2324              
2325             Deletes the password for the specified user, which terminates the user's ability
2326             to access AWS services through the AWS Management Console.
2327              
2328             B<Important>:
2329             Deleting a user's password does not prevent a user from accessing IAM through
2330             the command line interface or the API. To prevent all user access you must also either
2331             make the access key inactive or delete it. For more information about making keys inactive
2332             or deleting them, see update_access_key and delete_access_key.
2333              
2334             =over
2335              
2336             =item UserName (required)
2337              
2338             The name of the user whose password you want to delete.
2339              
2340             =back
2341              
2342             Returns true on success or Net::Amazon::IAM::Error on fail.
2343              
2344             =cut
2345              
2346             sub delete_login_profile {
2347             my $self = shift;
2348              
2349             my %args = validate(@_, {
2350             UserName => { type => SCALAR },
2351             });
2352              
2353             my $xml = $self->_sign(Action => 'DeleteLoginProfile', %args);
2354              
2355             if ( grep { defined && length } $xml->{'Error'} ) {
2356             return $self->_parse_errors($xml);
2357             } else {
2358             return 1;
2359             }
2360             }
2361              
2362             =head2 get_login_profile(%params)
2363              
2364             Retrieves the user name and password-creation date for the specified user.
2365             If the user has not been assigned a password, the action returns a 404 (NoSuchEntity) error.
2366              
2367             =over
2368              
2369             =item UserName (required)
2370              
2371             The name of the user whose login profile you want to retrieve.
2372              
2373             =back
2374              
2375             Returns Net::Amazon::IAM::LoginProfile object on success or Net::Amazon::IAM::Error on fail.
2376              
2377             =cut
2378              
2379             sub get_login_profile {
2380             my $self = shift;
2381              
2382             my %args = validate(@_, {
2383             UserName => { type => SCALAR },
2384             });
2385              
2386             my $xml = $self->_sign(Action => 'GetLoginProfile', %args);
2387              
2388             if ( grep { defined && length } $xml->{'Error'} ) {
2389             return $self->_parse_errors($xml);
2390             } else {
2391             return Net::Amazon::IAM::LoginProfile->new(
2392             $xml->{'GetLoginProfileResult'}{'LoginProfile'},
2393             );
2394             }
2395             }
2396              
2397             =head2 update_login_profile(%params)
2398              
2399             Changes the password for the specified user.
2400              
2401             =over
2402              
2403             =item UserName (required)
2404              
2405             The name of the user whose password you want to update.
2406              
2407             =item Password (required)
2408              
2409             The new password for the specified user.
2410              
2411             =item PasswordResetRequired (optional)
2412              
2413             Require the specified user to set a new password on next sign-in.
2414              
2415             =back
2416              
2417             Returns true on success or Net::Amazon::IAM::Error on fail.
2418              
2419             =cut
2420              
2421             sub update_login_profile {
2422             my $self = shift;
2423              
2424             my %args = validate(@_, {
2425             UserName => { type => SCALAR },
2426             Password => { type => SCALAR, optional => 1 },
2427             PasswordResetRequired => { type => SCALAR, optional => 1 },
2428             });
2429              
2430             my $xml = $self->_sign(Action => 'UpdateLoginProfile', %args);
2431              
2432             if ( grep { defined && length } $xml->{'Error'} ) {
2433             return $self->_parse_errors($xml);
2434             } else {
2435             return 1;
2436             }
2437             }
2438              
2439             no Moose;
2440             1;
2441              
2442             =head1 KNOWN ISSUES
2443              
2444             * missing some ( a lot of ) methods
2445              
2446             * missing tests
2447              
2448             * list_user_policies returns just an ArrayRef.
2449              
2450             =head1 AUTHOR
2451              
2452             Igor Tsigankov <tsiganenok@gmail.com>
2453              
2454             =head1 COPYRIGHT
2455              
2456             Copyright (c) 2015 Igor Tsigankov.
2457              
2458             This program is free software; you can redistribute it and/or modify it
2459             under the same terms as Perl itself.
2460              
2461             =cut
2462              
2463             __END__