mod.rs (6793B)
1 //! Using HTTP Authentication, a mutable reference can be generated to mutable content. 2 //! 3 //! The mutable reference is generated from the identity value of the authenticating client, 4 //! together with an identifier, which can be any arbitrary byte value. 5 //! 6 //! Mutable references are generated using [record::ResourceKey](record::ResourceKey) together with 7 //! the [auth::AuthResult](auth::AuthResult) struct. 8 //! 9 //! # How to authenticate 10 //! 11 //! Authentication in `wala` uses the `Authorization` HTTP header with the custom `PUBSIG` scheme 12 //! to determine the identity for which a client wishes to generate a mutable reference. The header 13 //! uses the following format: 14 //! 15 //! ``` ignore, 16 //! Authorization: PUBSIG <scheme>:<identity>:<signature> 17 //! ``` 18 //! 19 //! In the above, `scheme` specifies the authentication module to use (submodules of 20 //! [wala::auth](crate::auth). `identity` is the key against which the `signature` will be 21 //! validated. 22 //! 23 //! There is no access control for which key may store mutable references. All that is required is 24 //! a valid signature. 25 //! 26 //! # Mutable reference 27 //! 28 //! The generated mutable reference is a digest of the `identity` from the authentication, and the 29 //! local part of the `URL`. 30 //! 31 //! For example, given the request: 32 //! 33 //! ``` ignore, 34 //! PUT /xyzzy HTTP/1.1 35 //! Authorization: PUBSIG foo:123:456 36 //! Content-Length: 3 37 //! 38 //! bar 39 //! ``` 40 //! 41 //! If we pretend that `456` is a valid signature for the `123` under the fictional `foo` 42 //! authentication scheme, then the mutable reference generated will be `SHA256(SHA256("xyzzy") | "123")` 43 //! which is `925b268b49dbd2455742082134c72291b5afb2b332c8dcb6d60f06eb8e26b350` 44 //! 45 //! The immutable reference (generated from the content body "bar") will simultaneously be stored, 46 //! under `SHA256("bar")`, which is `fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9`. 47 //! 48 //! Consequtively, for a `wala` server running on `localhost:8000`, the content can be retrieved using 49 //! both of the following `URLs`: 50 //! 51 //! ``` ignore, 52 //! http://localhost:8000/925b268b49dbd2455742082134c72291b5afb2b332c8dcb6d60f06eb8e26b350 53 //! http://localhost:8000/fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9 54 //! ``` 55 //! 56 //! # Overwriting a reference 57 //! 58 //! If a subsequent mutable reference is generated for different content, then the existing mutable 59 //! reference will be overwritten. `wala` provides no feature to write-protect existing mutable 60 //! references. 61 //! 62 //! Of course, for immutable references, the reference for the same content will always be the 63 //! same. 64 //! 65 //! # Authentication schemes 66 //! 67 //! Every submodule of [wala::auth](crate::auth) defines individual authentication schemes. 68 //! 69 //! All schemes, even the [mock](crate::auth::mock) one, must be explicitly be included as a 70 //! feature during build. 71 //! 72 //! For any scheme included during build, a module function `auth_check` will be called to verify 73 //! the data. See [auth::mock::auth_check](crate::auth::mock::auth_check) for an example. 74 //! 75 //! Details on input formats for each scheme is documented within the modules themselves. 76 use std::str::FromStr; 77 use std::error::Error; 78 use std::fmt; 79 80 /// Holds the result of a client authentication request. 81 pub struct AuthResult { 82 /// The resolved identity value. An unsuccessful authentication will result in an empty vector. 83 pub identity: Vec<u8>, 84 /// If true, authentication verification has been attempted and failed. 85 pub error: bool, 86 } 87 88 /// Encapsulates the input provided by the client for authentication. 89 pub struct AuthSpec { 90 /// Authentication method. This determines which authentication submodule will be used. 91 pub method: String, 92 /// The key corrdsponding to the signature. 93 pub key: String, 94 /// Signature over the content of the request. The signature must match against the given key. 95 pub signature: String, 96 } 97 98 impl AuthSpec { 99 /// Resturns true if the `signature` matches the `key` using the given `method` for the 100 /// `auth::AuthSpec`. 101 pub fn valid(&self) -> bool { 102 self.key.len() > 0 103 } 104 } 105 106 impl AuthResult { 107 /// True if authentication has been successfully executed. 108 pub fn active(&self) -> bool { 109 self.identity.len() > 0 110 } 111 112 /// True if no error occurred during verification. Also returns true if no verification has been attmpted. 113 pub fn valid(&self) -> bool { 114 !self.error 115 } 116 } 117 118 impl fmt::Debug for AuthResult { 119 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 120 fmt.write_str(&hex::encode(&self.identity)) 121 } 122 } 123 124 #[derive(Debug)] 125 /// Indicates invalid authentication data from client. 126 pub struct AuthSpecError; 127 128 impl Error for AuthSpecError { 129 fn description(&self) -> &str{ 130 "auth string malformed" 131 } 132 } 133 134 impl fmt::Display for AuthSpecError { 135 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 136 fmt.write_str(self.description()) 137 } 138 } 139 140 141 impl FromStr for AuthSpec { 142 type Err = AuthSpecError; 143 144 fn from_str(s: &str) -> Result<AuthSpec, AuthSpecError> { 145 let mut auth_kv = s.split(" "); 146 match auth_kv.next() { 147 Some(v) => { 148 if v != "PUBSIG" { 149 return Err(AuthSpecError{}); 150 } 151 }, 152 _ => {}, 153 }; 154 155 let ss = match auth_kv.next() { 156 Some(v) => { 157 v 158 }, 159 _ => { 160 return Err(AuthSpecError{}); 161 }, 162 }; 163 164 let mut auth_fields = ss.split(":"); 165 if auth_fields.clone().count() != 3 { 166 return Err(AuthSpecError{}) 167 } 168 let auth_type: String = auth_fields.next().unwrap().to_string(); 169 let auth_key: String = auth_fields.next().unwrap().to_string(); 170 let auth_signature: String = auth_fields.next().unwrap().to_string(); 171 172 let r = AuthSpec{ 173 method: auth_type, 174 key: auth_key, 175 signature: auth_signature, 176 }; 177 Ok(r) 178 } 179 } 180 181 impl fmt::Debug for AuthSpec { 182 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 183 fmt.write_str( 184 format!( 185 "{} key {:?}", 186 self.method, 187 self.key, 188 ).as_str() 189 ) 190 } 191 } 192 193 #[derive(Debug)] 194 /// Error type indicating that an error has occurred during authentication. 195 pub struct AuthError; 196 197 impl fmt::Display for AuthError { 198 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 199 fmt.write_str(self.description()) 200 } 201 } 202 203 impl Error for AuthError { 204 fn description(&self) -> &str{ 205 "auth key signature mismatch" 206 } 207 } 208 209 210 #[cfg(feature = "dev")] 211 pub mod mock; 212 213 #[cfg(feature = "pgpauth")] 214 pub mod pgp_sequoia;