From a99050ca643f9bf0d9f719c81505143833286ffb Mon Sep 17 00:00:00 2001 From: Ethan Donowitz Date: Fri, 4 Feb 2022 00:12:05 +0000 Subject: [PATCH] refactor: cache FxA OAuth client Closes #1209 --- src/tokenserver/mod.rs | 7 ++++--- src/tokenserver/support.rs | 38 ++++++++++++++++++++++++++++---------- src/tokenserver/verify.py | 19 ++++++++++--------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/src/tokenserver/mod.rs b/src/tokenserver/mod.rs index eefc82a041..d8617a4803 100644 --- a/src/tokenserver/mod.rs +++ b/src/tokenserver/mod.rs @@ -50,9 +50,10 @@ impl ServerState { oauth_verifier } else { - Box::new(OAuthVerifier { - fxa_oauth_server_url: settings.fxa_oauth_server_url.clone(), - }) + Box::new( + OAuthVerifier::new(settings.fxa_oauth_server_url.clone()) + .expect("failed to create Tokenserver OAuth verifier"), + ) }; let use_test_transactions = false; diff --git a/src/tokenserver/support.rs b/src/tokenserver/support.rs index d98b73f967..ffc191b65b 100644 --- a/src/tokenserver/support.rs +++ b/src/tokenserver/support.rs @@ -1,5 +1,5 @@ use actix_web::Error; -use pyo3::prelude::{IntoPy, PyAny, PyErr, PyModule, PyObject, Python}; +use pyo3::prelude::{IntoPy, Py, PyAny, PyErr, PyModule, PyObject, Python}; use pyo3::types::{IntoPyDict, PyString}; use serde::{Deserialize, Serialize}; @@ -119,11 +119,34 @@ impl Clone for Box { #[derive(Clone)] /// An adapter to the PyFxA Python library. pub struct OAuthVerifier { - pub fxa_oauth_server_url: Option, + inner: Py, } impl OAuthVerifier { const FILENAME: &'static str = "verify.py"; + + pub fn new(fxa_oauth_server_url: Option) -> Result { + let inner: Py = Python::with_gil::<_, Result, PyErr>>(|py| { + let code = include_str!("verify.py"); + let module = PyModule::from_code(py, code, Self::FILENAME, Self::FILENAME)?; + let kwargs = fxa_oauth_server_url + .clone() + .map(|url| [("server_url", url)].into_py_dict(py)); + let object: Py = module + .getattr("FxaOAuthClient")? + .call((), kwargs) + .map_err(|e| { + e.print_and_set_sys_last_vars(py); + e + })? + .into(); + + Ok(object) + }) + .map_err(pyerr_to_actix_error)?; + + Ok(Self { inner }) + } } impl VerifyToken for OAuthVerifier { @@ -131,15 +154,10 @@ impl VerifyToken for OAuthVerifier { /// tokens. fn verify_token(&self, token: &str) -> Result { let maybe_token_data_string = Python::with_gil(|py| { - let code = include_str!("verify.py"); - let module = PyModule::from_code(py, code, Self::FILENAME, Self::FILENAME)?; - let kwargs = self - .fxa_oauth_server_url - .clone() - .map(|url| [("server_url", url)].into_py_dict(py)); - let result: &PyAny = module + let client = self.inner.as_ref(py); + let result: &PyAny = client .getattr("verify_token")? - .call((token,), kwargs) + .call((token,), None) .map_err(|e| { e.print_and_set_sys_last_vars(py); e diff --git a/src/tokenserver/verify.py b/src/tokenserver/verify.py index 5d8088dcc7..1f4b13b076 100644 --- a/src/tokenserver/verify.py +++ b/src/tokenserver/verify.py @@ -4,14 +4,15 @@ DEFAULT_OAUTH_SCOPE = 'https://identity.mozilla.com/apps/oldsync' +class FxaOAuthClient: + def __init__(self, server_url=None): + self._client = Client(server_url=server_url) -def verify_token(token, server_url=None): - client = Client(server_url=server_url) + def verify_token(self, token): + try: + token_data = self._client.verify_token(token, DEFAULT_OAUTH_SCOPE) - try: - token_data = client.verify_token(token, DEFAULT_OAUTH_SCOPE) - - # Serialize the data to make it easier to parse in Rust - return json.dumps(token_data) - except (ClientError, TrustError): - return None + # Serialize the data to make it easier to parse in Rust + return json.dumps(token_data) + except (ClientError, TrustError): + return None