class ListSigningCertificates(IAMRequest):
    DESCRIPTION = "List a user's signing certificates"
    ARGS = [
        arg_user(nargs='?',
                 help='''user to list certificates for
                     (default: current user)'''),
        Arg('-v',
            '--verbose',
            action='store_true',
            route_to=None,
            help="also show certificates' contents"), AS_ACCOUNT
    ]
    LIST_TAGS = ['Certificates']

    def main(self):
        return PaginatedResponse(self, (None, ), ('Certificates', ))

    def prepare_for_page(self, page):
        # Pages are defined by markers
        self.params['Marker'] = page

    def get_next_page(self, response):
        if response.get('IsTruncatated') == 'true':
            return response['Marker']

    def print_result(self, result):
        for cert in result.get('Certificates', []):
            print cert['CertificateId']
            if self.args['verbose']:
                print cert['CertificateBody']
            print cert['Status']
            print cert.get('UserName') or ''
class GetUserPolicy(IAMRequest):
    DESCRIPTION = "Display a user's policy"
    ARGS = [
        arg_user(help='user the poilcy is attached to (required)'),
        Arg('-p',
            '--policy-name',
            dest='PolicyName',
            metavar='POLICY',
            required=True,
            help='name of the policy to show (required)'),
        Arg('--pretty-print',
            action='store_true',
            route_to=None,
            help='reformat the policy for easier reading'), AS_ACCOUNT
    ]

    def print_result(self, result):
        policy_content = urllib.unquote(result['PolicyDocument'])
        if self.args['pretty_print']:
            try:
                policy_json = json.loads(policy_content)
            except ValueError:
                self.log.debug('JSON parse error', exc_info=True)
                raise ValueError(
                    "policy '{0}' does not appear to be valid JSON".format(
                        self.args['PolicyName']))
            policy_content = json.dumps(policy_json, indent=4)
        print policy_content
Beispiel #3
0
class ListAccessKeys(IAMRequest):
    DESCRIPTION = "List a user's access keys"
    ARGS = [arg_user(nargs='?',
                     help='user to list keys for (default: current user)'),
            AS_ACCOUNT]
    LIST_TAGS = ['AccessKeyMetadata']

    def main(self):
        return PaginatedResponse(self, (None,), ('AccessKeyMetadata',))

    def prepare_for_page(self, page):
        # Pages are defined by markers
        self.params['Marker'] = page

    # pylint: disable=no-self-use
    def get_next_page(self, response):
        if response.get('IsTruncated') == 'true':
            return response['Marker']
    # pylint: enable=no-self-use

    # pylint: disable=no-self-use
    def print_result(self, result):
        for accesskey in result.get('AccessKeyMetadata', []):
            print accesskey.get('AccessKeyId')
            print accesskey.get('Status')
Beispiel #4
0
class ListMFADevices(IAMRequest):
    DESCRIPTION = "List a user's MFA devices"
    ARGS = [
        arg_user(nargs='?',
                 help='''user to list MFA devices for
                     (default: current user)'''), AS_ACCOUNT
    ]
    LIST_TAGS = ['MFADevices']

    def main(self):
        return PaginatedResponse(self, (None, ), ('MFADevices', ))

    def prepare_for_page(self, page):
        # Pages are defined by markers
        self.params['Marker'] = page

    # pylint: disable=no-self-use
    def get_next_page(self, response):
        if response.get('IsTruncated') == 'true':
            return response['Marker']

    # pylint: enable=no-self-use

    # pylint: disable=no-self-use
    def print_result(self, result):
        for device in result.get('MFADevices', []):
            print device['SerialNumber']
class ListGroupsForUser(IAMRequest):
    DESCRIPTION = 'List all groups a user is a member of'
    ARGS = [
        arg_user(help='user to list membership for (required)'), AS_ACCOUNT
    ]
    LIST_TAGS = ['Groups']

    def main(self):
        return PaginatedResponse(self, (None, ), ('Groups', ))

    def prepare_for_page(self, page):
        # Pages are defined by markers
        self.params['Marker'] = page

    # pylint: disable=no-self-use
    def get_next_page(self, response):
        if response.get('IsTruncated') == 'true':
            return response['Marker']

    # pylint: enable=no-self-use

    # pylint: disable=no-self-use
    def print_result(self, result):
        for group in result.get('Groups', []):
            print group['Arn']
Beispiel #6
0
class CreateSigningCertificate(IAMRequest):
    DESCRIPTION = '[Eucalyptus only] Create a new signing certificate'
    ARGS = [
        arg_user(nargs='?',
                 help='''user to create the signing
                     certificate for (default: current user)'''),
        Arg('--out',
            metavar='FILE',
            route_to=None,
            help='file to write the certificate to (default: stdout)'),
        Arg('--keyout',
            metavar='FILE',
            route_to=None,
            help='file to write the private key to (default: stdout)'),
        AS_ACCOUNT
    ]

    def postprocess(self, result):
        if self.args['out']:
            with open(self.args['out'], 'w') as certfile:
                certfile.write(result['Certificate']['CertificateBody'])
        if self.args['keyout']:
            old_umask = os.umask(0o077)
            with open(self.args['keyout'], 'w') as keyfile:
                keyfile.write(result['Certificate']['PrivateKey'])
            os.umask(old_umask)

    def print_result(self, result):
        print result['Certificate']['CertificateId']
        if not self.args['out']:
            print result['Certificate']['CertificateBody']
        if not self.args['keyout']:
            print result['Certificate']['PrivateKey']
Beispiel #7
0
class AddUserPolicy(IAMRequest):
    DESCRIPTION = ('Add a new policy to a user. To add more complex policies '
                   'than this tool supports, see euare-useruploadpolicy(1).')
    ARGS = [arg_user(help='user to attach the policy to (required)'),
            Arg('-p', '--policy-name', metavar='POLICY', required=True,
                help='name of the new policy (required)'),
            Arg('-e', '--effect', choices=('Allow', 'Deny'), required=True,
                help='whether the new policy should Allow or Deny (required)'),
            Arg('-a', '--action', dest='actions', action='append',
                required=True, help='''action(s) the policy should apply to
                (at least one required)'''),
            Arg('-r', '--resource', dest='resources', action='append',
                required=True, help='''resource(s) the policy should apply to
                (at least one required)'''),
            Arg('-o', '--output', action='store_true',
                help='display the newly-created policy'),
            AS_ACCOUNT]

    def main(self):
        policy = build_iam_policy(self.args['effect'], self.args['resources'],
                                  self.args['actions'])
        policy_doc = json.dumps(policy)
        req = PutUserPolicy.from_other(
            self, UserName=self.args['UserName'],
            PolicyName=self.args['policy_name'], PolicyDocument=policy_doc,
            DelegateAccount=self.params['DelegateAccount'])
        response = req.main()
        response['PolicyDocument'] = policy_doc
        return response

    def print_result(self, result):
        if self.args['output']:
            print result['PolicyDocument']
Beispiel #8
0
class DeactivateMFADevice(IAMRequest):
    DESCRIPTION = 'Deactivate an MFA device'
    ARGS = [arg_user(
                help='user owning the MFA device to deactivate (required)'),
            Arg('-s', '--serial-number', dest='SerialNumber', metavar='SERIAL',
                required=True, help='''serial number of the MFA device to
                                       deactivate (required)'''),
            AS_ACCOUNT]
class DeleteUserPolicy(IAMRequest):
    DESCRIPTION = 'Remove a policy from a user'
    ARGS = [
        arg_user(help='user the policy is attached to (required)'),
        Arg('-p',
            '--policy-name',
            dest='PolicyName',
            metavar='POLICY',
            required=True,
            help='name of the policy to delete (required)'), AS_ACCOUNT
    ]
Beispiel #10
0
class GetUserInfo(IAMRequest, TabifyingMixin):
    DESCRIPTION = '[Eucalyptus only] Display information about a user'
    ARGS = [arg_user(nargs='?', help='''name of the user to describe
                     (default: current user)'''),
            Arg('-k', '--info-key', dest='InfoKey',
                help='name of the piece of user info to show'),
            AS_ACCOUNT]
    LIST_TAGS = ['Infos']

    def print_result(self, result):
        for info in result.get('Infos', []):
            print self.tabify((info.get('Key'), info.get('Value')))
Beispiel #11
0
class ResyncMFADevice(IAMRequest):
    DESCRIPTION = 'Re-synchronize an MFA device with the server'
    ARGS = [arg_user(help='''user owning the MFA device to re-synchronize
                     (required)'''),
            Arg('-s', '--serial-number', dest='SerialNumber', metavar='SERIAL',
                required=True,
                help='serial number of the MFA device (required)'),
            Arg('-c1', dest='AuthenticationCode1', metavar='CODE',
                required=True, help='''an authentication code emitted by the
                                       MFA device (required)'''),
            Arg('-c2', dest='AuthenticationCode2', metavar='CODE',
                required=True, help='''a subsequent authentication code emitted
                                       by the MFA device (required)'''),
            AS_ACCOUNT]
class UpdateLoginProfile(IAMRequest):
    DESCRIPTION = "Update a user's password"
    ARGS = [
        arg_user(help='name of the user to change a password for (required)'),
        Arg('-p',
            '--password',
            dest='Password',
            help='''the new password.  If unspecified, the new password
                        will be read from the console.'''), AS_ACCOUNT
    ]

    def configure(self):
        IAMRequest.configure(self)
        if self.args['Password'] is None:
            self.log.info('no password supplied; prompting')
            self.params['Password'] = prompt_for_password()
class UpdateUserInfo(IAMRequest):
    DESCRIPTION = "[Eucalyptus only] Update a user's information"
    ARGS = [
        arg_user(nargs='?', help='user to update (default: current user)'),
        Arg('-k',
            '--info-key',
            dest='InfoKey',
            metavar='KEY',
            required=True,
            help='name of the info field to set (required)'),
        Arg('-i',
            '--info-value',
            dest='InfoValue',
            metavar='VALUE',
            help='value to set the info field to (omit to delete it)'),
        AS_ACCOUNT
    ]
class UploadSigningCertificate(IAMRequest):
    DESCRIPTION = 'Upload a signing certificate'
    ARGS = [arg_user(help='''user the signing certificate is for
                     (default: current user)'''),
            MutuallyExclusiveArgList(
                Arg('-c', '--certificate-body', dest='CertificateBody',
                    metavar='CERT_CONTENT',
                    help='PEM-encoded contents of the new certificate'),
                Arg('-f', '--certificate-file', dest='CertificateBody',
                    metavar='FILE', type=open,
                    help='file containing the new certificate'))
            .required(),
            AS_ACCOUNT]

    # pylint: disable=no-self-use
    def print_result(self, result):
        print result.get('Certificate', {}).get('CertificateId')
Beispiel #15
0
class UpdateUser(IAMRequest):
    DESCRIPTION = 'Change the name and/or path of a user'
    ARGS = [arg_user(help='name of the user to update'),
            Arg('-n', '--new-user-name', dest='NewUserName', metavar='USER',
                help='new name for the user'),
            Arg('-p', '--new-path', dest='NewPath', metavar='PATH',
                help='new path for the user'),
            Arg('--enabled', dest='Enabled', choices=('true', 'false'),
                help='''[Eucalyptus only] 'true' to enable the user, or 'false'
                        to disable the user'''),
            Arg('--pwd-expires', dest='PasswordExpiration',
                metavar='YYYY-MM-DDThh:mm:ssZ', help='''[Eucalyptus only]
                New password expiration date, in ISO8601 format'''),
            Arg('--reg-status', dest='RegStatus',
                choices=('REGISTERED', 'APPROVED', 'CONFIRMED'),
                help='''[Eucalyptus < 4.2 only] new registration status. Only
                        CONFIRMED users may access the system.'''),
            AS_ACCOUNT]
Beispiel #16
0
class GetUser(IAMRequest):
    DESCRIPTION = "Display a user's ARN and GUID"
    ARGS = [
        arg_user(nargs='?',
                 help='''name of the user to describe
                     (default: current user)'''),
        Arg('--show-extra',
            dest='ShowExtra',
            action='store_const',
            const='true',
            help='also display additional user info'), AS_ACCOUNT
    ]

    def print_result(self, result):
        print result['User']['Arn']
        print result['User']['UserId']
        if self.args['ShowExtra'] == 'true':
            for attr in ('CreateDate', 'Enabled', 'RegStatus',
                         'PasswordExpiration'):
                print result['User'].get(attr, '')
Beispiel #17
0
class GetLoginProfile(IAMRequest):
    DESCRIPTION = 'Verify that a user has a password'
    ARGS = [
        arg_user(help='user owning the password to check (required)'),
        Arg('--verbose',
            action='store_true',
            route_to=None,
            help="print extra info about the user's password"), AS_ACCOUNT
    ]

    def print_result(self, result):
        # If we've managed to get to this point, we already know the user has
        # a login profile.
        user_name = result['LoginProfile'].get('UserName')
        print 'Login Profile Exists for User', user_name
        if self.args['verbose']:
            create_date = result['LoginProfile'].get('CreateDate')
            if create_date:
                print 'Creation date:', create_date
            must_change = result['LoginProfile'].get('MustChangePassword')
            if must_change:
                print 'Must change password:', must_change
Beispiel #18
0
class PutUserPolicy(IAMRequest):
    DESCRIPTION = 'Attach a policy to a user'
    ARGS = [
        arg_user(help='user to attach the policy to (required)'),
        Arg('-p',
            '--policy-name',
            dest='PolicyName',
            metavar='POLICY',
            required=True,
            help='name of the policy (required)'),
        MutuallyExclusiveArgList(
            Arg('-o',
                '--policy-content',
                dest='PolicyDocument',
                metavar='POLICY_CONTENT',
                help='the policy to attach'),
            Arg('-f',
                '--policy-document',
                dest='PolicyDocument',
                metavar='FILE',
                type=open,
                help='file containing the policy to attach')).required(),
        AS_ACCOUNT
    ]
class EnableMFADevice(IAMRequest):
    DESCRIPTION = 'Enable an MFA device'
    ARGS = [
        arg_user(help='user to enable the MFA device for (required)'),
        Arg('-s',
            '--serial-number',
            dest='SerialNumber',
            metavar='SERIAL',
            required=True,
            help='serial number of the MFA device to activate (required)'),
        Arg('-c1',
            dest='AuthenticationCode1',
            metavar='CODE',
            required=True,
            help='''an authentication code emitted by the
                                       MFA device (required)'''),
        Arg('-c2',
            dest='AuthenticationCode2',
            metavar='CODE',
            required=True,
            help='''a subsequent authentication code emitted
                                       by the MFA device (required)'''),
        AS_ACCOUNT
    ]
Beispiel #20
0
class CreateAccessKey(IAMRequest):
    DESCRIPTION = 'Create a new access key for a user'
    ARGS = [
        arg_user(help='''user the new key will belong to
                     (default: current user)'''),
        Arg('-w',
            '--write-config',
            action='store_true',
            route_to=None,
            help='''output access keys and region information in the
                form of a euca2ools.ini(5) configuration file instead of
                by themselves'''),
        Arg('-d',
            '--domain',
            route_to=None,
            help='''the DNS domain
                to use for region information in configuration file
                output (default: based on IAM URL)'''),
        Arg('-l',
            '--set-default-user',
            action='store_true',
            route_to=None,
            help='''set this user as the default user for the region
                in euca2ools.ini(5) configuration file output.  This
                option is only useful when used with -w.'''), AS_ACCOUNT
    ]

    def postprocess(self, result):
        if self.args.get('write_config'):
            parsed = six.moves.urllib.parse.urlparse(self.service.endpoint)
            if not self.args.get('domain'):
                dnsname = parsed.netloc.split(':')[0]
                if all(label.isdigit() for label in dnsname.split('.')):
                    msg = ('warning: IAM URL {0} refers to a specific IP; '
                           'for a complete configuration file supply '
                           'the region\'s DNS domain with -d/--domain'.format(
                               self.service.endpoint))
                    print >> sys.stderr, msg
                else:
                    self.args['domain'] = parsed.netloc.split('.', 1)[1]
            configfile = six.moves.configparser.SafeConfigParser()
            if self.args.get('domain'):
                if ':' not in self.args['domain'] and ':' in parsed.netloc:
                    # Add the port
                    self.args['domain'] += ':' + parsed.netloc.split(':')[1]
                # This uses self.config.region instead of
                # self.service.region_name because the latter is a global
                # service in AWS and thus frequently deferred with "use"
                # statements.  That may eventually happen in eucalyptus
                # cloud federations as well.
                #
                # At some point an option that lets one choose a region
                # name at the command line may be useful, but until
                # someone asks for it let's not clutter it up for now.
                region_name = self.config.region or self.args['domain']
                region_section = 'region {0}'.format(region_name.split(':')[0])
                configfile.add_section(region_section)
                for service in sorted(euca2ools.util.generate_service_names()):
                    url = '{scheme}://{service}.{domain}/'.format(
                        scheme=parsed.scheme,
                        domain=self.args['domain'],
                        service=service)
                    configfile.set(region_section, '{0}-url'.format(service),
                                   url)

            user_name = result['AccessKey'].get('UserName') or 'root'
            account_id = self.get_user_account_id()
            if account_id:
                user_name = '{0}:{1}'.format(account_id, user_name)
            user_section = 'user {0}'.format(user_name)
            configfile.add_section(user_section)
            configfile.set(user_section, 'key-id',
                           result['AccessKey']['AccessKeyId'])
            configfile.set(user_section, 'secret-key',
                           result['AccessKey']['SecretAccessKey'])
            if account_id:
                configfile.set(user_section, 'account-id', account_id)
            if self.args.get('set_default_user'):
                configfile.set(region_section, 'user', user_name)
            result['configfile'] = configfile

    def print_result(self, result):
        if self.args.get('write_config'):
            result['configfile'].write(sys.stdout)
        else:
            print result['AccessKey']['AccessKeyId']
            print result['AccessKey']['SecretAccessKey']

    def get_user_account_id(self):
        req = GetUser.from_other(
            self,
            UserName=self.params['UserName'],
            DelegateAccount=self.params.get('DelegateAccount'))
        try:
            response = req.main()
        except euca2ools.exceptions.AWSError as err:
            if err.status_code == 403:
                msg = ('warning: unable to retrieve account ID ({0})'.format(
                    err.message))
                print >> sys.stderr, msg
                return None
            raise
        arn = response['User']['Arn']
        return arn.split(':')[4]
Beispiel #21
0
class CreateUser(IAMRequest):
    DESCRIPTION = 'Create a new user'
    ARGS = [
        arg_user(help='name of the new user (required)'),
        Arg('-p',
            '--path',
            dest='Path',
            help='path for the new user (default: "/")'),
        Arg('-g',
            '--group-name',
            route_to=None,
            help='also add the new user to a group'),
        Arg('--verify',
            action='store_true',
            route_to=None,
            help='''ensure the group given with -g exists before doing
                anything'''),
        Arg('-k',
            '--create-accesskey',
            action='store_true',
            route_to=None,
            help='also create an access key for the new user and show it'),
        MutuallyExclusiveArgList(
            Arg('-v',
                '--verbose',
                action='store_true',
                route_to=None,
                help="show the new user's ARN and GUID"),
            Arg('-w',
                '--write-config',
                action='store_true',
                route_to=None,
                help='''output access keys and region information in the
                    form of a euca2ools.ini(5) configuration file instead of
                    by themselves (implies -k)''')),
        Arg('-d',
            '--domain',
            route_to=None,
            help='''the DNS domain to
                use for region information in configuration file output
                (default: based on IAM URL)'''), AS_ACCOUNT
    ]

    def preprocess(self):
        if self.args.get('verify') and self.args.get('group_name'):
            obj = GetGroup.from_other(
                self,
                GroupName=self.args['group_name'],
                DelegateAccount=self.params['DelegateAccount'])
            # This will blow up if the group does not exist.
            obj.main()

    def postprocess(self, result):
        if self.args.get('group_name'):
            obj = AddUserToGroup.from_other(
                self,
                UserName=self.args['UserName'],
                GroupName=self.args['group_name'],
                DelegateAccount=self.params['DelegateAccount'])
            obj.main()
        if self.args.get('create_accesskey') or self.args.get('write_config'):
            obj = CreateAccessKey.from_other(
                self,
                UserName=self.args['UserName'],
                DelegateAccount=self.params['DelegateAccount'],
                write_config=self.args.get('write_config'),
                domain=self.args.get('domain'))
            key_result = obj.main()
            result.update(key_result)

    def print_result(self, result):
        if self.args.get('write_config'):
            result['configfile'].write(sys.stdout)
        else:
            if self.args['verbose']:
                print result['User']['Arn']
                print result['User']['UserId']
            if 'AccessKey' in result:
                print result['AccessKey']['AccessKeyId']
                print result['AccessKey']['SecretAccessKey']
Beispiel #22
0
class DeleteUser(IAMRequest):
    DESCRIPTION = 'Delete a user'
    ARGS = [
        arg_user(help='name of the user to delete (required)'),
        Arg('-r',
            '--recursive',
            action='store_true',
            route_to=None,
            help='''remove all IAM resources associated with the user
                        first'''),
        Arg('-R',
            '--recursive-euca',
            dest='IsRecursive',
            action='store_const',
            const='true',
            help=argparse.SUPPRESS),
        Arg('-p',
            '--pretend',
            action='store_true',
            route_to=None,
            help='''list the resources that would be deleted instead of
                        actually deleting them. Implies -r.'''), AS_ACCOUNT
    ]

    def main(self):
        if self.args['recursive'] or self.args['pretend']:
            # Figure out what we'd have to delete
            req = ListAccessKeys.from_other(
                self,
                UserName=self.args['UserName'],
                DelegateAccount=self.params['DelegateAccount'])
            keys = req.main().get('AccessKeyMetadata', [])
            req = ListUserPolicies.from_other(
                self,
                UserName=self.args['UserName'],
                DelegateAccount=self.params['DelegateAccount'])
            policies = req.main().get('PolicyNames', [])
            req = ListSigningCertificates.from_other(
                self,
                UserName=self.args['UserName'],
                DelegateAccount=self.params['DelegateAccount'])
            certs = req.main().get('Certificates', [])
            req = ListGroupsForUser.from_other(
                self,
                UserName=self.args['UserName'],
                DelegateAccount=self.params['DelegateAccount'])
            groups = req.main().get('Groups', [])
            req = GetLoginProfile.from_other(
                self,
                UserName=self.args['UserName'],
                DelegateAccount=self.params['DelegateAccount'])
            try:
                # This will raise an exception if no login profile is found.
                req.main()
                has_login_profile = True
            except AWSError as err:
                if err.code == 'NoSuchEntity':
                    # It doesn't exist
                    has_login_profile = False
                else:
                    # Something else went wrong; not our problem
                    raise
        else:
            # Just in case
            keys = []
            policies = []
            certs = []
            groups = []
            has_login_profile = False
        if self.args['pretend']:
            return {
                'keys': keys,
                'policies': policies,
                'certificates': certs,
                'groups': groups,
                'has_login_profile': has_login_profile
            }
        else:
            if self.args['recursive']:
                for key in keys:
                    req = DeleteAccessKey.from_other(
                        self,
                        UserName=self.args['UserName'],
                        AccessKeyId=key['AccessKeyId'],
                        DelegateAccount=self.params['DelegateAccount'])
                    req.main()
                for policy in policies:
                    req = DeleteUserPolicy.from_other(
                        self,
                        UserName=self.args['UserName'],
                        PolicyName=policy,
                        DelegateAccount=self.params['DelegateAccount'])
                    req.main()
                for cert in certs:
                    req = DeleteSigningCertificate.from_other(
                        self,
                        UserName=self.args['UserName'],
                        CertificateId=cert['CertificateId'],
                        DelegateAccount=self.params['DelegateAccount'])
                    req.main()
                for group in groups:
                    req = RemoveUserFromGroup.from_other(
                        self,
                        user_names=[self.args['UserName']],
                        GroupName=group['GroupName'],
                        DelegateAccount=self.params['DelegateAccount'])
                    req.main()
                if has_login_profile:
                    req = DeleteLoginProfile.from_other(
                        self,
                        UserName=self.args['UserName'],
                        DelegateAccount=self.params['DelegateAccount'])
                    req.main()
            return self.send()

    def print_result(self, result):
        if self.args['pretend']:
            print 'accesskeys'
            for key in result['keys']:
                print '\t' + key['AccessKeyId']
            print 'policies'
            for policy in result['policies']:
                print '\t' + policy
            print 'certificates'
            for cert in result['certificates']:
                print '\t' + cert['CertificateId']
            print 'groups'
            for group in result['groups']:
                print '\t' + group['Arn']
Beispiel #23
0
class DeleteLoginProfile(IAMRequest):
    DESCRIPTION = "Delete a user's password"
    ARGS = [arg_user(help='''name of the user whose password should be
                     deleted (required)'''),
            AS_ACCOUNT]
class ListUserPolicies(IAMRequest):
    DESCRIPTION = 'List one or all policies attached to a user'
    ARGS = [
        arg_user(help='user owning the policies to list (required)'),
        Arg('-p',
            '--policy-name',
            metavar='POLICY',
            route_to=None,
            help='display a specific policy'),
        Arg('-v',
            '--verbose',
            action='store_true',
            route_to=None,
            help='''display the contents of the resulting policies (in
                        addition to their names)'''),
        Arg('--pretty-print',
            action='store_true',
            route_to=None,
            help='''when printing the contents of policies, reformat them
                        for easier reading'''), AS_ACCOUNT
    ]
    LIST_TAGS = ['PolicyNames']

    def main(self):
        return PaginatedResponse(self, (None, ), ('PolicyNames', ))

    def prepare_for_page(self, page):
        # Pages are defined by markers
        self.params['Marker'] = page

    # pylint: disable=no-self-use
    def get_next_page(self, response):
        if response.get('IsTruncated') == 'true':
            return response['Marker']

    # pylint: enable=no-self-use

    def print_result(self, result):
        if self.args.get('policy_name'):
            # Look for the specific policy the user asked for
            for policy_name in result.get('PolicyNames', []):
                if policy_name == self.args['policy_name']:
                    if self.args['verbose']:
                        self.print_policy(policy_name)
                    else:
                        print policy_name
                    break
        else:
            for policy_name in result.get('PolicyNames', []):
                print policy_name
                if self.args['verbose']:
                    self.print_policy(policy_name)
        # We already take care of pagination
        print 'IsTruncated: false'

    def print_policy(self, policy_name):
        req = GetUserPolicy.from_other(
            self,
            UserName=self.args['UserName'],
            PolicyName=policy_name,
            pretty_print=self.args['pretty_print'],
            DelegateAccount=self.params.get('DelegateAccount'))
        response = req.main()
        req.print_result(response)