Skip to content

Commit

Permalink
VC/Zoom: Drop support for JWT authentication (#224)
Browse files Browse the repository at this point in the history
  • Loading branch information
duartegalvao authored Feb 26, 2024
1 parent 6734a2f commit bece9ee
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 53 deletions.
7 changes: 1 addition & 6 deletions vc_zoom/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

- Adapt to Indico 3.3 changes
- Support Python 3.12
- Drop support for discontinued JWT authentication

### 3.2.5

Expand Down Expand Up @@ -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
Expand Down
68 changes: 28 additions & 40 deletions vc_zoom/indico_vc_zoom/api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import time

import jwt
import requests
from pytz import utc
from requests import Session
Expand Down Expand Up @@ -172,20 +171,16 @@ 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
:param timeout: the time out to use for API requests
"""
# 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,
Expand Down Expand Up @@ -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'),
Expand Down Expand Up @@ -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']
7 changes: 1 addition & 6 deletions vc_zoom/indico_vc_zoom/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@

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',
Expand All @@ -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)
Expand Down Expand Up @@ -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': '',
Expand Down
1 change: 0 additions & 1 deletion vc_zoom/setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down

0 comments on commit bece9ee

Please sign in to comment.