| |
@@ -0,0 +1,557 @@
|
| |
+ From 38c4f963644d40007851b79fdbb5bb652edc1fc9 Mon Sep 17 00:00:00 2001
|
| |
+ From: Matthieu Huin <mhuin@redhat.com>
|
| |
+ Date: Thu, 17 Jun 2021 12:32:06 +0200
|
| |
+ Subject: [PATCH 1/1] Revert to pyJWT 1.7.1
|
| |
+
|
| |
+ Fedora 34 packages pyJWT 1.7.1 - This fixes packaging problems.
|
| |
+
|
| |
+ Change-Id: I8a3e260b7f1268fca59dd14d296591b87cba06d0
|
| |
+ ---
|
| |
+ requirements.txt | 2 +-
|
| |
+ tests/unit/test_auth.py | 40 +++++++-------------
|
| |
+ tests/unit/test_client.py | 4 +-
|
| |
+ tests/unit/test_web.py | 52 +++++++++++++-------------
|
| |
+ tests/zuul_client/test_zuulclient.py | 10 ++---
|
| |
+ zuul/cmd/client.py | 2 +-
|
| |
+ zuul/driver/auth/jwt.py | 38 ++++++++++++-------
|
| |
+ zuul/driver/github/githubconnection.py | 2 +-
|
| |
+ zuul/lib/auth.py | 2 +-
|
| |
+ 9 files changed, 76 insertions(+), 76 deletions(-)
|
| |
+
|
| |
+ diff --git a/requirements.txt b/requirements.txt
|
| |
+ index 3ca11a6a..9fc76296 100644
|
| |
+ --- a/requirements.txt
|
| |
+ +++ b/requirements.txt
|
| |
+ @@ -23,7 +23,7 @@ alembic
|
| |
+ cryptography>=1.6
|
| |
+ cachecontrol
|
| |
+ cachetools
|
| |
+ -pyjwt>=2.0.0,<3.0
|
| |
+ +pyjwt<2.0.0
|
| |
+ iso8601
|
| |
+ psutil
|
| |
+ fb-re2>=1.0.6
|
| |
+ diff --git a/tests/unit/test_auth.py b/tests/unit/test_auth.py
|
| |
+ index 74fdf180..768db8d7 100644
|
| |
+ --- a/tests/unit/test_auth.py
|
| |
+ +++ b/tests/unit/test_auth.py
|
| |
+ @@ -17,7 +17,6 @@ import json
|
| |
+ from unittest import mock
|
| |
+ import os.path
|
| |
+ import jwt
|
| |
+ -from io import StringIO
|
| |
+ import time
|
| |
+
|
| |
+ from zuul.driver import auth
|
| |
+ @@ -32,10 +31,10 @@ with open(os.path.join(FIXTURE_DIR,
|
| |
+ algo = jwt.algorithms.RSAAlgorithm(jwt.algorithms.RSAAlgorithm.SHA256)
|
| |
+ with open(os.path.join(FIXTURE_DIR,
|
| |
+ 'auth/oidc-key'), 'r') as k:
|
| |
+ - OIDC_PRIVATE_KEY = algo.prepare_key(k.read())
|
| |
+ + OIDC_PRIVATE_KEY = algo.prepare_key(k.read().encode('utf-8'))
|
| |
+ with open(os.path.join(FIXTURE_DIR,
|
| |
+ 'auth/oidc-key.pub'), 'r') as k:
|
| |
+ - pub_key = algo.prepare_key(k.read())
|
| |
+ + pub_key = algo.prepare_key(k.read().encode('utf-8'))
|
| |
+ pub_jwk = algo.to_jwk(pub_key)
|
| |
+ key = {
|
| |
+ "kid": "OwO",
|
| |
+ @@ -53,31 +52,23 @@ with open(os.path.join(FIXTURE_DIR,
|
| |
+ }
|
| |
+
|
| |
+
|
| |
+ -class FakeResponse:
|
| |
+ - def __init__(self, json_dict):
|
| |
+ - self._json = json_dict
|
| |
+ -
|
| |
+ - def json(self):
|
| |
+ - 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)
|
| |
+ + 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)
|
| |
+
|
| |
+
|
| |
+ -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 FakeResponse:
|
| |
+ + def __init__(self, json_dict):
|
| |
+ + self._json = json_dict
|
| |
+ +
|
| |
+ + def json(self):
|
| |
+ + return self._json
|
| |
+
|
| |
+
|
| |
+ class TestOpenIDConnectAuthenticator(BaseTestCase):
|
| |
+ @@ -101,9 +92,6 @@ class TestOpenIDConnectAuthenticator(BaseTestCase):
|
| |
+ algorithm='RS256',
|
| |
+ headers={'kid': 'OwO'})
|
| |
+ with mock.patch('requests.get', side_effect=mock_get):
|
| |
+ - # patching call in PyJWKClient's fetch_data
|
| |
+ - with mock.patch('urllib.request.urlopen',
|
| |
+ - side_effect=mock_urlopen):
|
| |
+ - decoded = OIDCAuth.decodeToken(token)
|
| |
+ - for claim in payload.keys():
|
| |
+ - self.assertEqual(payload[claim], decoded[claim])
|
| |
+ + decoded = OIDCAuth.decodeToken(token)
|
| |
+ + for claim in payload.keys():
|
| |
+ + self.assertEqual(payload[claim], decoded[claim])
|
| |
+ diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
|
| |
+ index 461a8b4a..9b3edb44 100644
|
| |
+ --- a/tests/unit/test_client.py
|
| |
+ +++ b/tests/unit/test_client.py
|
| |
+ @@ -146,9 +146,9 @@ class TestWebTokenClient(BaseClientTestCase):
|
| |
+ key=self.config.get(
|
| |
+ 'auth zuul_operator',
|
| |
+ 'secret'),
|
| |
+ - algorithms=[self.config.get(
|
| |
+ + algorithms=self.config.get(
|
| |
+ 'auth zuul_operator',
|
| |
+ - 'driver')],
|
| |
+ + 'driver'),
|
| |
+ audience=self.config.get(
|
| |
+ 'auth zuul_operator',
|
| |
+ 'client_id'),)
|
| |
+ diff --git a/tests/unit/test_web.py b/tests/unit/test_web.py
|
| |
+ index bfbc3302..3a7ac636 100644
|
| |
+ --- a/tests/unit/test_web.py
|
| |
+ +++ b/tests/unit/test_web.py
|
| |
+ @@ -1466,7 +1466,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='OnlyZuulNoDana',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ resp = self.post_url(
|
| |
+ "api/tenant/tenant-one/project/org/project/autohold",
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -1501,7 +1501,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() - 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ resp = self.post_url(
|
| |
+ "api/tenant/tenant-one/project/org/project/autohold",
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -1536,7 +1536,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ resp = self.post_url(
|
| |
+ "api/tenant/tenant-one/project/org/project/autohold",
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -1576,7 +1576,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ 'ref': None,
|
| |
+ 'node_hold_expiration': None}
|
| |
+ good_token = jwt.encode(good_authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ req = self.post_url(
|
| |
+ 'api/tenant/tenant-one/project/org/project/autohold',
|
| |
+ headers={'Authorization': 'Bearer %s' % good_token},
|
| |
+ @@ -1610,7 +1610,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ req = self.post_url(
|
| |
+ 'api/tenant/tenant-one/project/org/project/autohold',
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -1636,7 +1636,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+
|
| |
+ def _init_autohold_delete(self, authz):
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+
|
| |
+ client = zuul.rpcclient.RPCClient('127.0.0.1',
|
| |
+ self.gearman_server.port)
|
| |
+ @@ -1674,7 +1674,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ bad_token = jwt.encode(bad_authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ resp = self.delete_url(
|
| |
+ "api/tenant/tenant-one/autohold/%s" % request_id,
|
| |
+ headers={'Authorization': 'Bearer %s' % bad_token})
|
| |
+ @@ -1718,7 +1718,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ path = "api/tenant/%(tenant)s/project/%(project)s/enqueue"
|
| |
+ enqueue_args = {'tenant': 'tenant-one',
|
| |
+ 'project': 'org/project', }
|
| |
+ @@ -1770,7 +1770,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ req = self.post_url(path % enqueue_args,
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ json=ref)
|
| |
+ @@ -1811,7 +1811,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ path = "api/tenant/%(tenant)s/project/%(project)s/dequeue"
|
| |
+ dequeue_args = {'tenant': 'tenant-one',
|
| |
+ 'project': 'org/project', }
|
| |
+ @@ -1933,7 +1933,7 @@ class TestTenantScopedWebApi(BaseTestWeb):
|
| |
+ 'exp': time.time() + 3600,
|
| |
+ 'iat': time.time()}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ req = self.post_url(
|
| |
+ 'api/tenant/tenant-one/promote',
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -2007,7 +2007,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ req = self.post_url(
|
| |
+ 'api/tenant/tenant-one/project/org/project/autohold',
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -2030,7 +2030,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
|
| |
+ 'project': project, }
|
| |
+
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ req = self.post_url(path % enqueue_args,
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ json=change)
|
| |
+ @@ -2074,7 +2074,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
|
| |
+ 'groups': ['ghostbusters', 'secretary'],
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ path = "api/tenant/%(tenant)s/project/%(project)s/enqueue"
|
| |
+ enqueue_args = {'tenant': 'tenant-one',
|
| |
+ 'project': 'org/project2', }
|
| |
+ @@ -2100,7 +2100,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
|
| |
+ 'car': 'ecto-1'},
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ path = "api/tenant/%(tenant)s/project/%(project)s/enqueue"
|
| |
+ enqueue_args = {'tenant': 'tenant-one',
|
| |
+ 'project': 'org/project', }
|
| |
+ @@ -2122,7 +2122,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
|
| |
+ 'zuul': {'admin': admin_tenants},
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ # TODO(mhu) deprecated, remove after next release
|
| |
+ req = self.get_url('/api/user/authorizations',
|
| |
+ headers={'Authorization': 'Bearer %s' % token})
|
| |
+ @@ -2164,7 +2164,7 @@ class TestTenantScopedWebApiWithAuthRules(BaseTestWeb):
|
| |
+ authz = test_user['authz']
|
| |
+ authz['exp'] = time.time() + 3600
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ # TODO(mhu) deprecated, remove after next release
|
| |
+ req = self.get_url('/api/user/authorizations',
|
| |
+ headers={'Authorization': 'Bearer %s' % token})
|
| |
+ @@ -2231,7 +2231,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ resp = self.post_url(
|
| |
+ "api/tenant/tenant-one/project/org/project/autohold",
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -2267,7 +2267,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
|
| |
+ 'exp': time.time() + 7200,
|
| |
+ 'iat': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ resp = self.post_url(
|
| |
+ "api/tenant/tenant-one/project/org/project/autohold",
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -2303,7 +2303,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
|
| |
+ 'exp': time.time() + 3600,
|
| |
+ 'iat': time.time()}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ time.sleep(10)
|
| |
+ resp = self.post_url(
|
| |
+ "api/tenant/tenant-one/project/org/project/autohold",
|
| |
+ @@ -2347,7 +2347,7 @@ class TestTenantScopedWebApiTokenWithExpiry(BaseTestWeb):
|
| |
+ 'exp': time.time() + 3600,
|
| |
+ 'iat': time.time()}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ req = self.post_url(
|
| |
+ 'api/tenant/tenant-one/project/org/project/autohold',
|
| |
+ headers={'Authorization': 'Bearer %s' % token},
|
| |
+ @@ -2451,7 +2451,7 @@ class TestCLIViaWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ [os.path.join(sys.prefix, 'bin/zuul'),
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token,
|
| |
+ @@ -2490,7 +2490,7 @@ class TestCLIViaWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ [os.path.join(sys.prefix, 'bin/zuul'),
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token,
|
| |
+ @@ -2519,7 +2519,7 @@ class TestCLIViaWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ [os.path.join(sys.prefix, 'bin/zuul'),
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token,
|
| |
+ @@ -2555,7 +2555,7 @@ class TestCLIViaWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ [os.path.join(sys.prefix, 'bin/zuul'),
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token,
|
| |
+ @@ -2606,7 +2606,7 @@ class TestCLIViaWebApi(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ [os.path.join(sys.prefix, 'bin/zuul'),
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token,
|
| |
+ diff --git a/tests/zuul_client/test_zuulclient.py b/tests/zuul_client/test_zuulclient.py
|
| |
+ index c17b2ab9..705119c6 100644
|
| |
+ --- a/tests/zuul_client/test_zuulclient.py
|
| |
+ +++ b/tests/zuul_client/test_zuulclient.py
|
| |
+ @@ -190,7 +190,7 @@ class TestZuulClientAdmin(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ ['zuul-client',
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token, '-v',
|
| |
+ @@ -230,7 +230,7 @@ class TestZuulClientAdmin(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ ['zuul-client',
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token, '-v',
|
| |
+ @@ -266,7 +266,7 @@ class TestZuulClientAdmin(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ ['zuul-client',
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token, '-v',
|
| |
+ @@ -308,7 +308,7 @@ class TestZuulClientAdmin(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ ['zuul-client',
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token, '-v',
|
| |
+ @@ -359,7 +359,7 @@ class TestZuulClientAdmin(BaseTestWeb):
|
| |
+ },
|
| |
+ 'exp': time.time() + 3600}
|
| |
+ token = jwt.encode(authz, key='NoDanaOnlyZuul',
|
| |
+ - algorithm='HS256')
|
| |
+ + algorithm='HS256').decode('utf-8')
|
| |
+ p = subprocess.Popen(
|
| |
+ ['zuul-client',
|
| |
+ '--zuul-url', self.base_url, '--auth-token', token, '-v',
|
| |
+ diff --git a/zuul/cmd/client.py b/zuul/cmd/client.py
|
| |
+ index d7154184..7e99c040 100644
|
| |
+ --- a/zuul/cmd/client.py
|
| |
+ +++ b/zuul/cmd/client.py
|
| |
+ @@ -572,7 +572,7 @@ class Client(zuul.cmd.ZuulApp):
|
| |
+ try:
|
| |
+ auth_token = jwt.encode(token,
|
| |
+ key=key,
|
| |
+ - algorithm=driver)
|
| |
+ + algorithm=driver).decode('utf-8')
|
| |
+ print("Bearer %s" % auth_token)
|
| |
+ err_code = 0
|
| |
+ except Exception as e:
|
| |
+ diff --git a/zuul/driver/auth/jwt.py b/zuul/driver/auth/jwt.py
|
| |
+ index 7fe23f2f..2cc79826 100644
|
| |
+ --- a/zuul/driver/auth/jwt.py
|
| |
+ +++ b/zuul/driver/auth/jwt.py
|
| |
+ @@ -16,6 +16,7 @@
|
| |
+ import logging
|
| |
+ import math
|
| |
+ import time
|
| |
+ +import json
|
| |
+ import jwt
|
| |
+ import requests
|
| |
+ from urllib.parse import urljoin
|
| |
+ @@ -70,19 +71,19 @@ class JWTAuthenticator(AuthenticatorInterface):
|
| |
+ """Verify the raw token and return the decoded dictionary of claims"""
|
| |
+ try:
|
| |
+ decoded = self._decode(rawToken)
|
| |
+ - except jwt.exceptions.InvalidSignatureError:
|
| |
+ + except jwt.InvalidSignatureError:
|
| |
+ raise exceptions.AuthTokenInvalidSignatureException(
|
| |
+ realm=self.realm)
|
| |
+ - except jwt.exceptions.DecodeError:
|
| |
+ + except jwt.DecodeError:
|
| |
+ raise exceptions.AuthTokenUndecodedException(
|
| |
+ realm=self.realm)
|
| |
+ - except jwt.exceptions.ExpiredSignatureError:
|
| |
+ + except jwt.ExpiredSignatureError:
|
| |
+ raise exceptions.TokenExpiredError(
|
| |
+ realm=self.realm)
|
| |
+ - except jwt.exceptions.InvalidIssuerError:
|
| |
+ + except jwt.InvalidIssuerError:
|
| |
+ raise exceptions.IssuerUnknownError(
|
| |
+ realm=self.realm)
|
| |
+ - except jwt.exceptions.InvalidAudienceError:
|
| |
+ + except jwt.InvalidAudienceError:
|
| |
+ raise exceptions.IncorrectAudienceError(
|
| |
+ realm=self.realm)
|
| |
+ except Exception as e:
|
| |
+ @@ -153,7 +154,7 @@ class HS256Authenticator(JWTAuthenticator):
|
| |
+ def _decode(self, rawToken):
|
| |
+ return jwt.decode(rawToken, self.secret, issuer=self.issuer_id,
|
| |
+ audience=self.audience,
|
| |
+ - algorithms=[self.algorithm])
|
| |
+ + algorithms=self.algorithm)
|
| |
+
|
| |
+
|
| |
+ class RS256Authenticator(JWTAuthenticator):
|
| |
+ @@ -171,7 +172,7 @@ class RS256Authenticator(JWTAuthenticator):
|
| |
+ def _decode(self, rawToken):
|
| |
+ return jwt.decode(rawToken, self.public_key, issuer=self.issuer_id,
|
| |
+ audience=self.audience,
|
| |
+ - algorithms=[self.algorithm])
|
| |
+ + algorithms=self.algorithm)
|
| |
+
|
| |
+
|
| |
+ class OpenIDConnectAuthenticator(JWTAuthenticator):
|
| |
+ @@ -202,9 +203,9 @@ class OpenIDConnectAuthenticator(JWTAuthenticator):
|
| |
+ raise exceptions.JWKSException(
|
| |
+ realm=self.realm,
|
| |
+ msg=msg)
|
| |
+ - jwks_client = jwt.PyJWKClient(keys_url)
|
| |
+ + # TODO keys can probably be cached
|
| |
+ try:
|
| |
+ - signing_key = jwks_client.get_signing_key(kid=key_id)
|
| |
+ + certs = requests.get(keys_url).json()
|
| |
+ except Exception as e:
|
| |
+ msg = 'Could not fetch Identity Provider keys at %s: %s'
|
| |
+ logger.error(msg % (keys_url, e))
|
| |
+ @@ -212,9 +213,20 @@ class OpenIDConnectAuthenticator(JWTAuthenticator):
|
| |
+ realm=self.realm,
|
| |
+ msg='There was an error while fetching '
|
| |
+ 'keys for Identity Provider, check logs for details')
|
| |
+ - algorithm = signing_key._jwk_data.get("alg", None) or self.algorithm
|
| |
+ - key = signing_key.key
|
| |
+ - return key, algorithm
|
| |
+ + for key_dict in certs['keys']:
|
| |
+ + if key_dict.get('kid') == key_id:
|
| |
+ + # TODO: theoretically two other types of keys are
|
| |
+ + # 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):
|
| |
+ issuer = self.issuer_id
|
| |
+ @@ -246,7 +258,7 @@ class OpenIDConnectAuthenticator(JWTAuthenticator):
|
| |
+ key, algorithm = self.get_key(key_id)
|
| |
+ return jwt.decode(rawToken, key, issuer=self.issuer_id,
|
| |
+ audience=self.audience,
|
| |
+ - algorithms=[algorithm])
|
| |
+ + algorithms=algorithm)
|
| |
+
|
| |
+
|
| |
+ AUTHENTICATORS = {
|
| |
+ diff --git a/zuul/driver/github/githubconnection.py b/zuul/driver/github/githubconnection.py
|
| |
+ index 6089d4be..ed9a967e 100644
|
| |
+ --- a/zuul/driver/github/githubconnection.py
|
| |
+ +++ b/zuul/driver/github/githubconnection.py
|
| |
+ @@ -964,7 +964,7 @@ class GithubClientManager:
|
| |
+ data = {'iat': now, 'exp': expiry, 'iss': self.app_id}
|
| |
+ app_token = jwt.encode(data,
|
| |
+ self.app_key,
|
| |
+ - algorithm='RS256')
|
| |
+ + algorithm='RS256').decode('utf-8')
|
| |
+
|
| |
+ headers = {'Accept': PREVIEW_JSON_ACCEPT,
|
| |
+ 'Authorization': 'Bearer %s' % app_token}
|
| |
+ diff --git a/zuul/lib/auth.py b/zuul/lib/auth.py
|
| |
+ index a5866e90..effb4bc5 100644
|
| |
+ --- a/zuul/lib/auth.py
|
| |
+ +++ b/zuul/lib/auth.py
|
| |
+ @@ -74,7 +74,7 @@ class AuthenticatorRegistry(object):
|
| |
+ cpb.capabilities_registry.register_capabilities('auth', capabilities)
|
| |
+
|
| |
+ def authenticate(self, rawToken):
|
| |
+ - unverified = jwt.decode(rawToken, options={'verify_signature': False})
|
| |
+ + unverified = jwt.decode(rawToken, verify=False)
|
| |
+ for auth_name in self.authenticators:
|
| |
+ authenticator = self.authenticators[auth_name]
|
| |
+ if authenticator.issuer_id == unverified.get('iss', ''):
|
| |
+ --
|
| |
+ 2.31.1
|
| |
+
|
| |
Can it provides more version ?