blob: 0fcc17e5a8c831bcdcdf090bfcbc61ed0cedf7d4 [file] [log] [blame]
Vadim Shtayurac4c76b62014-01-13 15:05:41 -08001#!/usr/bin/env python
2# Copyright 2013 The Swarming Authors. All rights reserved.
3# Use of this source code is governed under the Apache License, Version 2.0 that
4# can be found in the LICENSE file.
5
6"""Client tool to perform various authentication related tasks."""
7
8__version__ = '0.3'
9
10import optparse
11import sys
12
13from third_party import colorama
14from third_party.depot_tools import fix_encoding
15from third_party.depot_tools import subcommand
16
17from utils import net
18from utils import oauth
19from utils import tools
20
21
22def add_auth_options(parser):
23 """Adds command line options related to authentication."""
24 parser.auth_group = optparse.OptionGroup(parser, 'Authentication')
25 parser.auth_group.add_option(
26 '--use-cookie-auth', action='store_true',
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080027 help='Use cookie authentication instead of OAuth2.')
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080028 parser.add_option_group(parser.auth_group)
29 oauth.add_oauth_options(parser)
30
31
32def process_auth_options(options):
33 """Configures process-wide authentication parameters based on |options|."""
34 method = 'cookie' if options.use_cookie_auth else 'oauth'
35 net.configure_auth(method, oauth_options=options)
36
37
38class AuthServiceError(Exception):
39 """Unexpected response from authentication service."""
40
41
42class AuthService(object):
43 """Represents remote Authentication service."""
44
45 def __init__(self, url):
46 self._service = net.get_http_service(url)
47
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080048 def login(self, allow_user_interaction):
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080049 """Refreshes cached access token or creates a new one."""
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080050 return self._service.login(allow_user_interaction)
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080051
52 def logout(self):
53 """Purges cached access token."""
54 return self._service.logout()
55
56 def get_current_identity(self):
57 """Returns identity associated with currently used credentials.
58
59 Identity is a string:
60 user:<email> - if using OAuth or cookie based authentication.
61 bot:<id> - if using HMAC based authentication.
62 anonymous:anonymous - if not authenticated.
63 """
64 identity = self._service.json_request('GET', '/auth/api/v1/accounts/self')
65 if not identity:
66 raise AuthServiceError('Failed to fetch identity')
67 return identity['identity']
68
69
70@subcommand.usage('[options]')
71def CMDlogin(parser, args):
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080072 """Runs interactive login flow and stores auth token/cookie on disk."""
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080073 (options, args) = parser.parse_args(args)
74 process_auth_options(options)
75 service = AuthService(options.service)
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080076 if service.login(True):
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080077 print 'Logged in as \'%s\'.' % service.get_current_identity()
78 return 0
79 else:
80 print 'Login failed or canceled.'
81 return 1
82
83
84@subcommand.usage('[options]')
85def CMDlogout(parser, args):
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080086 """Purges cached auth token/cookie."""
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080087 (options, args) = parser.parse_args(args)
88 process_auth_options(options)
89 service = AuthService(options.service)
90 service.logout()
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080091 return 0
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080092
93
94@subcommand.usage('[options]')
95def CMDcheck(parser, args):
Vadim Shtayurae34e13a2014-02-02 11:23:26 -080096 """Shows identity associated with currently cached auth token/cookie."""
Vadim Shtayurac4c76b62014-01-13 15:05:41 -080097 (options, args) = parser.parse_args(args)
98 process_auth_options(options)
99 service = AuthService(options.service)
Vadim Shtayurae34e13a2014-02-02 11:23:26 -0800100 service.login(False)
Vadim Shtayurac4c76b62014-01-13 15:05:41 -0800101 print service.get_current_identity()
Vadim Shtayurae34e13a2014-02-02 11:23:26 -0800102 return 0
Vadim Shtayurac4c76b62014-01-13 15:05:41 -0800103
104
105class OptionParserAuth(tools.OptionParserWithLogging):
106 def __init__(self, **kwargs):
107 tools.OptionParserWithLogging.__init__(self, prog='auth.py', **kwargs)
108 self.server_group = tools.optparse.OptionGroup(self, 'Server')
109 self.server_group.add_option(
110 '-S', '--service',
111 metavar='URL', default='',
112 help='Service to use')
113 self.add_option_group(self.server_group)
114 add_auth_options(self)
115
116 def parse_args(self, *args, **kwargs):
117 options, args = tools.OptionParserWithLogging.parse_args(
118 self, *args, **kwargs)
119 options.service = options.service.rstrip('/')
120 if not options.service:
121 self.error('--service is required.')
122 return options, args
123
124
125def main(args):
126 dispatcher = subcommand.CommandDispatcher(__name__)
127 try:
128 return dispatcher.execute(OptionParserAuth(version=__version__), args)
129 except Exception as e:
130 tools.report_error(e)
131 return 1
132
133
134if __name__ == '__main__':
135 fix_encoding.fix_encoding()
136 tools.disable_buffering()
137 colorama.init()
138 sys.exit(main(sys.argv[1:]))