mirror of
https://github.com/khornberg/octokit.py
synced 2026-05-22 15:03:52 +03:00
Feature: Add authentication as app -- Breaking Change!
Previously 'app' auth was actually authentication as an 'installation'. This corrects that. Use auth="installation".
This commit is contained in:
@@ -129,6 +129,10 @@ app::
|
||||
|
||||
octokit = Octokit(auth='app', app_id=42, private_key=private_key)
|
||||
|
||||
app::
|
||||
|
||||
octokit = Octokit(auth='installation', app_id=42, private_key=private_key)
|
||||
|
||||
For applications provide the application id either from the ping webhook or the application's page on GitHub.
|
||||
The :code:`private_key` is a string of your private key provided for the application.
|
||||
The :code:`app` scheme will use the application id and private key to get a token for the first installation id of the application.
|
||||
|
||||
@@ -21,7 +21,7 @@ def read(*names, **kwargs):
|
||||
|
||||
setup(
|
||||
name='octokitpy',
|
||||
version='0.5.0',
|
||||
version='0.6.0',
|
||||
license='MIT license',
|
||||
description='Python client for GitHub API',
|
||||
long_description='%s\n%s' % (
|
||||
|
||||
+16
-4
@@ -55,6 +55,7 @@ class Base(object):
|
||||
authentication_schemes = {
|
||||
'basic': self._setup_basic_authentication,
|
||||
'token': self._setup_token_authentication,
|
||||
'installation': self._setup_installation_authentication,
|
||||
'app': self._setup_app_authentication,
|
||||
}
|
||||
if kwargs.get('auth'):
|
||||
@@ -72,13 +73,20 @@ class Base(object):
|
||||
self.token = kwargs['token']
|
||||
self.auth = kwargs['auth']
|
||||
|
||||
def _setup_app_authentication(self, kwargs):
|
||||
def _setup_installation_authentication(self, kwargs):
|
||||
assert kwargs['app_id']
|
||||
assert kwargs['private_key']
|
||||
self.token, self.expires_at = self._app_auth_get_token(kwargs['app_id'], kwargs['private_key'])
|
||||
self.auth = kwargs['auth']
|
||||
self.headers['accept'] = 'application/vnd.github.machine-man-preview+json'
|
||||
|
||||
def _setup_app_authentication(self, kwargs):
|
||||
assert kwargs['app_id']
|
||||
assert kwargs['private_key']
|
||||
self.jwt = self._app_auth_get_jwt(kwargs['app_id'], kwargs['private_key'])
|
||||
self.auth = kwargs['auth']
|
||||
self.headers['accept'] = 'application/vnd.github.machine-man-preview+json'
|
||||
|
||||
def _app_auth_get_token(self, app_id, key):
|
||||
headers = {
|
||||
'Authorization': 'Bearer {}'.format(self._app_auth_get_jwt(app_id, key)),
|
||||
@@ -86,8 +94,8 @@ class Base(object):
|
||||
}
|
||||
installation_url = '{}/app/installations'.format(self.base_url)
|
||||
installations = requests.get(installation_url, headers=headers).json()
|
||||
installation_id = installations[0]['id']
|
||||
installation_token_url = '{}/installations/{}/access_tokens'.format(self.base_url, installation_id)
|
||||
self.installation_id = [x.get('id') for x in installations if x.get('app_id') == app_id].pop()
|
||||
installation_token_url = '{}/installations/{}/access_tokens'.format(self.base_url, self.installation_id)
|
||||
response = requests.post(installation_token_url, headers=headers).json()
|
||||
return response['token'], response['expires_at']
|
||||
|
||||
@@ -102,7 +110,11 @@ class Base(object):
|
||||
def _auth(self, requests_kwargs):
|
||||
if getattr(self, 'auth', None) == 'basic':
|
||||
return {'auth': (self.username, self.password)}
|
||||
if getattr(self, 'auth', None) in ['token', 'app']:
|
||||
if getattr(self, 'auth', None) in ['app']:
|
||||
headers = requests_kwargs['headers']
|
||||
headers.update({'Authorization': 'Bearer {}'.format(self.jwt)})
|
||||
return {'headers': headers}
|
||||
if getattr(self, 'auth', None) in ['token', 'installation']:
|
||||
headers = requests_kwargs['headers']
|
||||
headers.update({'Authorization': 'token {}'.format(self.token)})
|
||||
return {'headers': headers}
|
||||
|
||||
+33
-12
@@ -58,38 +58,39 @@ class TestAuth(object):
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
def test_can_set_app_authentication(self, mocker):
|
||||
def test_can_set_installation_authentication(self, mocker):
|
||||
Request = namedtuple('Request', ['json'])
|
||||
get = mocker.patch('requests.get')
|
||||
get.return_value = Request(json=lambda: [{'id': 37}])
|
||||
get.return_value = Request(json=lambda: [{'id': 13, 'app_id': 1}, {'id': 37, 'app_id': 42}])
|
||||
post = mocker.patch('requests.post')
|
||||
post.return_value = Request(json=lambda: {'token': 'v1.1f699f1069f60', 'expires_at': '2016-07-11T22:14:10Z'})
|
||||
with open(os.path.join(os.path.dirname(__file__), 'test.pem'), 'r') as f:
|
||||
private_key = f.read()
|
||||
sut = Octokit(auth='app', app_id=42, private_key=private_key)
|
||||
assert sut.auth == 'app'
|
||||
sut = Octokit(auth='installation', app_id=42, private_key=private_key)
|
||||
assert sut.auth == 'installation'
|
||||
assert sut.token == 'v1.1f699f1069f60'
|
||||
assert sut.expires_at == '2016-07-11T22:14:10Z'
|
||||
|
||||
def test_cannot_set_app_authentication_with_out_required_data(self):
|
||||
def test_cannot_set_installation_authentication_with_out_required_data(self):
|
||||
with pytest.raises(KeyError):
|
||||
Octokit(auth='app')
|
||||
Octokit(auth='installation')
|
||||
with pytest.raises(AssertionError):
|
||||
Octokit(auth='app', app_id='')
|
||||
Octokit(auth='installation', app_id='')
|
||||
with pytest.raises(KeyError):
|
||||
Octokit(auth='app', app_id=42)
|
||||
Octokit(auth='installation', app_id=42)
|
||||
with pytest.raises(AssertionError):
|
||||
Octokit(auth='app', app_id=42, private_key='')
|
||||
Octokit(auth='installation', app_id=42, private_key='')
|
||||
|
||||
def test_app_token_is_used_if_set(self, mocker):
|
||||
def test_installation_token_is_used_if_set(self, mocker):
|
||||
Request = namedtuple('Request', ['json'])
|
||||
get = mocker.patch('requests.get')
|
||||
get.return_value = Request(json=lambda: [{'id': 37}])
|
||||
get.return_value = Request(json=lambda: [{'id': 13, 'app_id': 1}, {'id': 37, 'app_id': 42}])
|
||||
post = mocker.patch('requests.post')
|
||||
post.return_value = Request(json=lambda: {'token': 'v1.1f699f1069f60', 'expires_at': '2016-07-11T22:14:10Z'})
|
||||
with open(os.path.join(os.path.dirname(__file__), 'test.pem'), 'r') as f:
|
||||
private_key = f.read()
|
||||
sut = Octokit(auth='app', app_id=42, private_key=private_key)
|
||||
sut = Octokit(auth='installation', app_id=42, private_key=private_key)
|
||||
assert sut.installation_id == 37
|
||||
get = mocker.patch('requests.get')
|
||||
sut.authorization.get(id=100)
|
||||
headers = {
|
||||
@@ -102,3 +103,23 @@ class TestAuth(object):
|
||||
params={},
|
||||
headers=headers,
|
||||
)
|
||||
|
||||
def test_cannot_set_app_authentication_with_out_required_data(self):
|
||||
with pytest.raises(KeyError):
|
||||
Octokit(auth='app')
|
||||
with pytest.raises(AssertionError):
|
||||
Octokit(auth='app', app_id='')
|
||||
with pytest.raises(KeyError):
|
||||
Octokit(auth='app', app_id=42)
|
||||
with pytest.raises(AssertionError):
|
||||
Octokit(auth='app', app_id=42, private_key='')
|
||||
|
||||
def test_can_set_app_authentication(self, mocker):
|
||||
Request = namedtuple('Request', ['json'])
|
||||
get = mocker.patch('requests.get')
|
||||
get.return_value = Request(json=lambda: [{'id': 37}])
|
||||
with open(os.path.join(os.path.dirname(__file__), 'test.pem'), 'r') as f:
|
||||
private_key = f.read()
|
||||
sut = Octokit(auth='app', app_id=42, private_key=private_key)
|
||||
assert sut.auth == 'app'
|
||||
assert sut.jwt is not None
|
||||
|
||||
Reference in New Issue
Block a user