use crate::errors::{AuthenticationDeserializationError, DeserializationError, SerializationError}; use crate::standard_roundtrip; #[cfg(test)] use async_std::task; #[cfg(test)] use futures::io::Cursor; use futures::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use proptest::proptest; #[cfg(test)] use proptest::prelude::{Arbitrary, Just, Strategy, prop_oneof}; #[cfg(test)] use proptest::strategy::BoxedStrategy; use std::fmt; #[allow(clippy::upper_case_acronyms)] #[derive(Clone, Debug, Eq, PartialEq)] pub enum AuthenticationMethod { None, GSSAPI, UsernameAndPassword, ChallengeHandshake, ChallengeResponse, SSL, NDS, MultiAuthenticationFramework, JSONPropertyBlock, PrivateMethod(u8), NoAcceptableMethods, } impl fmt::Display for AuthenticationMethod { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { AuthenticationMethod::None => write!(f, "No authentication"), AuthenticationMethod::GSSAPI => write!(f, "GSS-API"), AuthenticationMethod::UsernameAndPassword => write!(f, "Username and password"), AuthenticationMethod::ChallengeHandshake => write!(f, "Challenge/Handshake"), AuthenticationMethod::ChallengeResponse => write!(f, "Challenge/Response"), AuthenticationMethod::SSL => write!(f, "SSL"), AuthenticationMethod::NDS => write!(f, "NDS Authentication"), AuthenticationMethod::MultiAuthenticationFramework => { write!(f, "Multi-Authentication Framework") } AuthenticationMethod::JSONPropertyBlock => write!(f, "JSON Property Block"), AuthenticationMethod::PrivateMethod(m) => write!(f, "Private Method {:x}", m), AuthenticationMethod::NoAcceptableMethods => write!(f, "No Acceptable Methods"), } } } #[cfg(test)] impl Arbitrary for AuthenticationMethod { type Parameters = (); type Strategy = BoxedStrategy; fn arbitrary_with(_args: Self::Parameters) -> BoxedStrategy { prop_oneof![ Just(AuthenticationMethod::None), Just(AuthenticationMethod::GSSAPI), Just(AuthenticationMethod::UsernameAndPassword), Just(AuthenticationMethod::ChallengeHandshake), Just(AuthenticationMethod::ChallengeResponse), Just(AuthenticationMethod::SSL), Just(AuthenticationMethod::NDS), Just(AuthenticationMethod::MultiAuthenticationFramework), Just(AuthenticationMethod::JSONPropertyBlock), Just(AuthenticationMethod::NoAcceptableMethods), (0x80u8..=0xfe).prop_map(AuthenticationMethod::PrivateMethod), ].boxed() } } impl AuthenticationMethod { pub async fn read( r: &mut R, ) -> Result { let mut byte_buffer = [0u8; 1]; let amount_read = r.read(&mut byte_buffer).await?; if amount_read == 0 { return Err(AuthenticationDeserializationError::NoDataFound.into()); } match byte_buffer[0] { 0 => Ok(AuthenticationMethod::None), 1 => Ok(AuthenticationMethod::GSSAPI), 2 => Ok(AuthenticationMethod::UsernameAndPassword), 3 => Ok(AuthenticationMethod::ChallengeHandshake), 5 => Ok(AuthenticationMethod::ChallengeResponse), 6 => Ok(AuthenticationMethod::SSL), 7 => Ok(AuthenticationMethod::NDS), 8 => Ok(AuthenticationMethod::MultiAuthenticationFramework), 9 => Ok(AuthenticationMethod::JSONPropertyBlock), x if (0x80..=0xfe).contains(&x) => Ok(AuthenticationMethod::PrivateMethod(x)), 0xff => Ok(AuthenticationMethod::NoAcceptableMethods), e => Err(AuthenticationDeserializationError::InvalidAuthenticationByte(e).into()), } } pub async fn write( &self, w: &mut W, ) -> Result<(), SerializationError> { let value = match self { AuthenticationMethod::None => 0, AuthenticationMethod::GSSAPI => 1, AuthenticationMethod::UsernameAndPassword => 2, AuthenticationMethod::ChallengeHandshake => 3, AuthenticationMethod::ChallengeResponse => 5, AuthenticationMethod::SSL => 6, AuthenticationMethod::NDS => 7, AuthenticationMethod::MultiAuthenticationFramework => 8, AuthenticationMethod::JSONPropertyBlock => 9, AuthenticationMethod::PrivateMethod(pm) => *pm, AuthenticationMethod::NoAcceptableMethods => 0xff, }; Ok(w.write_all(&[value]).await?) } } standard_roundtrip!(auth_byte_roundtrips, AuthenticationMethod); #[test] fn bad_byte() { let no_len = vec![42]; let mut cursor = Cursor::new(no_len); let ys = AuthenticationMethod::read(&mut cursor); assert_eq!( Err(DeserializationError::AuthenticationMethodError( AuthenticationDeserializationError::InvalidAuthenticationByte(42) )), task::block_on(ys) ); } #[test] fn display_isnt_empty() { let vals = vec![ AuthenticationMethod::None, AuthenticationMethod::GSSAPI, AuthenticationMethod::UsernameAndPassword, AuthenticationMethod::ChallengeHandshake, AuthenticationMethod::ChallengeResponse, AuthenticationMethod::SSL, AuthenticationMethod::NDS, AuthenticationMethod::MultiAuthenticationFramework, AuthenticationMethod::JSONPropertyBlock, AuthenticationMethod::NoAcceptableMethods, AuthenticationMethod::PrivateMethod(42), ]; for method in vals.iter() { let str = format!("{}", method); assert!(str.is_ascii()); assert!(!str.is_empty()); } }