3 unstable releases
0.2.0 | Dec 8, 2022 |
---|---|
0.1.2 | Nov 29, 2022 |
0.1.1 | Nov 29, 2022 |
#2535 in Cryptography
29KB
301 lines
Http Signature Normalization Actix-Web Extractor
Experimental Extractor for request signatures
Http Signature Normalization is a minimal-dependency crate for producing HTTP Signatures with user-provided signing and verification. The API is simple; there's a series of steps for creation and verification with types that ensure reasonable usage. This library takes a different approach from the other implementation, which prefers Middlewares.
Usage
This crate provides extensions the ClientRequest type from Actix Web, and provides middlewares for verifying HTTP Signatures, and optionally, Digest headers
First, add this crate to your dependencies
actix-rt = "2.7.0"
actix-web = "4.0.0"
thiserror = "1"
http-signature-normalization-actix-extractor = "0.1.0"
sha2 = "0.10"
Then, use it in your client
use actix_web::{http::StatusCode, web, App, HttpRequest, HttpResponse, HttpServer, ResponseError};
use http_signature_normalization_actix_extractor::{
Algorithm, Config, ConfigGenerator, DeprecatedAlgorithm, Signed, VerifyKey,
};
use sha2::Sha256;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().route("/", web::post().to(protected)))
.bind("127.0.0.1:8010")?
.run()
.await
}
async fn protected(signed_request: Signed<String, Cfg, Sha256, Key>) -> &'static str {
let (value, signature) = signed_request.into_parts();
println!("{}", value);
println!("{:#?}", signature);
"hewwo, mr obama"
}
pub struct Cfg;
#[derive(Debug)]
pub struct Key;
#[derive(Debug, thiserror::Error)]
pub enum VerifyError {
#[error("Unsupported algorithm")]
Algorithm,
#[error("Couldn't decode signature")]
Decode,
#[error("Invalid key")]
Key,
}
impl ConfigGenerator for Cfg {
fn config() -> Config {
Config::new().require_header("accept")
}
}
#[async_trait::async_trait(?Send)]
impl VerifyKey for Key {
type Error = VerifyError;
async fn init(
_: &HttpRequest,
key_id: &str,
algorithm: Option<&Algorithm>,
) -> Result<Self, Self::Error> {
match algorithm {
Some(Algorithm::Hs2019 | Algorithm::Deprecated(DeprecatedAlgorithm::RsaSha256)) => (),
_ => return Err(VerifyError::Algorithm),
};
if key_id != "my-key-id" {
return Err(VerifyError::Key);
}
Ok(Key)
}
fn verify(&mut self, signature: &str, signing_string: &str) -> Result<bool, Self::Error> {
use subtle::ConstantTimeEq;
let decoded = base64::decode(&signature).map_err(|_| VerifyError::Decode)?;
Ok(decoded.ct_eq(signing_string.as_bytes()).into())
}
}
impl ResponseError for VerifyError {
fn status_code(&self) -> StatusCode {
StatusCode::BAD_REQUEST
}
fn error_response(&self) -> HttpResponse {
HttpResponse::BadRequest().finish()
}
}
Contributing
Feel free to open issues for anything you find an issue with. Please note that any contributed code will be licensed under the AGPLv3.
License
Copyright © 2022 Riley Trautman
HTTP Signature Normalization Actix Extractor is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
HTTP Signature Normalization Actix Extractor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. This file is part of HTTP Signature Normalization Actix Extractor.
You should have received a copy of the GNU General Public License along with HTTP Signature Normalization Actix Extractor. If not, see http://www.gnu.org/licenses/.
Dependencies
~20–32MB
~533K SLoC