diff --git a/src/tokenserver/mod.rs b/src/tokenserver/mod.rs index eefc82a041..9857e4e0d3 100644 --- a/src/tokenserver/mod.rs +++ b/src/tokenserver/mod.rs @@ -44,15 +44,17 @@ impl ServerState { let oauth_verifier = Box::new(TestModeOAuthVerifier); #[cfg(not(feature = "tokenserver_test_mode"))] - let oauth_verifier = Box::new(OAuthVerifier { - fxa_oauth_server_url: settings.fxa_oauth_server_url.clone(), - }); + let oauth_verifier = Box::new( + OAuthVerifier::new(settings.fxa_oauth_server_url.as_deref()) + .expect("failed to create Tokenserver OAuth verifier"), + ); 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.as_deref()) + .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 0ff26c2e75..ef3f815bbd 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}; @@ -100,11 +100,32 @@ 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<&str>) -> 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.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 { @@ -112,15 +133,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..ff32a51f35 100644 --- a/src/tokenserver/verify.py +++ b/src/tokenserver/verify.py @@ -5,13 +5,15 @@ DEFAULT_OAUTH_SCOPE = 'https://identity.mozilla.com/apps/oldsync' -def verify_token(token, server_url=None): - client = Client(server_url=server_url) +class FxaOAuthClient: + def __init__(self, server_url=None): + self._client = Client(server_url=server_url) - try: - token_data = client.verify_token(token, DEFAULT_OAUTH_SCOPE) + def verify_token(self, token): + try: + token_data = self._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