wala-rust

Content-adressed HTTP file server
Info | Log | Files | Refs | README | LICENSE

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;