mirror of
https://github.com/mozilla-services/syncstorage-rs.git
synced 2026-05-05 12:16:21 +02:00
feat: support multiple FxA JWKs to ease key rotation (#1339)
This commit is contained in:
parent
f76b5fc675
commit
eba3566225
@ -34,13 +34,13 @@ services:
|
||||
SYNC_TOKENSERVER__FXA_EMAIL_DOMAIN: api-accounts.stage.mozaws.net
|
||||
SYNC_TOKENSERVER__FXA_METRICS_HASH_SECRET: secret0
|
||||
SYNC_TOKENSERVER__RUN_MIGRATIONS: "true"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__KTY: "RSA"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__ALG: "RS256"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__KID: "20190730-15e473fd"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__FXA_CREATED_AT: "1564502400"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__USE: "sig"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__N: "15OpVGC7ws_SlU0gRbRh1Iwo8_gR8ElX2CDnbN5blKyXLg-ll0ogktoDXc-tDvTabRTxi7AXU0wWQ247odhHT47y5uz0GASYXdfPponynQ_xR9CpNn1eEL1gvDhQN9rfPIzfncl8FUi9V4WMd5f600QC81yDw9dX-Z8gdkru0aDaoEKF9-wU2TqrCNcQdiJCX9BISotjz_9cmGwKXFEekQNJWBeRQxH2bUmgwUK0HaqwW9WbYOs-zstNXXWFsgK9fbDQqQeGehXLZM4Cy5Mgl_iuSvnT3rLzPo2BmlxMLUvRqBx3_v8BTtwmNGA0v9O0FJS_mnDq0Iue0Dz8BssQCQ"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__E: "AQAB"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__KTY: "RSA"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__ALG: "RS256"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__KID: "20190730-15e473fd"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__FXA_CREATED_AT: "1564502400"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__USE: "sig"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__N: "15OpVGC7ws_SlU0gRbRh1Iwo8_gR8ElX2CDnbN5blKyXLg-ll0ogktoDXc-tDvTabRTxi7AXU0wWQ247odhHT47y5uz0GASYXdfPponynQ_xR9CpNn1eEL1gvDhQN9rfPIzfncl8FUi9V4WMd5f600QC81yDw9dX-Z8gdkru0aDaoEKF9-wU2TqrCNcQdiJCX9BISotjz_9cmGwKXFEekQNJWBeRQxH2bUmgwUK0HaqwW9WbYOs-zstNXXWFsgK9fbDQqQeGehXLZM4Cy5Mgl_iuSvnT3rLzPo2BmlxMLUvRqBx3_v8BTtwmNGA0v9O0FJS_mnDq0Iue0Dz8BssQCQ"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__E: "AQAB"
|
||||
TOKENSERVER_HOST: http://localhost:8000
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
|
||||
@ -35,13 +35,13 @@ services:
|
||||
SYNC_TOKENSERVER__FXA_EMAIL_DOMAIN: api-accounts.stage.mozaws.net
|
||||
SYNC_TOKENSERVER__FXA_METRICS_HASH_SECRET: secret0
|
||||
SYNC_TOKENSERVER__RUN_MIGRATIONS: "true"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__KTY: "RSA"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__ALG: "RS256"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__KID: "20190730-15e473fd"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__FXA_CREATED_AT: "1564502400"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__USE: "sig"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__N: "15OpVGC7ws_SlU0gRbRh1Iwo8_gR8ElX2CDnbN5blKyXLg-ll0ogktoDXc-tDvTabRTxi7AXU0wWQ247odhHT47y5uz0GASYXdfPponynQ_xR9CpNn1eEL1gvDhQN9rfPIzfncl8FUi9V4WMd5f600QC81yDw9dX-Z8gdkru0aDaoEKF9-wU2TqrCNcQdiJCX9BISotjz_9cmGwKXFEekQNJWBeRQxH2bUmgwUK0HaqwW9WbYOs-zstNXXWFsgK9fbDQqQeGehXLZM4Cy5Mgl_iuSvnT3rLzPo2BmlxMLUvRqBx3_v8BTtwmNGA0v9O0FJS_mnDq0Iue0Dz8BssQCQ"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_JWK__E: "AQAB"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__KTY: "RSA"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__ALG: "RS256"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__KID: "20190730-15e473fd"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__FXA_CREATED_AT: "1564502400"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__USE: "sig"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__N: "15OpVGC7ws_SlU0gRbRh1Iwo8_gR8ElX2CDnbN5blKyXLg-ll0ogktoDXc-tDvTabRTxi7AXU0wWQ247odhHT47y5uz0GASYXdfPponynQ_xR9CpNn1eEL1gvDhQN9rfPIzfncl8FUi9V4WMd5f600QC81yDw9dX-Z8gdkru0aDaoEKF9-wU2TqrCNcQdiJCX9BISotjz_9cmGwKXFEekQNJWBeRQxH2bUmgwUK0HaqwW9WbYOs-zstNXXWFsgK9fbDQqQeGehXLZM4Cy5Mgl_iuSvnT3rLzPo2BmlxMLUvRqBx3_v8BTtwmNGA0v9O0FJS_mnDq0Iue0Dz8BssQCQ"
|
||||
SYNC_TOKENSERVER__FXA_OAUTH_PRIMARY_JWK__E: "AQAB"
|
||||
TOKENSERVER_HOST: http://localhost:8000
|
||||
entrypoint: >
|
||||
/bin/sh -c "
|
||||
|
||||
@ -232,6 +232,17 @@ impl Settings {
|
||||
"https://oauth.stage.mozaws.net",
|
||||
)?;
|
||||
s.set_default("tokenserver.fxa_oauth_request_timeout", 10)?;
|
||||
|
||||
// The type parameter for None::<bool> below would more appropriately be `Jwk`, but due
|
||||
// to constraints imposed by version 0.11 of the config crate, it is not possible to
|
||||
// implement `ValueKind: From<Jwk>`. The next best thing would be to use `ValueKind`,
|
||||
// but `ValueKind` is private in this version of config. We use `bool` as a placeholder,
|
||||
// since `ValueKind: From<bool>` is implemented, and None::<T> for all T is simply
|
||||
// converted to ValueKind::Nil (see below link).
|
||||
// https://github.com/mehcode/config-rs/blob/0.11.0/src/value.rs#L35
|
||||
s.set_default("tokenserver.fxa_oauth_primary_jwk", None::<bool>)?;
|
||||
s.set_default("tokenserver.fxa_oauth_secondary_jwk", None::<bool>)?;
|
||||
|
||||
s.set_default("tokenserver.node_type", "spanner")?;
|
||||
s.set_default("tokenserver.statsd_label", "syncstorage.tokenserver")?;
|
||||
s.set_default("tokenserver.run_migrations", cfg!(test))?;
|
||||
|
||||
@ -3,7 +3,6 @@ use futures::TryFutureExt;
|
||||
use pyo3::{
|
||||
prelude::{Py, PyAny, PyErr, PyModule, Python},
|
||||
types::{IntoPyDict, PyString},
|
||||
IntoPy,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json;
|
||||
@ -11,7 +10,7 @@ use tokenserver_common::error::TokenserverError;
|
||||
use tokio::{task, time};
|
||||
|
||||
use super::VerifyToken;
|
||||
use crate::tokenserver::settings::Settings;
|
||||
use crate::tokenserver::settings::{Jwk, Settings};
|
||||
|
||||
use core::time::Duration;
|
||||
use std::convert::TryFrom;
|
||||
@ -47,24 +46,31 @@ impl TryFrom<&Settings> for Verifier {
|
||||
let module = PyModule::from_code(py, code, Self::FILENAME, Self::FILENAME)?;
|
||||
let kwargs = {
|
||||
let dict = [("server_url", &settings.fxa_oauth_server_url)].into_py_dict(py);
|
||||
let jwks = settings
|
||||
.fxa_oauth_jwk
|
||||
.as_ref()
|
||||
.map(|jwk| {
|
||||
let dict = [
|
||||
("kty", &jwk.kty),
|
||||
("alg", &jwk.alg),
|
||||
("kid", &jwk.kid),
|
||||
("use", &jwk.use_of_key),
|
||||
("n", &jwk.n),
|
||||
("e", &jwk.e),
|
||||
]
|
||||
.into_py_dict(py);
|
||||
dict.set_item("fxa-createdAt", jwk.fxa_created_at).unwrap();
|
||||
let parse_jwk = |jwk: &Jwk| {
|
||||
let dict = [
|
||||
("kty", &jwk.kty),
|
||||
("alg", &jwk.alg),
|
||||
("kid", &jwk.kid),
|
||||
("use", &jwk.use_of_key),
|
||||
("n", &jwk.n),
|
||||
("e", &jwk.e),
|
||||
]
|
||||
.into_py_dict(py);
|
||||
dict.set_item("fxa-createdAt", jwk.fxa_created_at).unwrap();
|
||||
|
||||
[dict]
|
||||
})
|
||||
.into_py(py);
|
||||
dict
|
||||
};
|
||||
|
||||
let jwks = match (
|
||||
&settings.fxa_oauth_primary_jwk,
|
||||
&settings.fxa_oauth_secondary_jwk,
|
||||
) {
|
||||
(Some(primary_jwk), Some(secondary_jwk)) => {
|
||||
Some(vec![parse_jwk(primary_jwk), parse_jwk(secondary_jwk)])
|
||||
}
|
||||
(Some(jwk), None) | (None, Some(jwk)) => Some(vec![parse_jwk(jwk)]),
|
||||
(None, None) => None,
|
||||
};
|
||||
dict.set_item("jwks", jwks).unwrap();
|
||||
dict
|
||||
};
|
||||
@ -84,7 +90,8 @@ impl TryFrom<&Settings> for Verifier {
|
||||
Ok(Self {
|
||||
inner,
|
||||
timeout: settings.fxa_oauth_request_timeout,
|
||||
jwk_is_cached: settings.fxa_oauth_jwk.is_some(),
|
||||
jwk_is_cached: settings.fxa_oauth_primary_jwk.is_some()
|
||||
|| settings.fxa_oauth_secondary_jwk.is_some(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,10 @@ pub struct Settings {
|
||||
/// The JWK to be used to verify OAuth tokens. Passing a JWK to the PyFxA Python library
|
||||
/// prevents it from making an external API call to FxA to get the JWK, yielding substantial
|
||||
/// performance benefits.
|
||||
pub fxa_oauth_jwk: Option<Jwk>,
|
||||
pub fxa_oauth_primary_jwk: Option<Jwk>,
|
||||
/// A secondary JWK to be used to verify OAuth tokens. This is intended to be used to enable
|
||||
/// seamless key rotations on FxA.
|
||||
pub fxa_oauth_secondary_jwk: Option<Jwk>,
|
||||
/// The issuer expected in the BrowserID verification response.
|
||||
pub fxa_browserid_issuer: String,
|
||||
/// The audience to be sent to the FxA BrowserID verification server.
|
||||
@ -80,7 +83,8 @@ impl Default for Settings {
|
||||
fxa_metrics_hash_secret: "secret".to_owned(),
|
||||
fxa_oauth_server_url: "https://oauth.stage.mozaws.net".to_owned(),
|
||||
fxa_oauth_request_timeout: 10,
|
||||
fxa_oauth_jwk: None,
|
||||
fxa_oauth_primary_jwk: None,
|
||||
fxa_oauth_secondary_jwk: None,
|
||||
fxa_browserid_audience: "https://token.stage.mozaws.net".to_owned(),
|
||||
fxa_browserid_issuer: "api-accounts.stage.mozaws.net".to_owned(),
|
||||
fxa_browserid_server_url: "https://verifier.stage.mozaws.net/v2".to_owned(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user