diff options
author | Colin Watson <cjwatson@debian.org> | 2017-12-12 15:20:49 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2017-12-12 15:20:49 +0000 |
commit | 9e4403035a9953c99117083e6373ae3c441a76b5 (patch) | |
tree | d91b137df6767bfb8cb72de6b9fd21efb0c3dee4 /macaroonbakery/httpbakery/agent | |
parent | 949b7072cabce0daed6c94993ad44c8ea8648dbd (diff) |
Import py-macaroon-bakery_1.1.0.orig.tar.gz
Diffstat (limited to 'macaroonbakery/httpbakery/agent')
-rw-r--r-- | macaroonbakery/httpbakery/agent/__init__.py | 8 | ||||
-rw-r--r-- | macaroonbakery/httpbakery/agent/_agent.py (renamed from macaroonbakery/httpbakery/agent/agent.py) | 115 |
2 files changed, 63 insertions, 60 deletions
diff --git a/macaroonbakery/httpbakery/agent/__init__.py b/macaroonbakery/httpbakery/agent/__init__.py index db252de..c0a7523 100644 --- a/macaroonbakery/httpbakery/agent/__init__.py +++ b/macaroonbakery/httpbakery/agent/__init__.py @@ -1,8 +1,9 @@ # Copyright 2017 Canonical Ltd. # Licensed under the LGPLv3, see LICENCE file for details. -from macaroonbakery.httpbakery.agent.agent import ( - load_agent_file, +from ._agent import ( + load_auth_info, + read_auth_info, Agent, AgentInteractor, AgentFileFormatError, @@ -13,5 +14,6 @@ __all__ = [ 'AgentFileFormatError', 'AgentInteractor', 'AuthInfo', - 'load_agent_file', + 'load_auth_info', + 'read_auth_info', ] diff --git a/macaroonbakery/httpbakery/agent/agent.py b/macaroonbakery/httpbakery/agent/_agent.py index ad56015..b717261 100644 --- a/macaroonbakery/httpbakery/agent/agent.py +++ b/macaroonbakery/httpbakery/agent/_agent.py @@ -1,20 +1,18 @@ # Copyright 2017 Canonical Ltd. # Licensed under the LGPLv3, see LICENCE file for details. -import base64 -from collections import namedtuple +import copy import json +import logging +from collections import namedtuple -import nacl.public -import nacl.encoding -import nacl.exceptions +import macaroonbakery.bakery as bakery +import macaroonbakery.httpbakery as httpbakery +import macaroonbakery._utils as utils import requests.cookies -import six -from six.moves.urllib.parse import urlparse + from six.moves.urllib.parse import urljoin -import macaroonbakery as bakery -import macaroonbakery.utils as utils -import macaroonbakery.httpbakery as httpbakery +log = logging.getLogger(__name__) class AgentFileFormatError(Exception): @@ -24,40 +22,41 @@ class AgentFileFormatError(Exception): pass -def load_agent_file(filename, cookies=None): - ''' Loads agent information from the specified file. - - The agent cookies are added to cookies, or a newly created cookie jar - if cookies is not specified. The updated cookies is returned along - with the private key associated with the agent. These can be passed - directly as the cookies and key parameter to BakeryAuth. +def load_auth_info(filename): + '''Loads agent authentication information from the specified file. + The returned information is suitable for passing as an argument + to the AgentInteractor constructor. + @param filename The name of the file to open (str) + @return AuthInfo The authentication information + @raises AgentFileFormatError when the file format is bad. ''' - with open(filename) as f: - data = json.load(f) + return read_auth_info(f.read()) + + +def read_auth_info(agent_file_content): + '''Loads agent authentication information from the + specified content string, as read from an agents file. + The returned information is suitable for passing as an argument + to the AgentInteractor constructor. + @param agent_file_content The agent file content (str) + @return AuthInfo The authentication information + @raises AgentFileFormatError when the file format is bad. + ''' try: - key = nacl.public.PrivateKey( - data['key']['private'], - nacl.encoding.Base64Encoder, + data = json.loads(agent_file_content) + return AuthInfo( + key=bakery.PrivateKey.deserialize(data['key']['private']), + agents=list( + Agent(url=a['url'], username=a['username']) + for a in data.get('agents', []) + ), ) - if cookies is None: - cookies = requests.cookies.RequestsCookieJar() - for agent in data['agents']: - u = urlparse(agent['url']) - value = {'username': agent['username'], - 'public_key': data['key']['public']} - jv = json.dumps(value) - if six.PY3: - jv = jv.encode('utf-8') - v = base64.b64encode(jv) - if six.PY3: - v = v.decode('utf-8') - cookie = requests.cookies.create_cookie('agent-login', v, - domain=u.netloc, - path=u.path) - cookies.set_cookie(cookie) - return cookies, key - except (KeyError, ValueError, nacl.exceptions.TypeError) as e: + except ( + KeyError, + ValueError, + TypeError, + ) as e: raise AgentFileFormatError('invalid agent file', e) @@ -110,9 +109,10 @@ class AgentInteractor(httpbakery.Interactor, httpbakery.LegacyInteractor): if not location.endswith('/'): location += '/' login_url = urljoin(location, p.login_url) + # TODO use client to make the request. resp = requests.get(login_url, json={ 'Username': agent.username, - 'PublicKey': self._auth_info.key.encode().decode('utf-8'), + 'PublicKey': str(self._auth_info.key), }) if resp.status_code != 200: raise httpbakery.InteractionError( @@ -144,30 +144,31 @@ class AgentInteractor(httpbakery.Interactor, httpbakery.LegacyInteractor): the discharge macaroon using the client's private key ''' agent = self._find_agent(location) - pk_encoded = self._auth_info.key.public_key.encode().decode('utf-8') - value = { - 'username': agent.username, - 'public_key': pk_encoded, - } - # TODO(rogpeppe) use client passed into interact method. - client = httpbakery.Client(key=self._auth_info.key) - client.cookies.set_cookie(utils.cookie( + # Shallow-copy the client so that we don't unexpectedly side-effect + # it by changing the key. Another possibility might be to + # set up agent authentication differently, in such a way that + # we're sure that client.key is the same as self._auth_info.key. + client = copy.copy(client) + client.key = self._auth_info.key + resp = client.request( + method='POST', url=visit_url, - name='agent-login', - value=base64.urlsafe_b64encode( - json.dumps(value).encode('utf-8')).decode('utf-8'), - )) - resp = requests.get(url=visit_url, cookies=client.cookies, auth=client.auth()) + json={ + 'username': agent.username, + 'public_key': str(self._auth_info.key.public_key), + }, + ) if resp.status_code != 200: raise httpbakery.InteractionError( - 'cannot acquire agent macaroon: {}'.format(resp.status_code)) - if not resp.json().get('agent-login', False): + 'cannot acquire agent macaroon from {}: {} (response body: {!r})'.format(visit_url, resp.status_code, resp.text)) + if not resp.json().get('agent_login', False): raise httpbakery.InteractionError('agent login failed') class Agent(namedtuple('Agent', 'url, username')): ''' Represents an agent that can be used for agent authentication. - @param url holds the URL of the discharger that knows about the agent (string). + @param url(string) holds the URL of the discharger that knows about + the agent. @param username holds the username agent (string). ''' |