Repository: swimos/swim-rust (language: rust)

Issue:
Remove authentication crate



Discussion / hints:

Fix patch:
diff --git a/swim_server/Cargo.toml b/swim_server/Cargo.toml
index 056892741..ffe0dfa8b 100644
--- a/swim_server/Cargo.toml
+++ b/swim_server/Cargo.toml
@@ -40,7 +40,6 @@ trybuild = "1.0.48"
 tokio-tungstenite = { version = "0.13.0", git = "https://github.com/swimos/tokio-tungstenite/", branch = "deflate-v13", features = ["tls", "deflate"] }
 tokio-native-tls = "0.3"
 trust-dns-resolver = { version = "0.20", optional = true, features = ["tokio-runtime"] }
-auth = { path = "auth" }
 regex = "1"
 lazy_static = "1.4.0"
 percent-encoding = "2.1.0"
diff --git a/swim_server/auth/Cargo.toml b/swim_server/auth/Cargo.toml
deleted file mode 100644
index 68b4facc7..000000000
--- a/swim_server/auth/Cargo.toml
+++ /dev/null
@@ -1,27 +0,0 @@
-[package]
-name = "auth"
-version = "0.1.0"
-authors = ["Swim.AI developers info@swim.ai"]
-edition = "2018"
-
-[dependencies]
-swim_common = { path = "../../swim_common" }
-swim_future = { path = "../../swim_utilities/swim_future" }
-swim_utilities = { path = "../../swim_utilities" }
-swim_runtime = { path = "../../swim_runtime" }
-
-tokio = "1.1.1"
-jwt = "0.12.0"
-serde = "1.0.117"
-serde_json = "1.0.59"
-futures = "0.3.4"
-futures-util = "0.3.4"
-im = "15.0.0"
-reqwest = "0.11.0"
-http = "0.2.3"
-url = { version = "2.1.1", features = ["serde"] }
-biscuit = "0.5.0"
-chrono = "0.4"
-
-[dev-dependencies]
-tokio = { version = "1.1.1", features = ["rt-multi-thread", "macros", "test-util"] }
diff --git a/swim_server/auth/src/googleid/mod.rs b/swim_server/auth/src/googleid/mod.rs
deleted file mode 100644
index c6d9a737d..000000000
--- a/swim_server/auth/src/googleid/mod.rs
+++ /dev/null
@@ -1,583 +0,0 @@
-// Copyright 2015-2021 SWIM.AI inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use std::num::NonZeroI64;
-
-use biscuit::jws::Compact;
-use biscuit::{ClaimsSet, CompactJson, Empty, SingleOrMultiple};
-use chrono::{Duration, Utc};
-use futures::FutureExt;
-use futures_util::future::BoxFuture;
-use im::HashSet;
-use serde::{Deserialize, Serialize};
-use url::Url;
-
-use swim_common::form::Form;
-use swim_common::model::{Value, ValueKind};
-
-use crate::googleid::store::{
-    GoogleKeyStore, GoogleKeyStoreError, DEFAULT_CERT_SKEW, GOOGLE_JWK_CERTS_URL,
-};
-use crate::policy::{IssuedPolicy, PolicyDirective};
-use crate::token::Token;
-use crate::{AuthenticationError, Authenticator};
-use biscuit::jwa::SignatureAlgorithm;
-use std::borrow::Borrow;
-use std::convert::TryFrom;
-use swim_common::form::structural::read::error::ExpectedEvent;
-use swim_common::form::structural::read::event::{NumericValue, ReadEvent};
-use swim_common::form::structural::read::recognizer::primitive::StringRecognizer;
-use swim_common::form::structural::read::recognizer::{
-    Recognizer, RecognizerReadable, SimpleAttrBody, VecRecognizer,
-};
-use swim_common::form::structural::read::ReadError;
-use swim_common::form::structural::write::{
-    BodyWriter, HeaderWriter, PrimitiveWriter, RecordBodyKind, StructuralWritable, StructuralWriter,
-};
-use swim_common::model::text::Text;
-
-mod store;
-#[cfg(test)]
-mod tests;
-
-const GOOGLE_AUTH_TAG: &str = "googleId";
-const GOOGLE_ISS1: &str = "accounts.google.com";
-const GOOGLE_ISS2: &str = "https://accounts.google.com";
-const DEFAULT_TOKEN_SKEW: i64 = 5;
-
-/// An authenticator for validating Google ID tokens.
-/// See <https://developers.google.com/identity/sign-in/web/> for more information
-#[derive(Debug, PartialEq)]
-pub struct GoogleIdAuthenticator {
-    /// Number of seconds beyond the token's expiry time that are permitted.
-    token_skew: i64,
-    key_store: GoogleKeyStore,
-    emails: HashSet<String>,
-    audiences: HashSet<String>,
-}
-
-impl StructuralWritable for GoogleIdAuthenticator {
-    fn write_with<W: StructuralWriter>(
-        &self,
-        writer: W,
-    ) -> Result<<W as PrimitiveWriter>::Repr, <W as PrimitiveWriter>::Error> {
-        let header_writer = writer.record(1)?;
-        let mut body_writer = header_writer
-            .write_extant_attr(GOOGLE_AUTH_TAG)?
-            .complete_header(RecordBodyKind::MapLike, 5)?;
-        body_writer = body_writer.write_i64_slot("token_skew", self.token_skew)?;
-        body_writer = body_writer.write_i64_slot("cert_skew", self.key_store.cert_skew())?;
-        body_writer = body_writer.write_slot_into("publicKeyUri", self.key_store.key_url())?;
-        let emails = self.emails.iter().cloned().collect::<Vec<_>>();
-        body_writer = body_writer.write_slot_into("emails", emails)?;
-        let audiences = self.audiences.iter().cloned().collect::<Vec<_>>();
-        body_writer = body_writer.write_slot_into("audiences", audiences)?;
-        body_writer.done()
-    }
-
-    fn write_into<W: StructuralWriter>(
-        self,
-        writer: W,
-    ) -> Result<<W as PrimitiveWriter>::Repr, <W as PrimitiveWriter>::Error> {
-        let header_writer = writer.record(1)?;
-        let mut body_writer = header_writer
-            .write_extant_attr(GOOGLE_AUTH_TAG)?
-            .complete_header(RecordBodyKind::MapLike, 5)?;
-        body_writer = body_writer.write_i64_slot("token_skew", self.token_skew)?;
-        body_writer = body_writer.write_i64_slot("cert_skew", self.key_store.cert_skew())?;
-        body_writer = body_writer.write_slot_into("publicKeyUri", self.key_store.key_url())?;
-        let emails = self.emails.into_iter().collect::<Vec<_>>();
-        body_writer = body_writer.write_slot_into("emails", emails)?;
-        let audiences = self.audiences.into_iter().collect::<Vec<_>>();
-        body_writer = body_writer.write_slot_into("audiences", audiences)?;
-        body_writer.done()
-    }
-
-    fn num_attributes(&self) -> usize {
-        1
-    }
-}
-
-#[derive(Clone, Copy)]
-enum AuthRecogField {
-    TokenSkew,
-    CertSkew,
-    PublicKeyUri,
-    Emails,
-    Audiences,
-}
-
-enum AuthRecogState {
-    Init,
-    Tag,
-    AfterTag,
-    InBody,
-    Slot(AuthRecogField),
-    Field(AuthRecogField),
-}
-
-pub struct GoogleIdAuthenticatorRecognizer {
-    state: AuthRecogState,
-    token_skew: Option<i64>,
-    cert_skew: Option<i64>,
-    public_key_uri: Option<Url>,
-    emails: Option<Vec<String>>,
-    audiences: Option<Vec<String>>,
-    emails_recognizer: VecRecognizer<String, StringRecognizer>,
-    audiences_recognizer: VecRecognizer<String, StringRecognizer>,
-}
-
-impl GoogleIdAuthenticatorRecognizer {
-    fn try_done(&mut self) -> Result<GoogleIdAuthenticator, ReadError> {
-        let GoogleIdAuthenticatorRecognizer {
-            token_skew,
-            cert_skew,
-            public_key_uri,
-            emails,
-            audiences,
-            ..
-        } = self;
-        let mut missing = vec![];
-        if token_skew.is_none() {
-            missing.push(Text::new("token_skew"));
-        }
-        if cert_skew.is_none() {
-            missing.push(Text::new("cert_skew"));
-        }
-        if public_key_uri.is_none() {
-            missing.push(Text::new("publicKeyUri"));
-        }
-        if emails.is_none() {
-            missing.push(Text::new("emails"));
-        }
-        if audiences.is_none() {
-            missing.push(Text::new("audiences"));
-        }
-        if let (
-            Some(token_skew),
-            Some(cert_skew),
-            Some(public_key_uri),
-            Some(emails),
-            Some(audiences),
-        ) = (
-            token_skew.take(),
-            cert_skew.take(),
-            public_key_uri.take(),
-            emails.take(),
-            audiences.take(),
-        ) {
-            Ok(GoogleIdAuthenticator {
-                token_skew,
-                key_store: GoogleKeyStore::new(public_key_uri, cert_skew),
-                emails: emails.into_iter().collect(),
-                audiences: audiences.into_iter().collect(),
-            })
-        } else {
-            Err(ReadError::MissingFields(missing))
-        }
-    }
-}
-
-impl Default for GoogleIdAuthenticatorRecognizer {
-    fn default() -> Self {
-        GoogleIdAuthenticatorRecognizer {
-            state: AuthRecogState::Init,
-            token_skew: None,
-            cert_skew: None,
-            public_key_uri: None,
-            emails: None,
-            audiences: None,
-            emails_recognizer: <Vec<String>>::make_recognizer(),
-            audiences_recognizer: <Vec<String>>::make_recognizer(),
-        }
-    }
-}
-
-impl Recognizer for GoogleIdAuthenticatorRecognizer {
-    type Target = GoogleIdAuthenticator;
-
-    fn feed_event(&mut self, input: ReadEvent<'_>) -> Option<Result<Self::Target, ReadError>> {
-        match &self.state {
-            AuthRecogState::Init => {
-                if let ReadEvent::StartAttribute(name) = input {
-                    if name == GOOGLE_AUTH_TAG {
-                        self.state = AuthRecogState::Tag;
-                        None
-                    } else {
-                        Some(Err(ReadError::MissingTag))
-                    }
-                } else {
-                    Some(Err(input.kind_error(ExpectedEvent::Attribute(Some(
-                        Text::new(GOOGLE_AUTH_TAG),
-                    )))))
-                }
-            }
-            AuthRecogState::Tag => match input {
-                ReadEvent::Extant => None,
-                ReadEvent::EndAttribute => {
-                    self.state = AuthRecogState::AfterTag;
-                    None
-                }
-                ow => Some(Err(ow.kind_error(ExpectedEvent::EndOfAttribute))),
-            },
-            AuthRecogState::AfterTag => {
-                if matches!(&input, ReadEvent::StartBody) {
-                    self.state = AuthRecogState::InBody;
-                    None
-                } else {
-                    Some(Err(input.kind_error(ExpectedEvent::RecordBody)))
-                }
-            }
-            AuthRecogState::InBody => match input {
-                ReadEvent::TextValue(slot_name) => match slot_name.borrow() {
-                    "token_skew" => {
-                        self.state = AuthRecogState::Slot(AuthRecogField::TokenSkew);
-                        None
-                    }
-                    "cert_skew" => {
-                        self.state = AuthRecogState::Slot(AuthRecogField::CertSkew);
-                        None
-                    }
-                    "publicKeyUri" => {
-                        self.state = AuthRecogState::Slot(AuthRecogField::PublicKeyUri);
-                        None
-                    }
-                    "emails" => {
-                        self.state = AuthRecogState::Slot(AuthRecogField::Emails);
-                        None
-                    }
-                    "audiences" => {
-                        self.state = AuthRecogState::Slot(AuthRecogField::Audiences);
-                        None
-                    }
-                    ow => Some(Err(ReadError::UnexpectedField(Text::new(ow)))),
-                },
-                ReadEvent::EndRecord => Some(self.try_done()),
-                ow => Some(Err(ow.kind_error(ExpectedEvent::Or(vec![
-                    ExpectedEvent::ValueEvent(ValueKind::Text),
-                    ExpectedEvent::EndOfRecord,
-                ])))),
-            },
-            AuthRecogState::Slot(fld) => {
-                if matches!(&input, ReadEvent::Slot) {
-                    self.state = AuthRecogState::Field(*fld);
-                    None
-                } else {
-                    Some(Err(input.kind_error(ExpectedEvent::Slot)))
-                }
-            }
-            AuthRecogState::Field(AuthRecogField::TokenSkew) => match input {
-                ReadEvent::Number(NumericValue::Int(n)) => {
-                    self.token_skew = Some(n);
-                    self.state = AuthRecogState::InBody;
-                    None
-                }
-                ReadEvent::Number(NumericValue::UInt(n)) => {
-                    if let Ok(m) = i64::try_from(n) {
-                        self.token_skew = Some(m);
-                        self.state = AuthRecogState::InBody;
-                        None
-                    } else {
-                        Some(Err(ReadError::NumberOutOfRange))
-                    }
-                }
-                ow => Some(Err(
-                    ow.kind_error(ExpectedEvent::ValueEvent(ValueKind::UInt64))
-                )),
-            },
-            AuthRecogState::Field(AuthRecogField::CertSkew) => match input {
-                ReadEvent::Number(NumericValue::Int(n)) => {
-                    self.cert_skew = Some(n);
-                    self.state = AuthRecogState::InBody;
-                    None
-                }
-                ReadEvent::Number(NumericValue::UInt(n)) => {
-                    if let Ok(m) = i64::try_from(n) {
-                        self.cert_skew = Some(m);
-                        self.state = AuthRecogState::InBody;
-                        None
-                    } else {
-                        Some(Err(ReadError::NumberOutOfRange))
-                    }
-                }
-                ow => Some(Err(
-                    ow.kind_error(ExpectedEvent::ValueEvent(ValueKind::UInt64))
-                )),
-            },
-            AuthRecogState::Field(AuthRecogField::PublicKeyUri) => {
-                if let ReadEvent::TextValue(text) = input {
-                    if let Ok(url) = Url::parse(text.borrow()) {
-                        self.public_key_uri = Some(url);
-                        self.state = AuthRecogState::InBody;
-                        None
-                    } else {
-                        Some(Err(ReadError::Malformatted {
-                            text: text.into(),
-                            message: Text::new("No a valid URL."),
-                        }))
-                    }
-                } else {
-                    Some(Err(
-                        input.kind_error(ExpectedEvent::ValueEvent(ValueKind::Text))
-                    ))
-                }
-            }
-            AuthRecogState::Field(AuthRecogField::Emails) => {
-                match self.emails_recognizer.feed_event(input)? {
-                    Ok(v) => {
-                        self.emails = Some(v);
-                        self.state = AuthRecogState::InBody;
-                        None
-                    }
-                    Err(e) => Some(Err(e)),
-                }
-            }
-            AuthRecogState::Field(AuthRecogField::Audiences) => {
-                match self.audiences_recognizer.feed_event(input)? {
-                    Ok(v) => {
-                        self.audiences = Some(v);
-                        self.state = AuthRecogState::InBody;
-                        None
-                    }
-                    Err(e) => Some(Err(e)),
-                }
-            }
-        }
-    }
-
-    fn reset(&mut self) {
-        let GoogleIdAuthenticatorRecognizer {
-            state,
-            token_skew,
-            cert_skew,
-            public_key_uri,
-            emails,
-            audiences,
-            emails_recognizer,
-            audiences_recognizer,
-        } = self;
-        *state = AuthRecogState::Init;
-        *token_skew = None;
-        *cert_skew = None;
-        *public_key_uri = None;
-        *emails = None;
-        *audiences = None;
-        emails_recognizer.reset();
-        audiences_recognizer.reset();
-    }
-}
-
-impl RecognizerReadable for GoogleIdAuthenticator {
-    type Rec = GoogleIdAuthenticatorRecognizer;
-    type AttrRec = SimpleAttrBody<GoogleIdAuthenticatorRecognizer>;
-    type BodyRec = Self::Rec;
-
-    fn make_recognizer() -> Self::Rec {
-        GoogleIdAuthenticatorRecognizer::default()
-    }
-
-    fn make_attr_recognizer() -> Self::AttrRec {
-        SimpleAttrBody::new(Self::make_recognizer())
-    }
-
-    fn make_body_recognizer() -> Self::BodyRec {
-        Self::make_recognizer()
-    }
-}
-
-impl From<reqwest::Error> for AuthenticationError {
-    fn from(e: reqwest::Error) -> Self {
-        AuthenticationError::Malformatted(e.to_string())
-    }
-}
-
-impl From<serde_json::Error> for AuthenticationError {
-    fn from(e: serde_json::Error) -> Self {
-        AuthenticationError::Malformatted(e.to_string())
-    }
-}
-
-#[derive(Serialize, Deserialize, Debug, PartialEq, Form)]
-pub struct GoogleId {
-    email_verified: bool,
-    #[serde(rename = "azp")]
-    authorised_party: String,
-    #[serde(rename = "hd")]
-    hosted_domain: Option<Url>,
-    email: String,
-    name: String,
-    picture: Url,
-    given_name: String,
-    family_name: String,
-    locale: String,
-}
-
-impl CompactJson for GoogleId {}
-
-#[derive(Form)]
-#[form(tag = "googleId")]
-pub struct GoogleIdCredentials(String);
-
-impl<'s> Authenticator<'s> for GoogleIdAuthenticator {
-    type Credentials = GoogleIdCredentials;
-    type AuthenticateFuture = BoxFuture<'s, Result<IssuedPolicy, AuthenticationError>>;
-
-    /// Verifies that the provided Google ID token is valid.
-    ///
-    /// Verifies that the RS256 signature was signed using the public keys from the provided
-    /// `public_key_uri`, that the time that the expiry time of the token is valid (providing a
-    /// pre-configured clock skew grace period), that the issuer is one of `accounts.google.com`
-    /// or `https://accounts.google.com`, that the audience ID is one of the permitted values, and
-    /// that the email address associated with the token is also permitted.
-    ///
-    /// Returns `Ok` and an associated `PolicyDirective` or an `Err` if there was an error when
-    /// decoding the JWT.
-    fn authenticate(&'s mut self, credentials: GoogleIdCredentials) -> Self::AuthenticateFuture {
-        async move {
-            let jwt: Compact<ClaimsSet<GoogleId>, Empty> = Compact::new_encoded(&credentials.0);
-            let keys = self.key_store.keys().await?;
-
-            match jwt.decode_with_jwks(keys, Some(SignatureAlgorithm::RS256)) {
-                Ok(token) => {
-                    let (_header, token) = token.unwrap_decoded();
-                    let ClaimsSet {
-                        registered,
-                        private,
-                        ..
-                    } = token;
-
-                    // Check that the token has not expired
-                    let expiry_timestamp = match &registered.expiry {
-                        Some(expiry_time) => {
-                            if expiry_time.lt(&(Utc::now() + Duration::seconds(self.token_skew))) {
-                                return Ok(IssuedPolicy::deny(Value::Extant));
-                            } else {
-                                (**expiry_time).into()
-                            }
-                        }
-                        None => return Ok(IssuedPolicy::deny(Value::Extant)),
-                    };
-
-                    // Check that the issuer of the token is one of the expected Google issuers
-                    match &registered.issuer {
-                        Some(uri) => {
-                            let uri = uri.as_ref();
-                            if ![GOOGLE_ISS1, GOOGLE_ISS2].contains(&uri) {
-                                return Ok(IssuedPolicy::deny(Value::Extant));
-                            }
-                        }
-                        None => return Ok(IssuedPolicy::deny(Value::Extant)),
-                    }
-
-                    // Check the token's audience ID matches ours
-                    match &registered.audience {
-                        Some(SingleOrMultiple::Single(audience)) => {
-                            if !self.audiences.contains(audience) {
-                                return Ok(IssuedPolicy::forbid(Value::Extant));
-                            }
-                        }
-                        Some(SingleOrMultiple::Multiple(audiences)) => {
-                            let matched_audience =
-                                audiences.iter().any(|aud| self.audiences.contains(aud));
-
-                            if !matched_audience {
-                                return Ok(IssuedPolicy::forbid(Value::Extant));
-                            }
-                        }
-                        None => return Ok(IssuedPolicy::forbid(Value::Extant)),
-                    }
-
-                    // Check that the email of the token matches one of the configured emails
-                    if self.emails.contains(&private.email) {
-                        let token = Token::new(private.email.clone(), Some(expiry_timestamp));
-                        let policy = PolicyDirective::allow(private.into_value());
-
-                        Ok(IssuedPolicy::new(token, policy))
-                    } else {
-                        Ok(IssuedPolicy::deny(Value::Extant))
-                    }
-                }
-                Err(_) => Err(AuthenticationError::Malformatted(
-                    "Failed to decode JWT".into(),
-                )),
-            }
-        }
-        .boxed()
-    }
-}
-
-impl From<GoogleKeyStoreError> for AuthenticationError {
-    fn from(e: GoogleKeyStoreError) -> Self {
-        AuthenticationError::KeyStoreError(e.to_string())
-    }
-}
-
-#[derive(Default)]
-pub struct GoogleIdAuthenticatorBuilder {
-    /// Number of seconds before the public key certificate expiry time before forcing a refresh.
-    token_skew: Option<i64>,
-    /// Number of seconds beyond the token's expiry time that are permitted.
-    cert_skew: Option<i64>,
-    /// Permitted emails for this resource.
-    emails: Option<HashSet<String>>,
-    /// Permitted audiences for this resource.
-    audiences: Option<HashSet<String>>,
-    /// An optional override for the public key URL.
-    key_issuer_url: Option<Url>,
-}
-
-impl GoogleIdAuthenticatorBuilder {
-    pub fn token_skew(mut self, duration: NonZeroI64) -> Self {
-        self.token_skew = Some(duration.get());
-        self
-    }
-
-    pub fn cert_skew(mut self, duration: NonZeroI64) -> Self {
-        self.cert_skew = Some(duration.get());
-        self
-    }
-
-    pub fn emails(mut self, emails: HashSet<String>) -> Self {
-        self.emails = Some(emails);
-        self
-    }
-
-    pub fn audiences(mut self, audiences: HashSet<String>) -> Self {
-        self.audiences = Some(audiences);
-        self
-    }
-
-    pub fn key_issuer_url(mut self, url: Url) -> Self {
-        self.key_issuer_url = Some(url);
-        self
-    }
-
-    pub fn build(self) -> GoogleIdAuthenticator {
-        let public_key_uri = self.key_issuer_url.unwrap_or_else(|| {
-            Url::parse(GOOGLE_JWK_CERTS_URL)
-                .expect("Failed to parse default Google JWK certificate URL")
-        });
-        let token_skew = self.token_skew.unwrap_or(DEFAULT_TOKEN_SKEW);
-        let permitted_cert_exp_skew = self.cert_skew.unwrap_or(DEFAULT_CERT_SKEW);
-
-        GoogleIdAuthenticator {
-            token_skew,
-            key_store: GoogleKeyStore::new(public_key_uri, permitted_cert_exp_skew),
-            emails: self.emails.expect("At least one email must be provided"),
-            audiences: self
-                .audiences
-                .expect("At least one audience must be provided"),
-        }
-    }
-}
diff --git a/swim_server/auth/src/googleid/store.rs b/swim_server/auth/src/googleid/store.rs
deleted file mode 100644
index 3165bd5c0..000000000
--- a/swim_server/auth/src/googleid/store.rs
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright 2015-2021 SWIM.AI inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use biscuit::jwk::JWKSet;
-use biscuit::Empty;
-use chrono::{DateTime, FixedOffset, Utc};
-use http::header::{CACHE_CONTROL, EXPIRES};
-use http::HeaderMap;
-use std::fmt::{Display, Formatter};
-use swim_runtime::time::delay::delay_for;
-use swim_utilities::future::retryable::RetryStrategy;
-use url::Url;
-
-const MAX_AGE_DIRECTIVE: &str = "max-age";
-const NO_STORE_CACHEABILITY: &str = "no-store";
-pub const DEFAULT_CERT_SKEW: i64 = 30;
-pub const GOOGLE_JWK_CERTS_URL: &str = "https://www.googleapis.com/oauth2/v3/certs";
-
-#[derive(Debug, PartialEq)]
-enum KeyStoreStrategy {
-    /// Don't cache anything and always fetch the latest value when it's accessed.
-    NoStore,
-    /// Revalidate the entry at the provided time.
-    RevalidateAt(DateTime<FixedOffset>),
-}
-
-#[derive(Debug, PartialEq)]
-pub struct GoogleKeyStore {
-    strategy: KeyStoreStrategy,
-    /// Number of seconds before the public key certificate expiry time before forcing a refresh.
-    permitted_cert_exp_skew: i64,
-    /// The retry strategy to use after failing to refresh the public keys.
-    retry_strategy: RetryStrategy,
-    public_key_url: Url,
-    certs: JWKSet<Empty>,
-}
-
-impl Default for GoogleKeyStore {
-    fn default() -> Self {
-        GoogleKeyStore {
-            strategy: KeyStoreStrategy::NoStore,
-            permitted_cert_exp_skew: DEFAULT_CERT_SKEW,
-            retry_strategy: Default::default(),
-            public_key_url: Url::parse(GOOGLE_JWK_CERTS_URL)
-                .expect("Failed to parse default Google certificate URL"),
-            certs: JWKSet { keys: vec![] },
-        }
-    }
-}
-
-#[derive(Debug, PartialEq)]
-pub enum GoogleKeyStoreError {
-    ServerError,
-    UpdateError(String),
-}
-
-impl Display for GoogleKeyStoreError {
-    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
-        match self {
-            GoogleKeyStoreError::ServerError => write!(
-                f,
-                "The server responded with an error when attempting to update the certificate"
-            ),
-            GoogleKeyStoreError::UpdateError(e) => {
-                write!(f, "Failed to update certificates: {}", e)
-            }
-        }
-    }
-}
-
-impl GoogleKeyStore {
-    pub fn new(public_key_url: Url, cert_skew: i64) -> GoogleKeyStore {
-        GoogleKeyStore {
-            strategy: KeyStoreStrategy::NoStore,
-            permitted_cert_exp_skew: cert_skew,
-            retry_strategy: Default::default(),
-            public_key_url,
-            certs: JWKSet { keys: vec![] },
-        }
-    }
-
-    pub(crate) fn cert_skew(&self) -> i64 {
-        self.permitted_cert_exp_skew
-    }
-
-    pub(crate) fn key_url(&self) -> Url {
-        self.public_key_url.clone()
-    }
-
-    fn stale(&self) -> bool {
-        match self.strategy {
-            KeyStoreStrategy::NoStore => true,
-            KeyStoreStrategy::RevalidateAt(expires) => {
-                expires.lt(&Into::<DateTime<FixedOffset>>::into(Utc::now()))
-            }
-        }
-    }
-
-    fn parse_response(&self, headers: &HeaderMap) -> Result<KeyStoreStrategy, GoogleKeyStoreError> {
-        let cache_control_headers = headers.get_all(CACHE_CONTROL);
-
-        for cache_control_header in cache_control_headers {
-            let cache_control_header = cache_control_header.to_str().unwrap();
-            let directives = cache_control_header.split(',');
-
-            for directive in directives {
-                match directive.trim() {
-                    NO_STORE_CACHEABILITY => return Ok(KeyStoreStrategy::NoStore),
-                    dir if dir.starts_with(MAX_AGE_DIRECTIVE) => {
-                        let mut value_opt = dir.split('=').skip(1);
-
-                        return match value_opt.next() {
-                            Some(time) => match time.parse::<i64>() {
-                                Ok(seconds) => {
-                                    let expires = Utc::now()
-                                        + chrono::Duration::seconds(
-                                            seconds - self.permitted_cert_exp_skew,
-                                        );
-                                    Ok(KeyStoreStrategy::RevalidateAt(expires.into()))
-                                }
-                                Err(e) => Err(GoogleKeyStoreError::UpdateError(format!(
-                                    "Failed to parse max-age value: {}",
-                                    e
-                                ))),
-                            },
-                            None => Err(GoogleKeyStoreError::UpdateError(
-                                "Missing max-age value".into(),
-                            )),
-                        };
-                    }
-                    _ => {}
-                }
-            }
-        }
-
-        match headers.get(EXPIRES) {
-            Some(time) => match time.to_str() {
-                Ok(time) => match DateTime::parse_from_rfc2822(time) {
-                    Ok(expires) => Ok(KeyStoreStrategy::RevalidateAt(expires)),
-                    Err(e) => Err(GoogleKeyStoreError::UpdateError(format!(
-                        "Failed to parse expiry time: {}",
-                        e
-                    ))),
-                },
-                Err(e) => Err(GoogleKeyStoreError::UpdateError(format!(
-                    "Failed to parse expiry time: {}",
-                    e
-                ))),
-            },
-            None => Ok(KeyStoreStrategy::NoStore),
-        }
-    }
-
-    pub async fn refresh(&mut self) -> Result<(), GoogleKeyStoreError> {
-        if !self.stale() && !self.certs.keys.is_empty() {
-            return Ok(());
-        }
-
-        let mut has_errored = false;
-
-        loop {
-            let get_result = reqwest::get(self.public_key_url.as_str()).await;
-
-            match get_result {
-                Ok(response) if response.status().is_success() => {
-                    if has_errored {
-                        self.retry_strategy = RetryStrategy::default();
-                    }
-
-                    self.strategy = self.parse_response(response.headers())?;
-
-                    let response_body = response.text().await?;
-
-                    self.certs = serde_json::from_str(&response_body)?;
-
-                    return Ok(());
-                }
-                Ok(response) if response.status().is_server_error() => {
-                    match self.retry_strategy.next() {
-                        Some(Some(duration)) => {
-                            has_errored = true;
-                            delay_for(duration).await;
-                        }
-                        _ => return Err(GoogleKeyStoreError::ServerError),
-                    }
-                }
-                _ => return Err(GoogleKeyStoreError::ServerError),
-            }
-        }
-    }
-
-    pub async fn keys(&mut self) -> Result<&JWKSet<Empty>, GoogleKeyStoreError> {
-        self.refresh().await?;
-        Ok(&self.certs)
-    }
-}
-
-impl From<reqwest::Error> for GoogleKeyStoreError {
-    fn from(e: reqwest::Error) -> Self {
-        GoogleKeyStoreError::UpdateError(e.to_string())
-    }
-}
-
-impl From<serde_json::Error> for GoogleKeyStoreError {
-    fn from(e: serde_json::Error) -> Self {
-        GoogleKeyStoreError::UpdateError(e.to_string())
-    }
-}
-
-#[test]
-fn store_no_cache() {
-    let authenticator = GoogleKeyStore::new(Url::parse(GOOGLE_JWK_CERTS_URL).unwrap(), 30);
-
-    let mut header_map = HeaderMap::new();
-    header_map.insert(
-        CACHE_CONTROL,
-        http::HeaderValue::from_static(NO_STORE_CACHEABILITY),
-    );
-
-    let parse_result = authenticator.parse_response(&header_map);
-    assert_eq!(parse_result, Ok(KeyStoreStrategy::NoStore));
-}
-
-#[test]
-fn store_revalidate() {
-    let authenticator = GoogleKeyStore::new(Url::parse(GOOGLE_JWK_CERTS_URL).unwrap(), 30);
-    let grace_period = 30;
-
-    let mut header_map = HeaderMap::new();
-    header_map.insert(
-        CACHE_CONTROL,
-        http::HeaderValue::from_str(&format!("{}={}", MAX_AGE_DIRECTIVE, grace_period)).unwrap(),
-    );
-
-    let start = Utc::now();
-
-    let parse_result = authenticator.parse_response(&header_map);
-    match parse_result {
-        Ok(KeyStoreStrategy::RevalidateAt(expires)) => {
-            assert!(start < expires && expires < Utc::now() + chrono::Duration::seconds(30));
-        }
-        _ => panic!("Expected a revalidation strategy"),
-    }
-}
-
-#[test]
-fn store_unknown_directive() {
-    let authenticator = GoogleKeyStore::new(Url::parse(GOOGLE_JWK_CERTS_URL).unwrap(), 30);
-
-    let mut header_map = HeaderMap::new();
-    header_map.insert(
-        CACHE_CONTROL,
-        http::HeaderValue::from_static("only-if-cached"),
-    );
-
-    let parse_result = authenticator
-        .parse_response(&header_map)
-        .expect("Expected a valid key store strategy");
-
-    assert_eq!(parse_result, KeyStoreStrategy::NoStore)
-}
diff --git a/swim_server/auth/src/lib.rs b/swim_server/auth/src/lib.rs
deleted file mode 100644
index fdd45a2f5..000000000
--- a/swim_server/auth/src/lib.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2015-2021 SWIM.AI inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::googleid::GoogleIdAuthenticator;
-use crate::policy::{IssuedPolicy, PolicyDirective};
-use crate::token::Token;
-use futures::future::ready;
-use futures::Future;
-use futures_util::future::Ready;
-use std::fmt::Display;
-use swim_common::form::Form;
-use swim_common::model::Value;
-
-pub mod googleid;
-pub mod policy;
-mod token;
-
-pub enum AgentAuthenticator {
-    AlwaysAllow(AlwaysAllowAuthenticator),
-    AlwaysDeny(AlwaysDenyAuthenticator),
-    AlwaysForbid(AlwaysForbidAuthenticator),
-    GoogleId(Box<GoogleIdAuthenticator>),
-}
-
-#[derive(Debug, Eq, PartialEq)]
-pub enum AuthenticationError {
-    KeyStoreError(String),
-    ServerError,
-    Malformatted(String),
-}
-
-impl AuthenticationError {
-    pub fn malformatted<A: Display>(msg: &str, cause: A) -> AuthenticationError {
-        AuthenticationError::Malformatted(format!("{}: {}", msg, cause))
-    }
-}
-
-/// A trait for defining authenticators that validates a remote host or user credentials against
-/// some authentication implementation.
-pub trait Authenticator<'s>: Form {
-    /// The type of the structure that this authenticator requires.
-    type Credentials: Form;
-    /// A future that resolves to either a policy for the remote host or an associated error.
-    type AuthenticateFuture: Future<Output = Result<IssuedPolicy, AuthenticationError>> + 's;
-
-    /// Attempt to authenticate the remote host or user.
-    fn authenticate(&'s mut self, credentials: Self::Credentials) -> Self::AuthenticateFuture;
-}
-
-/// An authenticator that will always allow the remote host.
-#[derive(Form)]
-#[form(tag = "allow")]
-pub struct AlwaysAllowAuthenticator;
-
-impl<'s> Authenticator<'s> for AlwaysAllowAuthenticator {
-    type Credentials = Value;
-    type AuthenticateFuture = Ready<Result<IssuedPolicy, AuthenticationError>>;
-
-    fn authenticate(&'s mut self, credentials: Self::Credentials) -> Self::AuthenticateFuture {
-        ready(Ok(IssuedPolicy::new(
-            Token::empty(),
-            PolicyDirective::allow(credentials),
-        )))
-    }
-}
-
-/// An authenticator that will always deny the remote host.
-#[derive(Form)]
-#[form(tag = "deny")]
-pub struct AlwaysDenyAuthenticator;
-impl<'s> Authenticator<'s> for AlwaysDenyAuthenticator {
-    type Credentials = Value;
-    type AuthenticateFuture = Ready<Result<IssuedPolicy, AuthenticationError>>;
-
-    fn authenticate(&'s mut self, credentials: Self::Credentials) -> Self::AuthenticateFuture {
-        ready(Ok(IssuedPolicy::new(
-            Token::empty(),
-            PolicyDirective::deny(credentials),
-        )))
-    }
-}
-
-/// An authenticator that will always forbid the remote host.
-#[derive(Form)]
-#[form(tag = "forbid")]
-pub struct AlwaysForbidAuthenticator;
-impl<'s> Authenticator<'s> for AlwaysForbidAuthenticator {
-    type Credentials = Value;
-    type AuthenticateFuture = Ready<Result<IssuedPolicy, AuthenticationError>>;
-
-    fn authenticate(&'s mut self, credentials: Self::Credentials) -> Self::AuthenticateFuture {
-        ready(Ok(IssuedPolicy::new(
-            Token::empty(),
-            PolicyDirective::forbid(credentials),
-        )))
-    }
-}
diff --git a/swim_server/auth/src/policy/mod.rs b/swim_server/auth/src/policy/mod.rs
deleted file mode 100644
index 0a9463488..000000000
--- a/swim_server/auth/src/policy/mod.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright 2015-2021 SWIM.AI inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::token::{Expired, Token};
-use swim_common::model::Value;
-
-#[derive(Debug, Clone, PartialEq)]
-pub struct PolicyDirective {
-    value: Value,
-    policy: PolicyEffect,
-}
-
-impl Default for PolicyDirective {
-    fn default() -> Self {
-        PolicyDirective::allow(Value::Extant)
-    }
-}
-
-impl PolicyDirective {
-    pub fn allow(value: Value) -> PolicyDirective {
-        PolicyDirective {
-            value,
-            policy: PolicyEffect::Allow,
-        }
-    }
-
-    pub fn deny(value: Value) -> PolicyDirective {
-        PolicyDirective {
-            value,
-            policy: PolicyEffect::Deny,
-        }
-    }
-
-    pub fn forbid(value: Value) -> PolicyDirective {
-        PolicyDirective {
-            value,
-            policy: PolicyEffect::Forbid,
-        }
-    }
-
-    pub fn allowed(&self) -> bool {
-        matches!(self.policy, PolicyEffect::Allow)
-    }
-
-    pub fn denied(&self) -> bool {
-        matches!(self.policy, PolicyEffect::Deny)
-    }
-
-    pub fn forbidden(&self) -> bool {
-        matches!(self.policy, PolicyEffect::Forbid)
-    }
-}
-
-#[derive(Debug, PartialOrd, PartialEq, Eq, Copy, Clone)]
-pub enum PolicyEffect {
-    Allow,
-    Deny,
-    Forbid,
-}
-
-pub struct IssuedPolicy {
-    token: Token,
-    policy: PolicyDirective,
-}
-
-impl IssuedPolicy {
-    pub fn new(token: Token, policy: PolicyDirective) -> IssuedPolicy {
-        IssuedPolicy { token, policy }
-    }
-
-    pub fn allow(value: Value) -> IssuedPolicy {
-        IssuedPolicy::new(Token::empty(), PolicyDirective::allow(value))
-    }
-
-    pub fn deny(value: Value) -> IssuedPolicy {
-        IssuedPolicy::new(Token::empty(), PolicyDirective::deny(value))
-    }
-
-    pub fn forbid(value: Value) -> IssuedPolicy {
-        IssuedPolicy::new(Token::empty(), PolicyDirective::forbid(value))
-    }
-
-    pub fn policy(&self) -> &PolicyDirective {
-        &self.policy
-    }
-
-    pub fn value(&self) -> &Value {
-        &self.policy.value
-    }
-
-    pub fn into_policy_value(self) -> Value {
-        self.policy.value
-    }
-}
-
-impl Expired for IssuedPolicy {
-    fn expired(&self, skew: i64) -> bool {
-        self.token.expired(skew)
-    }
-}
diff --git a/swim_server/auth/src/token.rs b/swim_server/auth/src/token.rs
deleted file mode 100644
index 81bdaf791..000000000
--- a/swim_server/auth/src/token.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2015-2021 SWIM.AI inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use chrono::{Duration, Utc};
-use swim_common::model::time::Timestamp;
-
-#[derive(Clone, PartialEq, Eq, Debug, Ord, PartialOrd, Hash)]
-pub struct Token {
-    id: String,
-    expires: Option<Timestamp>,
-}
-
-impl Token {
-    /// Creates a new token that will expire at the provided timestamp if it is `Some(_)` or which
-    /// will never expire if it is `None`.
-    pub fn new(id: String, expires: Option<Timestamp>) -> Token {
-        Token { id, expires }
-    }
-
-    pub fn empty() -> Token {
-        Token {
-            id: String::new(),
-            expires: None,
-        }
-    }
-}
-
-pub trait Expired {
-    fn expired(&self, skew: i64) -> bool;
-}
-
-impl Expired for Token {
-    fn expired(&self, skew: i64) -> bool {
-        match self.expires {
-            Some(expires) => expires.as_ref().lt(&(Utc::now() + Duration::seconds(skew))),
-            None => false,
-        }
-    }
-}


Test patch:
diff --git a/swim_server/auth/src/googleid/tests.rs b/swim_server/auth/src/googleid/tests.rs
deleted file mode 100644
index cfbc0b46f..000000000
--- a/swim_server/auth/src/googleid/tests.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2015-2021 SWIM.AI inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use crate::googleid::store::{GoogleKeyStore, GOOGLE_JWK_CERTS_URL};
-use crate::googleid::{GoogleId, GoogleIdAuthenticator, GoogleIdCredentials};
-use biscuit::jwa::SignatureAlgorithm;
-use biscuit::jws::{Compact, RegisteredHeader, Secret};
-use biscuit::{ClaimsSet, Empty, RegisteredClaims, SingleOrMultiple};
-use im::HashSet;
-use std::str::FromStr;
-use swim_common::form::Form;
-use swim_common::model::{Attr, Item, Value};
-use url::Url;
-
-fn expected_biscuit() -> Compact<ClaimsSet<GoogleId>, Empty> {
-    let expected_claims = ClaimsSet {
-        registered: RegisteredClaims {
-            issuer: Some(FromStr::from_str("accounts.google.com").unwrap()),
-            subject: Some(FromStr::from_str("117614620700092979612").unwrap()),
-            audience: Some(SingleOrMultiple::Single(
-                FromStr::from_str(
-                    "339656303991-hjc1rr2vv0lclnqg0jq76r4qar9c8p62.apps.googleusercontent.com",
-                )
-                .unwrap(),
-            )),
-            not_before: None,
-            ..Default::default()
-        },
-        private: GoogleId {
-            email_verified: false,
-            authorised_party: "".to_string(),
-            hosted_domain: Some("https://swim.ai/".parse().unwrap()),
-            email: "tom@swim.ai".to_string(),
-            name: "Tom".to_string(),
-            picture: "https://www.swim.ai/images/marlin-swim-blue.svg"
-                .parse()
-                .unwrap(),
-            given_name: "Tom".to_string(),
-            family_name: "Tom".to_string(),
-            locale: "EN".to_string(),
-        },
-    };
-
-    Compact::new_decoded(
-        From::from(RegisteredHeader {
-            algorithm: SignatureAlgorithm::RS256,
-            ..Default::default()
-        }),
-        expected_claims,
-    )
-}
-
-fn expected_token() -> String {
-    "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhY2NvdW50cy5nb29nbGUuY29tIiwic3ViIjoiMTE3N\
-        jE0NjIwNzAwMDkyOTc5NjEyIiwiYXVkIjoiMzM5NjU2MzAzOTkxLWhqYzFycjJ2djBsY2xucWcwanE3NnI0cWFyOWM4\
-        cDYyLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJhenAiOiIiLCJoZCI\
-        6Imh0dHBzOi8vc3dpbS5haS8iLCJlbWFpbCI6InRvbUBzd2ltLmFpIiwibmFtZSI6IlRvbSIsInBpY3R1cmUiOiJodH\
-        RwczovL3d3dy5zd2ltLmFpL2ltYWdlcy9tYXJsaW4tc3dpbS1ibHVlLnN2ZyIsImdpdmVuX25hbWUiOiJUb20iLCJmY\
-        W1pbHlfbmFtZSI6IlRvbSIsImxvY2FsZSI6IkVOIn0.USLIq07s92Ah4tMdJuxG-eiGwVxedFz8OBaI7r4GLLLzmJxq\
-        FDdPbX_RuS7yejU9L22C45X7siqsWXcFwqenkNcwKcDArAxdyR5rjL8iOoC5i8s6i754zbLsxdqq5yuWBG18vqXFl7D\
-        A0m2r8U60lUbdJh7kXDQNWn9hGfn4YjCnSEgCGkBVJQop_yIip-aTVzhahFEF4OFdMGBROHkUBeO5_FY_gV4PG5Qkc3\
-        tNvt6GNZU6PkeSu0dhuivnmNkqBwyAjywnL4_nqNmRivvv2YYviKug80xR-n-jSO3Sm0Nj-8x44gLDzQAbxrYJwOzsu\
-        MIe7Z7BTEC4lsNfpMfJWA"
-        .into()
-}
-
-#[test]
-fn test_signing() {
-    let private_key = Secret::rsa_keypair_from_file("test/private_key.der").unwrap();
-    let biscuit = expected_biscuit();
-    let encoded_biscuit = biscuit.into_encoded(&private_key).expect("Encode error");
-    let token = encoded_biscuit.unwrap_encoded().to_string();
-
-    assert_eq!(token, expected_token())
-}
-
-#[tokio::test]
-async fn test_decode() {
-    let secret = Secret::public_key_from_file("test/public_key.der").unwrap();
-    let credentials = GoogleIdCredentials(expected_token());
-    let compact: Compact<ClaimsSet<GoogleId>, Empty> = Compact::new_encoded(&credentials.0);
-    let algorithm = SignatureAlgorithm::RS256;
-    let decoded_biscuit = compact.decode(&secret, algorithm).expect("Decode failure");
-
-    assert_eq!(decoded_biscuit, expected_biscuit());
-}
-
-#[test]
-fn test_form() {
-    let mut emails = HashSet::new();
-    emails.insert("tom@swim.ai".to_string());
-
-    let mut audiences = HashSet::new();
-    audiences.insert("an audience".to_string());
-
-    let authenticator = GoogleIdAuthenticator {
-        token_skew: 5,
-        key_store: GoogleKeyStore::new(Url::parse(GOOGLE_JWK_CERTS_URL).unwrap(), 30),
-        emails,
-        audiences,
-    };
-
-    let value = Value::Record(
-        vec![Attr::of("googleId")],
-        vec![
-            Item::of(("token_skew", 5i64)),
-            Item::of(("cert_skew", 30i64)),
-            Item::of(("publicKeyUri", GOOGLE_JWK_CERTS_URL)),
-            Item::of(("emails", Value::from_vec(vec!["tom@swim.ai"]))),
-            Item::of(("audiences", Value::from_vec(vec!["an audience"]))),
-        ],
-    );
-
-    assert_eq!(authenticator.as_value(), value);
-    assert_eq!(
-        GoogleIdAuthenticator::try_from_value(&value),
-        Ok(authenticator)
-    );
-}
diff --git a/swim_server/auth/test/private_key.der b/swim_server/auth/test/private_key.der
deleted file mode 100644
index aa80f2d26..000000000
Binary files a/swim_server/auth/test/private_key.der and /dev/null differ
diff --git a/swim_server/auth/test/public_key.der b/swim_server/auth/test/public_key.der
deleted file mode 100644
index 53f58731e..000000000
Binary files a/swim_server/auth/test/public_key.der and /dev/null differ