summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Wirzenius <liw@liw.fi>2019-01-24 10:10:11 +0200
committerLars Wirzenius <liw@liw.fi>2019-01-24 10:10:11 +0200
commit478512d10ef861c05c7fb5e08b046d340636aef9 (patch)
treee04de686ff5748e249753bab7f6c3a5e11d2e57d
parent9570f628ec485cb2fe52685555103dfe2a89e596 (diff)
downloadeffitool-478512d10ef861c05c7fb5e08b046d340636aef9.tar.gz
Add: first step at creating client
-rw-r--r--README11
-rwxr-xr-xeffitool84
2 files changed, 92 insertions, 3 deletions
diff --git a/README b/README
index ccc3425..9320fb7 100644
--- a/README
+++ b/README
@@ -43,6 +43,17 @@ To check the status of the membership register:
./effitool status
+To register a new API client:
+
+ ./effitool register-client ID SECRET
+
+where `ID` is the client id and `SECRET` is the client secret. The new
+client will automatically be allowed the scopes. Note that the
+`credentials.conf` file is NOT updated: this command is for
+registering API clients for other people, who do not have access to
+the config file.
+
+
Legalese
-----------------------------------------------------------------------------
diff --git a/effitool b/effitool
index 1032da5..74da7be 100755
--- a/effitool
+++ b/effitool
@@ -17,6 +17,7 @@
import argparse
+import base64
import configparser
import http
import json
@@ -27,6 +28,7 @@ import urllib.request
CONFIG_FILENAME = os.path.expanduser('~/.config/effitool/credentials.conf')
JSON = 'application/json'
+URLENC = 'application/x-www-form-urlencoded'
class Config:
@@ -44,6 +46,12 @@ class Config:
def servers(self):
return [k for k in self._cp.keys() if k != 'DEFAULT']
+ def get_default_server(self):
+ sections = self._cp.sections()
+ if len(sections) != 1:
+ raise Exception('Config must have exactly one server')
+ return sections[0]
+
def get(self, name):
server = self._cp[name]
return {
@@ -76,6 +84,52 @@ class HTTPAPI:
body = r.read()
return json.loads(body)
+ def post_form(self, path, user, password, **kwargs):
+ url = self.url(path)
+ host, port, path = self.parse_url(url)
+
+ data = urllib.parse.urlencode(kwargs).encode('UTF-8')
+ headers = {
+ 'Content-type': URLENC,
+ 'Authorization': self.get_authorization(user, password),
+ }
+
+ req = urllib.request.Request(
+ url, data=data, headers=headers, method='POST')
+ r = urllib.request.urlopen(req)
+
+ status = r.getcode()
+ if status != http.HTTPStatus.OK:
+ raise Exception('Got HTTP status {}'.format(status))
+
+ info = r.info()
+ ct = info.get_content_type()
+ if ct != JSON:
+ raise Exception('Response is not JSON: {}'.ct)
+
+ body = r.read()
+ return json.loads(body)
+
+ def parse_url(self, url):
+ parse = urllib.parse.urlparse(url)
+ if parse.scheme != 'https':
+ raise Exception(
+ 'URL scheme must be https, not {}'.format(parse.scheme))
+
+ if ':' in parse.netloc:
+ host, port = parse.netloc.split(':', 1)
+ port = int(port)
+ else:
+ host = parse.netloc
+ port = None
+
+ return host, port, parse.path
+
+ def get_authorization(self, user, password):
+ clear = '{}:{}'.format(user, password)
+ basic = base64.b64encode(clear.encode('UTF-8'))
+ return 'Basic {}'.format(basic.decode('UTF-8'))
+
def list_servers(args, config):
for name in config.servers():
@@ -94,17 +148,41 @@ def status(args, config):
print('server', name, obj['resources'])
+def register_client(args, config):
+ new_client_id = args['client_id']
+ new_client_secret = args['client_secret']
+ name = config.get_default_server()
+ server = config.get(name)
+ url = server['url']
+ client_id = server['client_id']
+ client_secret = server['client_secret']
+ api = HTTPAPI(url)
+ r = api.post_form(
+ '/token', client_id, client_secret,
+ grant_type='client_credentials', scope='xxx')
+ token = r['access_token']
+
+ print('NEED TO ACTUALLY CREATE CLIENT HERE')
+ assert 0
+
+
def process_args(config):
subcommands = [
- ('list-servers', list_servers),
- ('status', status),
+ ('list-servers', list_servers, []),
+ ('status', status, []),
+ ('register-client', register_client, [
+ ('--client-id', {'required':True}),
+ ('--client-secret', {'required':True}),
+ ]),
]
p = argparse.ArgumentParser()
factory = p.add_subparsers()
- for name, func in subcommands:
+ for name, func, args in subcommands:
pp = factory.add_parser(name)
+ for name, kwargs in args:
+ pp.add_argument(name, **kwargs)
pp.set_defaults(func=func)
args = vars(p.parse_args())