1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
//! The `hawk` crate provides support for [Hawk](https://github.com/hueniverse/hawk) //! authentictation. It is a low-level crate, used by higher-level crates to integrate with various //! Rust HTTP libraries. For example `hyper-hawk` integrates Hawk with Hyper. //! //! # Examples //! //! ## Hawk Client //! //! A client can attach a Hawk Authorization header to requests by providing credentials to a //! Request instance, which will generate the header. //! //! ``` //! use hawk::{RequestBuilder, Credentials, Key, SHA256, PayloadHasher}; //! use std::time::{Duration, UNIX_EPOCH}; //! //! fn main() { //! // provide the Hawk id and key //! let credentials = Credentials { //! id: "test-client".to_string(), //! key: Key::new(vec![99u8; 32], SHA256).unwrap(), //! }; //! //! let payload_hash = PayloadHasher::hash("text/plain", SHA256, "request-body").unwrap(); //! //! // provide the details of the request to be authorized //! let request = RequestBuilder::new("POST", "example.com", 80, "/v1/users") //! .hash(&payload_hash[..]) //! .request(); //! //! // Get the resulting header, including the calculated MAC; this involves a random //! // nonce, so the MAC will be different on every request. //! let header = request.make_header(&credentials).unwrap(); //! //! // the header would the be attached to the request //! assert_eq!(header.id.unwrap(), "test-client"); //! assert_eq!(header.mac.unwrap().len(), 32); //! assert_eq!(header.hash.unwrap().len(), 32); //! } //! ``` //! //! A client that wishes to use a bewit (URL parameter) can do so as follows: //! //! ``` //! use hawk::{RequestBuilder, Credentials, Key, SHA256, Bewit}; //! use std::time::Duration; //! use std::borrow::Cow; //! //! let credentials = Credentials { //! id: "me".to_string(), //! key: Key::new("tok", SHA256).unwrap(), //! }; //! //! let client_req = RequestBuilder::new("GET", "mysite.com", 443, "/resource").request(); //! let client_bewit = client_req //! .make_bewit_with_ttl(&credentials, Duration::from_secs(10)) //! .unwrap(); //! let request_path = format!("/resource?bewit={}", client_bewit.to_str()); //! // .. make the request //! ``` //! //! ## Hawk Server //! //! To act as a server, parse the Hawk Authorization header from the request, generate a new //! Request instance, and use the request to validate the header. //! //! ``` //! use hawk::{RequestBuilder, Header, Key, SHA256}; //! use hawk::mac::Mac; //! use std::time::{Duration, UNIX_EPOCH}; //! //! fn main() { //! let mac = Mac::from(vec![7, 22, 226, 240, 84, 78, 49, 75, 115, 144, 70, //! 106, 102, 134, 144, 128, 225, 239, 95, 132, 202, //! 154, 213, 118, 19, 63, 183, 108, 215, 134, 118, 115]); //! // get the header (usually from the received request; constructed directly here) //! let hdr = Header::new(Some("dh37fgj492je"), //! Some(UNIX_EPOCH + Duration::new(1353832234, 0)), //! Some("j4h3g2"), //! Some(mac), //! Some("my-ext-value"), //! Some(vec![1, 2, 3, 4]), //! Some("my-app"), //! Some("my-dlg")).unwrap(); //! //! // build a request object based on what we know //! let hash = vec![1, 2, 3, 4]; //! let request = RequestBuilder::new("GET", "localhost", 443, "/resource") //! .hash(&hash[..]) //! .request(); //! //! let key = Key::new(vec![99u8; 32], SHA256).unwrap(); //! let one_week_in_secs = 7 * 24 * 60 * 60; //! if !request.validate_header(&hdr, &key, Duration::from_secs(5200 * one_week_in_secs)) { //! panic!("header validation failed. Is it 2117 already?"); //! } //! } //! ``` //! //! A server which validates bewits looks like this: //! //! ``` //! use hawk::{RequestBuilder, Credentials, Key, SHA256, Bewit}; //! use std::time::Duration; //! use std::borrow::Cow; //! //! let credentials = Credentials { //! id: "me".to_string(), //! key: Key::new("tok", SHA256).unwrap(), //! }; //! //! // simulate the client generation of a bewit //! let client_req = RequestBuilder::new("GET", "mysite.com", 443, "/resource").request(); //! let client_bewit = client_req //! .make_bewit_with_ttl(&credentials, Duration::from_secs(10)) //! .unwrap(); //! let request_path = format!("/resource?bewit={}", client_bewit.to_str()); //! //! let mut maybe_bewit = None; //! let server_req = RequestBuilder::new("GET", "mysite.com", 443, &request_path) //! .extract_bewit(&mut maybe_bewit).unwrap() //! .request(); //! let bewit = maybe_bewit.unwrap(); //! assert_eq!(bewit.id(), "me"); //! assert!(server_req.validate_bewit(&bewit, &credentials.key)); //! ``` //! //! ## Features //! //! By default, the `use_ring` feature is enabled, which means that this crate will //! use `ring` for all cryptographic operations. //! //! Alternatively, one can configure the crate with the `use_openssl` //! feature to use the `openssl` crate. //! //! If no features are enabled, you must provide a custom implementation of the //! [`hawk::crypto::Cryptographer`] trait to the `set_cryptographer` function, or //! the cryptographic operations will panic. //! //! Attempting to configure both the `use_ring` and `use_openssl` features will //! result in a build error. #[cfg(test)] #[macro_use] extern crate pretty_assertions; mod header; pub use crate::header::Header; mod credentials; pub use crate::credentials::{Credentials, DigestAlgorithm, Key}; mod request; pub use crate::request::{Request, RequestBuilder}; mod response; pub use crate::response::{Response, ResponseBuilder}; mod error; pub use crate::error::*; mod payload; pub use crate::payload::PayloadHasher; mod bewit; pub use crate::bewit::Bewit; pub mod mac; pub mod crypto; pub const SHA256: DigestAlgorithm = DigestAlgorithm::Sha256; pub const SHA384: DigestAlgorithm = DigestAlgorithm::Sha384; pub const SHA512: DigestAlgorithm = DigestAlgorithm::Sha512;