pub struct BiscuitMiddleware { /* private fields */ }
Expand description

On incoming request if there is a valid bearer token authorization header:

  • deserialize it using the provided public key
  • inject a biscuit as extension in handler

else return an 401 Unauthorized (missing or invalid header) or 403 Forbidden (deserialization error) with an error message in the body

Example

use actix_web::{get, web, App, HttpResponse, HttpServer};
use biscuit_actix_middleware::BiscuitMiddleware;
use biscuit_auth::{macros::*, Biscuit, KeyPair};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let root = KeyPair::new();
    let public_key = root.public();

    HttpServer::new(move || {
        App::new()
            .wrap(BiscuitMiddleware::new(public_key))
            .service(hello)     
    })
    .bind(("127.0.0.1", 8080))?;
    // this code is ran during tests so we can't start a long-running server
    // uncomment the two lines below and remove the `Ok(())`.
    //.run()
    //.await
    Ok(())
}
   
#[get("/hello")]
async fn hello(biscuit: web::ReqData<Biscuit>) -> HttpResponse {
    println!("{}", biscuit.print());
    let mut authorizer = authorizer!(
        r#"
      allow if role("admin");
    "#
    );

    authorizer.add_token(&biscuit).unwrap();
    if authorizer.authorize().is_err() {
        return HttpResponse::Forbidden().finish();
    }

    HttpResponse::Ok().body("Hello admin!")
}

Implementations§

source§

impl BiscuitMiddleware

source

pub fn new<KP>(public_key: KP) -> BiscuitMiddlewarewhere KP: RootKeyProvider + 'static,

Instantiate a new middleware.

RootKeyProvider is a biscuit-auth trait used to delegate PublicKey selection/rotation implementation.

If either selection or rotation are not required, you can pass a PublicKey (it already implements RootKeyProvider in biscuit-auth lib).

Examples

Selection and rotation are not required

use biscuit_actix_middleware::BiscuitMiddleware;
use biscuit_auth::KeyPair;

BiscuitMiddleware::new(KeyPair::new().public());

Setup a simple KeyProvider that only accepts tokens with a root_key_id corresponding to an index of an existing PublicKey

use biscuit_auth::{error::Format, Biscuit, KeyPair, PublicKey, RootKeyProvider};
use biscuit_actix_middleware::BiscuitMiddleware;

struct KeyProvider {
    roots: Vec<KeyPair>,
}

impl KeyProvider {
    fn new() -> Self {
        let mut new = KeyProvider { roots: vec![] };

        for _ in 1..11 {
            new.roots.push(KeyPair::new());
        }

        new
    }
}

impl RootKeyProvider for KeyProvider {
    fn choose(&self, key_id: Option<u32>) -> Result<PublicKey, Format> {
        Ok(self
            .roots
            .get(key_id.ok_or(Format::UnknownPublicKey)? as usize)
            .ok_or(Format::UnknownPublicKey)?
            .public())
    }
}

let key_provider = KeyProvider::new();

let middleware = BiscuitMiddleware::new(key_provider);
source

pub fn error_handler( self, handler: fn(_: MiddlewareError, _: &ServiceRequest) -> HttpResponse ) -> Self

Add a custom error handler to customize HttpResponse according to MiddlewareError and ServiceRequest params

Example
use biscuit_actix_middleware::{BiscuitMiddleware, error::*};

let root = KeyPair::new();
let public_key = root.public();
     
BiscuitMiddleware::new(public_key)
    .error_handler(
        |err: MiddlewareError, _: &ServiceRequest| -> HttpResponse {
            AppError::BiscuitToken.error_response()
        });
     
#[derive(Debug, Display)]
enum AppError {
    BiscuitToken,
}

impl ResponseError for AppError {
    fn error_response(&self) -> HttpResponse {
        match self {
            AppError::BiscuitToken => HttpResponse::Unauthorized().finish(),
        }
    }
}    

use actix_web::{error::ResponseError, dev::ServiceRequest, HttpResponse};
use derive_more::Display;
use biscuit_auth::KeyPair;
source

pub fn token_extractor( self, extractor: fn(_: &ServiceRequest) -> Option<Vec<u8>> ) -> Self

Add a custom token extractor to an existing middleware

Example
use biscuit_actix_middleware::BiscuitMiddleware;
use actix_web::{dev::ServiceRequest};
use biscuit_auth::KeyPair;

let root = KeyPair::new();
let public_key = root.public();
     
BiscuitMiddleware::new(public_key)
    .token_extractor(|req: &ServiceRequest| {
        Some(
            req.headers()
                .get("biscuit")?
                .to_str()
                .ok()?
                .to_string()
                .into_bytes(),
        )
    });
source

pub fn default_token_extractor(req: &ServiceRequest) -> Option<Vec<u8>>

Middleware default token extraction logic. It can be use as a base of a custom token extractor to add pre/post processing to token extraction.

Trait Implementations§

source§

impl<S, B> Transform<S, ServiceRequest> for BiscuitMiddlewarewhere S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>, S::Future: 'static, B: 'static,

§

type Response = ServiceResponse<EitherBody<B, BoxBody>>

Responses produced by the service.
§

type Error = Error

Errors produced by the service.
§

type InitError = ()

Errors produced while building a transform service.
§

type Transform = ImplBiscuitMiddleware<S>

The TransformService value created by this factory
§

type Future = Ready<Result<<BiscuitMiddleware as Transform<S, ServiceRequest>>::Transform, <BiscuitMiddleware as Transform<S, ServiceRequest>>::InitError>>

The future response value.
source§

fn new_transform(&self, service: S) -> Self::Future

Creates and returns a new Transform component, asynchronously

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for Twhere U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> Same<T> for T

§

type Output = T

Should always be Self
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for Twhere V: MultiLane<T>,

§

fn vzip(self) -> V

source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more