Merge "Bump pyjwt to 2.0.0"

This commit is contained in:
Zuul 2021-01-23 01:35:22 +00:00 committed by Gerrit Code Review
commit dc2d6c847d
9 changed files with 76 additions and 77 deletions

View File

@ -22,8 +22,7 @@ alembic
cryptography>=1.6 cryptography>=1.6
cachecontrol cachecontrol
cachetools cachetools
# PyJWT 2.0.0 has API breaking changes pyjwt>=2.0.0,<3.0
pyjwt<2.0.0
iso8601 iso8601
psutil psutil
fb-re2>=1.0.6 fb-re2>=1.0.6

View File

@ -17,6 +17,7 @@ import json
from unittest import mock from unittest import mock
import os.path import os.path
import jwt import jwt
from io import StringIO
import time import time
from zuul.driver import auth from zuul.driver import auth
@ -31,10 +32,10 @@ with open(os.path.join(FIXTURE_DIR,
algo = jwt.algorithms.RSAAlgorithm(jwt.algorithms.RSAAlgorithm.SHA256) algo = jwt.algorithms.RSAAlgorithm(jwt.algorithms.RSAAlgorithm.SHA256)
with open(os.path.join(FIXTURE_DIR, with open(os.path.join(FIXTURE_DIR,
'auth/oidc-key'), 'r') as k: 'auth/oidc-key'), 'r') as k:
OIDC_PRIVATE_KEY = algo.prepare_key(k.read().encode('utf-8')) OIDC_PRIVATE_KEY = algo.prepare_key(k.read())
with open(os.path.join(FIXTURE_DIR, with open(os.path.join(FIXTURE_DIR,
'auth/oidc-key.pub'), 'r') as k: 'auth/oidc-key.pub'), 'r') as k:
pub_key = algo.prepare_key(k.read().encode('utf-8')) pub_key = algo.prepare_key(k.read())
pub_jwk = algo.to_jwk(pub_key) pub_jwk = algo.to_jwk(pub_key)
key = { key = {
"kid": "OwO", "kid": "OwO",
@ -52,17 +53,6 @@ with open(os.path.join(FIXTURE_DIR,
} }
def mock_get(url, params=None, **kwargs):
if url == ("https://my.oidc.provider/auth/realms/realm-one/"
".well-known/openid-configuration"):
return FakeResponse(FAKE_WELL_KNOWN_CONFIG)
elif url == ("https://my.oidc.provider/auth/realms/realm-one/"
"protocol/openid-connect/certs"):
return FakeResponse(FAKE_CERTS)
else:
raise Exception("Unknown URL %s" % url)
class FakeResponse: class FakeResponse:
def __init__(self, json_dict): def __init__(self, json_dict):
self._json = json_dict self._json = json_dict
@ -71,6 +61,25 @@ class FakeResponse:
return self._json return self._json
def mock_get(url, params=None, **kwargs):
if url == ("https://my.oidc.provider/auth/realms/realm-one/"
".well-known/openid-configuration"):
return FakeResponse(FAKE_WELL_KNOWN_CONFIG)
else:
raise Exception("Unknown URL %s" % url)
def mock_urlopen(url, *args, **kwargs):
if url == ("https://my.oidc.provider/auth/realms/realm-one/"
"protocol/openid-connect/certs"):
io = StringIO()
json.dump(FAKE_CERTS, io)
io.seek(0)
return io
else:
raise Exception("Unknown URL %s" % url)
class TestOpenIDConnectAuthenticator(BaseTestCase): class TestOpenIDConnectAuthenticator(BaseTestCase):
def test_decodeToken(self): def test_decodeToken(self):
"""Test the decoding workflow""" """Test the decoding workflow"""
@ -92,6 +101,9 @@ class TestOpenIDConnectAuthenticator(BaseTestCase):
algorithm='RS256', algorithm='RS256',
headers={'kid': 'OwO'}) headers={'kid': 'OwO'})
with mock.patch('requests.get', side_effect=mock_get): with mock.patch('requests.get', side_effect=mock_get):
decoded = OIDCAuth.decodeToken(token) # patching call in PyJWKClient's fetch_data
for claim in payload.keys(): with mock.patch('urllib.request.urlopen',
self.assertEqual(payload[claim], decoded[claim]) side_effect=mock_urlopen):
decoded = OIDCAuth.decodeToken(token)
for claim in payload.keys():
self.assertEqual(payload[claim], decoded[claim])

View File

@ -136,9 +136,9 @@ class TestWebTokenClient(BaseClientTestCase):
key=self.config.get( key=self.config.get(
'auth zuul_operator', 'auth zuul_operator',
'secret'), 'secret'),
algorithm=self.config.get( algorithms=[self.config.get(
'auth zuul_operator', 'auth zuul_operator',
'driver'), 'driver')],
audience=self.config.get( audience=self.config.get(
'auth zuul_operator', 'auth zuul_operator',
'client_id'),) 'client_id'),)

View File

@ -1351,7 +1351,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='OnlyZuulNoDana', token = jwt.encode(authz, key='OnlyZuulNoDana',
algorithm='HS256').decode('utf-8') algorithm='HS256')
resp = self.post_url( resp = self.post_url(
"api/tenant/tenant-one/project/org/project/autohold", "api/tenant/tenant-one/project/org/project/autohold",
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -1386,7 +1386,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() - 3600} 'exp': time.time() - 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
resp = self.post_url( resp = self.post_url(
"api/tenant/tenant-one/project/org/project/autohold", "api/tenant/tenant-one/project/org/project/autohold",
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -1421,7 +1421,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
resp = self.post_url( resp = self.post_url(
"api/tenant/tenant-one/project/org/project/autohold", "api/tenant/tenant-one/project/org/project/autohold",
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -1461,7 +1461,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
'ref': None, 'ref': None,
'node_hold_expiration': None} 'node_hold_expiration': None}
good_token = jwt.encode(good_authz, key='NoDanaOnlyZuul', good_token = jwt.encode(good_authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
req = self.post_url( req = self.post_url(
'api/tenant/tenant-one/project/org/project/autohold', 'api/tenant/tenant-one/project/org/project/autohold',
headers={'Authorization': 'Bearer %s' % good_token}, headers={'Authorization': 'Bearer %s' % good_token},
@ -1495,7 +1495,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
req = self.post_url( req = self.post_url(
'api/tenant/tenant-one/project/org/project/autohold', 'api/tenant/tenant-one/project/org/project/autohold',
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -1521,7 +1521,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
def _init_autohold_delete(self, authz): def _init_autohold_delete(self, authz):
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
client = zuul.rpcclient.RPCClient('127.0.0.1', client = zuul.rpcclient.RPCClient('127.0.0.1',
self.gearman_server.port) self.gearman_server.port)
@ -1559,7 +1559,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
bad_token = jwt.encode(bad_authz, key='NoDanaOnlyZuul', bad_token = jwt.encode(bad_authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
resp = self.delete_url( resp = self.delete_url(
"api/tenant/tenant-one/autohold/%s" % request_id, "api/tenant/tenant-one/autohold/%s" % request_id,
headers={'Authorization': 'Bearer %s' % bad_token}) headers={'Authorization': 'Bearer %s' % bad_token})
@ -1603,7 +1603,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
path = "api/tenant/%(tenant)s/project/%(project)s/enqueue" path = "api/tenant/%(tenant)s/project/%(project)s/enqueue"
enqueue_args = {'tenant': 'tenant-one', enqueue_args = {'tenant': 'tenant-one',
'project': 'org/project', } 'project': 'org/project', }
@ -1655,7 +1655,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
req = self.post_url(path % enqueue_args, req = self.post_url(path % enqueue_args,
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
json=ref) json=ref)
@ -1696,7 +1696,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
path = "api/tenant/%(tenant)s/project/%(project)s/dequeue" path = "api/tenant/%(tenant)s/project/%(project)s/dequeue"
dequeue_args = {'tenant': 'tenant-one', dequeue_args = {'tenant': 'tenant-one',
'project': 'org/project', } 'project': 'org/project', }
@ -1818,7 +1818,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
'exp': time.time() + 3600, 'exp': time.time() + 3600,
'iat': time.time()} 'iat': time.time()}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
req = self.post_url( req = self.post_url(
'api/tenant/tenant-one/promote', 'api/tenant/tenant-one/promote',
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -1892,7 +1892,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
req = self.post_url( req = self.post_url(
'api/tenant/tenant-one/project/org/project/autohold', 'api/tenant/tenant-one/project/org/project/autohold',
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -1915,7 +1915,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
'project': project, } 'project': project, }
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
req = self.post_url(path % enqueue_args, req = self.post_url(path % enqueue_args,
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
json=change) json=change)
@ -1959,7 +1959,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
'groups': ['ghostbusters', 'secretary'], 'groups': ['ghostbusters', 'secretary'],
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
path = "api/tenant/%(tenant)s/project/%(project)s/enqueue" path = "api/tenant/%(tenant)s/project/%(project)s/enqueue"
enqueue_args = {'tenant': 'tenant-one', enqueue_args = {'tenant': 'tenant-one',
'project': 'org/project2', } 'project': 'org/project2', }
@ -1985,7 +1985,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
'car': 'ecto-1'}, 'car': 'ecto-1'},
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
path = "api/tenant/%(tenant)s/project/%(project)s/enqueue" path = "api/tenant/%(tenant)s/project/%(project)s/enqueue"
enqueue_args = {'tenant': 'tenant-one', enqueue_args = {'tenant': 'tenant-one',
'project': 'org/project', } 'project': 'org/project', }
@ -2007,7 +2007,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
'zuul': {'admin': admin_tenants}, 'zuul': {'admin': admin_tenants},
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
# TODO(mhu) deprecated, remove after next release # TODO(mhu) deprecated, remove after next release
req = self.get_url('/api/user/authorizations', req = self.get_url('/api/user/authorizations',
headers={'Authorization': 'Bearer %s' % token}) headers={'Authorization': 'Bearer %s' % token})
@ -2049,7 +2049,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
authz = test_user['authz'] authz = test_user['authz']
authz['exp'] = time.time() + 3600 authz['exp'] = time.time() + 3600
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
# TODO(mhu) deprecated, remove after next release # TODO(mhu) deprecated, remove after next release
req = self.get_url('/api/user/authorizations', req = self.get_url('/api/user/authorizations',
headers={'Authorization': 'Bearer %s' % token}) headers={'Authorization': 'Bearer %s' % token})
@ -2116,7 +2116,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
resp = self.post_url( resp = self.post_url(
"api/tenant/tenant-one/project/org/project/autohold", "api/tenant/tenant-one/project/org/project/autohold",
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -2152,7 +2152,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
'exp': time.time() + 7200, 'exp': time.time() + 7200,
'iat': time.time() + 3600} 'iat': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
resp = self.post_url( resp = self.post_url(
"api/tenant/tenant-one/project/org/project/autohold", "api/tenant/tenant-one/project/org/project/autohold",
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -2188,7 +2188,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
'exp': time.time() + 3600, 'exp': time.time() + 3600,
'iat': time.time()} 'iat': time.time()}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
time.sleep(10) time.sleep(10)
resp = self.post_url( resp = self.post_url(
"api/tenant/tenant-one/project/org/project/autohold", "api/tenant/tenant-one/project/org/project/autohold",
@ -2232,7 +2232,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
'exp': time.time() + 3600, 'exp': time.time() + 3600,
'iat': time.time()} 'iat': time.time()}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
req = self.post_url( req = self.post_url(
'api/tenant/tenant-one/project/org/project/autohold', 'api/tenant/tenant-one/project/org/project/autohold',
headers={'Authorization': 'Bearer %s' % token}, headers={'Authorization': 'Bearer %s' % token},
@ -2336,7 +2336,7 @@ class TestCLIViaWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
[os.path.join(sys.prefix, 'bin/zuul'), [os.path.join(sys.prefix, 'bin/zuul'),
'--zuul-url', self.base_url, '--auth-token', token, '--zuul-url', self.base_url, '--auth-token', token,
@ -2375,7 +2375,7 @@ class TestCLIViaWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
[os.path.join(sys.prefix, 'bin/zuul'), [os.path.join(sys.prefix, 'bin/zuul'),
'--zuul-url', self.base_url, '--auth-token', token, '--zuul-url', self.base_url, '--auth-token', token,
@ -2404,7 +2404,7 @@ class TestCLIViaWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
[os.path.join(sys.prefix, 'bin/zuul'), [os.path.join(sys.prefix, 'bin/zuul'),
'--zuul-url', self.base_url, '--auth-token', token, '--zuul-url', self.base_url, '--auth-token', token,
@ -2440,7 +2440,7 @@ class TestCLIViaWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
[os.path.join(sys.prefix, 'bin/zuul'), [os.path.join(sys.prefix, 'bin/zuul'),
'--zuul-url', self.base_url, '--auth-token', token, '--zuul-url', self.base_url, '--auth-token', token,
@ -2491,7 +2491,7 @@ class TestCLIViaWebApi(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
[os.path.join(sys.prefix, 'bin/zuul'), [os.path.join(sys.prefix, 'bin/zuul'),
'--zuul-url', self.base_url, '--auth-token', token, '--zuul-url', self.base_url, '--auth-token', token,

View File

@ -169,7 +169,7 @@ class TestZuulClientAdmin(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
['zuul-client', ['zuul-client',
'--zuul-url', self.base_url, '--auth-token', token, '-v', '--zuul-url', self.base_url, '--auth-token', token, '-v',
@ -209,7 +209,7 @@ class TestZuulClientAdmin(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
['zuul-client', ['zuul-client',
'--zuul-url', self.base_url, '--auth-token', token, '-v', '--zuul-url', self.base_url, '--auth-token', token, '-v',
@ -245,7 +245,7 @@ class TestZuulClientAdmin(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
['zuul-client', ['zuul-client',
'--zuul-url', self.base_url, '--auth-token', token, '-v', '--zuul-url', self.base_url, '--auth-token', token, '-v',
@ -287,7 +287,7 @@ class TestZuulClientAdmin(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
['zuul-client', ['zuul-client',
'--zuul-url', self.base_url, '--auth-token', token, '-v', '--zuul-url', self.base_url, '--auth-token', token, '-v',
@ -338,7 +338,7 @@ class TestZuulClientAdmin(BaseTestWeb):
}, },
'exp': time.time() + 3600} 'exp': time.time() + 3600}
token = jwt.encode(authz, key='NoDanaOnlyZuul', token = jwt.encode(authz, key='NoDanaOnlyZuul',
algorithm='HS256').decode('utf-8') algorithm='HS256')
p = subprocess.Popen( p = subprocess.Popen(
['zuul-client', ['zuul-client',
'--zuul-url', self.base_url, '--auth-token', token, '-v', '--zuul-url', self.base_url, '--auth-token', token, '-v',

View File

@ -581,7 +581,7 @@ class Client(zuul.cmd.ZuulApp):
try: try:
auth_token = jwt.encode(token, auth_token = jwt.encode(token,
key=key, key=key,
algorithm=driver).decode('utf-8') algorithm=driver)
print("Bearer %s" % auth_token) print("Bearer %s" % auth_token)
err_code = 0 err_code = 0
except Exception as e: except Exception as e:

View File

@ -18,7 +18,6 @@ import math
import time import time
import jwt import jwt
import requests import requests
import json
from urllib.parse import urljoin from urllib.parse import urljoin
from zuul import exceptions from zuul import exceptions
@ -74,16 +73,16 @@ class JWTAuthenticator(AuthenticatorInterface):
except jwt.exceptions.InvalidSignatureError: except jwt.exceptions.InvalidSignatureError:
raise exceptions.AuthTokenInvalidSignatureException( raise exceptions.AuthTokenInvalidSignatureException(
realm=self.realm) realm=self.realm)
except jwt.DecodeError: except jwt.exceptions.DecodeError:
raise exceptions.AuthTokenUndecodedException( raise exceptions.AuthTokenUndecodedException(
realm=self.realm) realm=self.realm)
except jwt.exceptions.ExpiredSignatureError: except jwt.exceptions.ExpiredSignatureError:
raise exceptions.TokenExpiredError( raise exceptions.TokenExpiredError(
realm=self.realm) realm=self.realm)
except jwt.InvalidIssuerError: except jwt.exceptions.InvalidIssuerError:
raise exceptions.IssuerUnknownError( raise exceptions.IssuerUnknownError(
realm=self.realm) realm=self.realm)
except jwt.InvalidAudienceError: except jwt.exceptions.InvalidAudienceError:
raise exceptions.IncorrectAudienceError( raise exceptions.IncorrectAudienceError(
realm=self.realm) realm=self.realm)
except Exception as e: except Exception as e:
@ -154,7 +153,7 @@ class HS256Authenticator(JWTAuthenticator):
def _decode(self, rawToken): def _decode(self, rawToken):
return jwt.decode(rawToken, self.secret, issuer=self.issuer_id, return jwt.decode(rawToken, self.secret, issuer=self.issuer_id,
audience=self.audience, audience=self.audience,
algorithms=self.algorithm) algorithms=[self.algorithm])
class RS256Authenticator(JWTAuthenticator): class RS256Authenticator(JWTAuthenticator):
@ -172,7 +171,7 @@ class RS256Authenticator(JWTAuthenticator):
def _decode(self, rawToken): def _decode(self, rawToken):
return jwt.decode(rawToken, self.public_key, issuer=self.issuer_id, return jwt.decode(rawToken, self.public_key, issuer=self.issuer_id,
audience=self.audience, audience=self.audience,
algorithms=self.algorithm) algorithms=[self.algorithm])
class OpenIDConnectAuthenticator(JWTAuthenticator): class OpenIDConnectAuthenticator(JWTAuthenticator):
@ -203,9 +202,9 @@ class OpenIDConnectAuthenticator(JWTAuthenticator):
raise exceptions.JWKSException( raise exceptions.JWKSException(
realm=self.realm, realm=self.realm,
msg=msg) msg=msg)
# TODO keys can probably be cached jwks_client = jwt.PyJWKClient(keys_url)
try: try:
certs = requests.get(keys_url).json() signing_key = jwks_client.get_signing_key(kid=key_id)
except Exception as e: except Exception as e:
msg = 'Could not fetch Identity Provider keys at %s: %s' msg = 'Could not fetch Identity Provider keys at %s: %s'
logger.error(msg % (keys_url, e)) logger.error(msg % (keys_url, e))
@ -213,20 +212,9 @@ class OpenIDConnectAuthenticator(JWTAuthenticator):
realm=self.realm, realm=self.realm,
msg='There was an error while fetching ' msg='There was an error while fetching '
'keys for Identity Provider, check logs for details') 'keys for Identity Provider, check logs for details')
for key_dict in certs['keys']: algorithm = signing_key._jwk_data.get("alg", None) or self.algorithm
if key_dict.get('kid') == key_id: key = signing_key.key
# TODO: theoretically two other types of keys are return key, algorithm
# supported by the JWKS standard. We should raise an error
# in the unlikely case 'kty' is not RSA.
# (see https://tools.ietf.org/html/rfc7518#section-6.1)
key = jwt.algorithms.RSAAlgorithm.from_jwk(
json.dumps(key_dict))
algorithm = key_dict.get('alg', None) or self.algorithm
return key, algorithm
raise exceptions.JWKSException(
self.realm,
'Cannot verify token: public key %s '
'not listed by Identity Provider' % key_id)
def get_well_known_config(self): def get_well_known_config(self):
issuer = self.issuer_id issuer = self.issuer_id
@ -258,7 +246,7 @@ class OpenIDConnectAuthenticator(JWTAuthenticator):
key, algorithm = self.get_key(key_id) key, algorithm = self.get_key(key_id)
return jwt.decode(rawToken, key, issuer=self.issuer_id, return jwt.decode(rawToken, key, issuer=self.issuer_id,
audience=self.audience, audience=self.audience,
algorithms=algorithm) algorithms=[algorithm])
AUTHENTICATORS = { AUTHENTICATORS = {

View File

@ -947,7 +947,7 @@ class GithubClientManager:
data = {'iat': now, 'exp': expiry, 'iss': self.app_id} data = {'iat': now, 'exp': expiry, 'iss': self.app_id}
app_token = jwt.encode(data, app_token = jwt.encode(data,
self.app_key, self.app_key,
algorithm='RS256').decode('utf-8') algorithm='RS256')
headers = {'Accept': PREVIEW_JSON_ACCEPT, headers = {'Accept': PREVIEW_JSON_ACCEPT,
'Authorization': 'Bearer %s' % app_token} 'Authorization': 'Bearer %s' % app_token}

View File

@ -74,7 +74,7 @@ class AuthenticatorRegistry(object):
cpb.capabilities_registry.register_capabilities('auth', capabilities) cpb.capabilities_registry.register_capabilities('auth', capabilities)
def authenticate(self, rawToken): def authenticate(self, rawToken):
unverified = jwt.decode(rawToken, verify=False) unverified = jwt.decode(rawToken, options={'verify_signature': False})
for auth_name in self.authenticators: for auth_name in self.authenticators:
authenticator = self.authenticators[auth_name] authenticator = self.authenticators[auth_name]
if authenticator.issuer_id == unverified.get('iss', ''): if authenticator.issuer_id == unverified.get('iss', ''):