VC/Zoom: Drop support for JWT authentication (#224)

This commit is contained in:
Duarte Galvão 2024-02-26 13:24:11 +01:00 committed by GitHub
parent 6734a2f739
commit bece9eec55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 30 additions and 53 deletions

View File

@ -15,6 +15,7 @@
- Adapt to Indico 3.3 changes
- Support Python 3.12
- Drop support for discontinued JWT authentication
### 3.2.5
@ -151,12 +152,6 @@ The scopes to select when creating the app are:
- `webinar:write:admin` (optional, only needed when using webinars)
### Zoom API key/secret (JWT, deprecated)
Zoom deprecated JWTs in June 2023, existing ones still work but no new ones can be created.
As soon as Zoom fully dropped them, JWT support will also be removed from this plugin.
## Intellectual Property
Developed by Giovanni Mariano @ **ENEA Frascati**, based on the Vidyo Plugin by the Indico Team at **CERN**. Further

View File

@ -7,7 +7,6 @@
import time
import jwt
import requests
from pytz import utc
from requests import Session
@ -172,11 +171,9 @@ class ZoomClient:
'webinar': WebinarComponent
}
def __init__(self, api_key, api_secret, account_id, client_id, client_secret, timeout=15):
def __init__(self, account_id, client_id, client_secret, timeout=15):
"""Create a new Zoom client.
:param api_key: the Zoom JWT API key
:param api_secret: the Zoom JWT API Secret
:param account_id: the Zoom Server OAuth Account ID
:param client_id: the Zoom Server OAuth Client ID
:param client_secret: the Zoom Server OAuth Client Secret
@ -184,8 +181,6 @@ class ZoomClient:
"""
# Setup the config details
config = {
'api_key': api_key,
'api_secret': api_secret,
'account_id': account_id,
'client_id': client_id,
'client_secret': client_secret,
@ -217,8 +212,6 @@ class ZoomIndicoClient:
def __init__(self):
from indico_vc_zoom.plugin import ZoomPlugin
self.client = ZoomClient(
ZoomPlugin.settings.get('api_key'),
ZoomPlugin.settings.get('api_secret'),
ZoomPlugin.settings.get('account_id'),
ZoomPlugin.settings.get('client_id'),
ZoomPlugin.settings.get('client_secret'),
@ -262,36 +255,31 @@ def get_zoom_token(config, *, force=False):
client_id = config['client_id']
client_secret = config['client_secret']
if account_id and client_id and client_secret:
ZoomPlugin.logger.debug(f'Using Server-to-Server-OAuth ({force=})')
hash_key = '-'.join((account_id, client_id, client_secret))
cache_key = f'token-{crc32(hash_key)}'
if not force and (token_data := token_cache.get(cache_key)):
expires_in = int(token_data['expires_at'] - time.time())
ZoomPlugin.logger.debug('Using token from cache (%s, %ds remaining)', cache_key, expires_in)
return token_data['access_token'], token_data['expires_at']
try:
resp = requests.post(
'https://zoom.us/oauth/token',
params={'grant_type': 'account_credentials', 'account_id': account_id},
auth=(client_id, client_secret)
)
resp.raise_for_status()
except HTTPError as exc:
ZoomPlugin.logger.error('Could not get zoom token: %s', exc.response.text if exc.response else exc)
raise Exception('Could not get zoom token; please contact an admin if this problem persists.')
token_data = resp.json()
assert 'access_token' in token_data
ZoomPlugin.logger.debug('Got new token from Zoom (expires_in=%s, scope=%s)', token_data['expires_in'],
token_data['scope'])
expires_at = int(time.time() + token_data['expires_in'])
token_data.setdefault('expires_at', expires_at) # zoom doesn't include this. wtf.
token_cache.set(cache_key, token_data, token_data['expires_in'])
return token_data['access_token'], token_data['expires_at']
elif config['api_key'] and config['api_secret']:
ZoomPlugin.logger.warning('Using JWT (deprecated)')
header = {'alg': 'HS256', 'typ': 'JWT'}
payload = {'iss': config['api_key'], 'exp': int(time.time() + 3600)}
return jwt.encode(payload, config['api_secret'], algorithm='HS256', headers=header), None
else:
if not (account_id and client_id and client_secret):
raise Exception('Zoom authentication not configured')
ZoomPlugin.logger.debug(f'Using Server-to-Server-OAuth ({force=})')
hash_key = '-'.join((account_id, client_id, client_secret))
cache_key = f'token-{crc32(hash_key)}'
if not force and (token_data := token_cache.get(cache_key)):
expires_in = int(token_data['expires_at'] - time.time())
ZoomPlugin.logger.debug('Using token from cache (%s, %ds remaining)', cache_key, expires_in)
return token_data['access_token'], token_data['expires_at']
try:
resp = requests.post(
'https://zoom.us/oauth/token',
params={'grant_type': 'account_credentials', 'account_id': account_id},
auth=(client_id, client_secret)
)
resp.raise_for_status()
except HTTPError as exc:
ZoomPlugin.logger.error('Could not get zoom token: %s', exc.response.text if exc.response else exc)
raise Exception('Could not get zoom token; please contact an admin if this problem persists.')
token_data = resp.json()
assert 'access_token' in token_data
ZoomPlugin.logger.debug('Got new token from Zoom (expires_in=%s, scope=%s)', token_data['expires_in'],
token_data['scope'])
expires_at = int(time.time() + token_data['expires_in'])
token_data.setdefault('expires_at', expires_at) # zoom doesn't include this. wtf.
token_cache.set(cache_key, token_data, token_data['expires_in'])
return token_data['access_token'], token_data['expires_at']

View File

@ -42,8 +42,7 @@ from indico_vc_zoom.util import (UserLookupMode, ZoomMeetingType, fetch_zoom_mee
class PluginSettingsForm(VCPluginSettingsFormBase):
_fieldsets = [
(_('API Credentials (Server-to-Server OAuth)'), ['account_id', 'client_id', 'client_secret', 'webhook_token']),
(_('API Credentials (Legacy JWT, deprecated)'), ['api_key', 'api_secret']),
(_('API Credentials'), ['account_id', 'client_id', 'client_secret', 'webhook_token']),
(_('Zoom Account'), ['user_lookup_mode', 'email_domains', 'authenticators', 'enterprise_domain',
'allow_webinars', 'phone_link']),
(_('Room Settings'), ['mute_audio', 'mute_host_video', 'mute_participant_video', 'join_before_host',
@ -52,8 +51,6 @@ class PluginSettingsForm(VCPluginSettingsFormBase):
(_('Access'), ['managers', 'acl'])
]
api_key = StringField(_('API Key'), [])
api_secret = IndicoPasswordField(_('API Secret'), [], toggle=True)
account_id = StringField(_('Account ID'), [])
client_id = StringField(_('Client ID'), [])
client_secret = IndicoPasswordField(_('Client Secret'), [], toggle=True)
@ -137,8 +134,6 @@ class ZoomPlugin(VCPluginMixin, IndicoPlugin):
vc_room_attach_form = VCRoomAttachForm
friendly_name = 'Zoom'
default_settings = VCPluginMixin.default_settings | {
'api_key': '',
'api_secret': '',
'account_id': '',
'client_id': '',
'client_secret': '',

View File

@ -24,7 +24,6 @@ include_package_data = true
python_requires = >=3.9.0, <3.13
install_requires =
indico>=3.3.dev0
PyJWT>=2.0.0,<3
[options.entry_points]
indico.plugins =