""" Manage your Anaconda repository channels. """ from __future__ import unicode_literals, print_function import socket import sys from datetime import datetime, timedelta import logging import argparse from argparse import FileType from .. import errors from .base import SubCommandBase logger = logging.getLogger('repo_cli') class SubCommand(SubCommandBase): name = "auth" def main(self): if self.args.info: self.show_token_info() elif self.args.list: self.show_tokens() return elif self.args.remove: self.remove_tokens(self.args.remove) return elif self.args.list_scopes: self.show_scopes() elif self.args.create: self.create_token(self.args.name, self.args.scopes, self.args.max_age) def create_token(self, name, scopes, max_age): # for this one we need to ask with the JWT... if not self.api._jwt: token = self.parent.auth_manager.interactive_get_token() if not self.api._jwt: self.log.info('Failed to authenticate...') return if not scopes: self.log.warning("You have not specified the scope of this token with the '--scopes' argument.") self.log.warning("This token will grant full access to %s's account" % (self.parent.auth_manager.username)) self.log.warning("Use the --list-scopes option to see a listing of your options") scopes = self.api.get_scopes() expiration = str(datetime.now().date() + timedelta(seconds=max_age)) data = self.api.create_user_token(name, expiration, scopes=scopes, resources=None) self.log.info('Token {0} succesfully created with id: {1}'.format(data['token'], data['id'])) def show_scopes(self): scopes = self.api.get_scopes() self.log.info('') self.log.info('Available scopes:') self.log.info('') self.log.info(','.join(sorted(scopes))) self.log.info('') def remove_tokens(self, tokens): for token in tokens: self.api.remove_user_token(token) self.log.info('Token %s successfully removed.' % token) def show_token_info(self): if not self.api._access_token: raise errors.Unauthorized() data = self.api.get_token_info() self.log.info('') self.log.info('Token: %s' % self.api._access_token) self.log.info('Expiration: %s' % data.get('expires_at', 'n/a')) def show_tokens(self): # for this one we need to ask with the JWT... if not self.api._jwt: token = self.parent.auth_manager.login() if not self.api._jwt: self.log.info('Failed to authenticate...') return data = self.api.get_user_tokens() if data: self.log.info('') self.log.info("Tokens count: %s" % len(data['items'])) for token in data['items']: self.log.info("-----------------") self.log.info("id: %s" % token['id']) self.log.info("name: %s" % token['name']) self.log.info("created_at: %s" % token['created_at']) self.log.info("expires_at: %s" % token['expires_at']) self.log.info("type: %s" % token['type']) self.log.info("-----------------") self.log.info('') def add_parser(self, subparsers): description = 'Manage Authorization Tokens' parser = subparsers.add_parser(self.name, help=description, description=description, epilog=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument('-n', '--name', default='conda_repo:%s' % (socket.gethostname()), help='A unique name so you can identify this token later.') # parser.add_argument('-o', '--org', '--organization', help='Set the token owner (must be an organization)', # dest='organization') g = parser.add_argument_group('token creation arguments', 'These arguments are only valid with the `--create` action') # g.add_argument('--strength', choices=['strong', 'weak'], default='strong', dest='strength') # g.add_argument('--strong', action='store_const', const='strong', dest='strength', # help='Create a longer token (default)') # g.add_argument('-w', '--weak', action='store_const', const='weak', dest='strength', # help='Create a shorter token') # g.add_argument('--url', default='http://anaconda.org', # help='The url of the application that will use this token') age_in_days = 30 default_age = 86400 * age_in_days # 30 days g.add_argument('--max-age', type=int, default=default_age, help='The maximum age in seconds that this token will be valid for (default value is' \ ' %s that equals to %s days' % (default_age, age_in_days)) g.add_argument('-s', '--scopes', action='append', help=('Scopes for token. For example if you want to limit this token to conda ' 'downloads only you would use --scopes "repo artifact:download"'), default=[]) g.add_argument('--out', default=sys.stdout, type=FileType('w')) group = parser.add_argument_group("actions") group = group.add_mutually_exclusive_group(required=True) group.add_argument('-x', '--list-scopes', action='store_true', help='list all authentication scopes') group.add_argument('-l', '--list', action='store_true', help='list all user authentication tokens') group.add_argument('-r', '--remove', metavar='ID', nargs='+', help='remove authentication tokens') group.add_argument('-c', '--create', action='store_true', help='Create an authentication token') group.add_argument('-i', '--info', '--current-info', dest='info', action='store_true', help='Show information about the current authentication token') parser.set_defaults(main=self.main)