// Copyright (c) 2024 Emmanuel Gil Peyrot // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. use xso::{AsXml, FromXml}; use crate::date::DateTime; use crate::ns; generate_elem_id!( /// A `` element, describing one mechanism allowed by the server to authenticate. Mechanism, "mechanism", FAST ); // TODO: Replace this with a proper bool once we can derive FromXml and AsXml on FastQuery. generate_attribute!( /// Whether TLS zero-roundtrip is possible. Tls0Rtt, "tls-0rtt", bool ); /// This is the `` element sent by the server as a SASL2 inline feature. #[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::FAST, name = "fast")] pub struct FastQuery { /// Whether TLS zero-roundtrip is possible. #[xml(attribute(default, name = "tls-0rtt"))] pub tls_0rtt: Tls0Rtt, /// A list of `` elements, listing all server allowed mechanisms. #[xml(child(n = ..))] pub mechanisms: Vec, } /// This is the `` element the client MUST include within its SASL2 authentication request. #[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::FAST, name = "fast")] pub struct FastResponse { /// Servers MUST reject any authentication requests received via TLS 0-RTT payloads that do not /// include a 'count' attribute, or where the count is less than or equal to a count that has /// already been processed for this token. This protects against replay attacks that 0-RTT is /// susceptible to. #[xml(attribute)] pub count: u32, /// If true and the client has successfully authenticated, the server MUST invalidate the /// token. #[xml(attribute(default))] pub invalidate: bool, } /// This is the `` element sent by the client in the SASL2 authenticate step. #[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::FAST, name = "request-token")] pub struct RequestToken { /// This element MUST contain a 'mechanism' attribute, the value of which MUST be one of the /// FAST mechanisms advertised by the server. #[xml(attribute)] pub mechanism: String, } /// This is the `` element sent by the server on successful SASL2 authentication containing /// a `` element. #[derive(FromXml, AsXml, Debug, Clone, PartialEq)] #[xml(namespace = ns::FAST, name = "token")] pub struct Token { /// The secret token to be used for subsequent authentications, as generated by the server. #[xml(attribute)] pub token: String, /// The timestamp at which the token will expire. #[xml(attribute)] pub expiry: DateTime, } #[cfg(test)] mod tests { use super::*; use minidom::Element; use std::str::FromStr; #[test] fn test_simple() { let elem: Element = "FOO-BAR" .parse() .unwrap(); let request = FastQuery::try_from(elem).unwrap(); assert_eq!(request.tls_0rtt, Tls0Rtt::False); assert_eq!(request.mechanisms, [Mechanism(String::from("FOO-BAR"))]); let elem: Element = "" .parse() .unwrap(); let response = FastResponse::try_from(elem).unwrap(); assert_eq!(response.count, 123); assert_eq!(response.invalidate, false); let elem: Element = "" .parse() .unwrap(); let request_token = RequestToken::try_from(elem).unwrap(); assert_eq!(request_token.mechanism, "FOO-BAR"); let elem: Element = "" .parse() .unwrap(); let token = Token::try_from(elem).unwrap(); assert_eq!(token.token, "ABCD"); assert_eq!( token.expiry, DateTime::from_str("2024-06-30T17:13:57+02:00").unwrap() ); } }