Macaroon

Struct Macaroon 

Source
pub struct Macaroon<C, M>(/* private fields */)
where
    M: OutputSizeUser;
Expand description

A macaroon token. For an introduction to macaroons, see fly.io’s execellent blog post. Our format isn’t exactly the same as the one in their examples, but it’s very similar.

To generate a new macaroon on the server side, see Macaroon::new.

Implementations§

Source§

impl<C, M> Macaroon<C, M>
where M: Mac + KeySizeUser + KeyInit, C: Serialize,

Source

pub fn attenuate(self, caveat: C) -> Self

Add a caveat to a token. See the documentation of Macaroon::new for an example.

Source

pub fn tail(&self) -> &GenericArray<u8, <M as OutputSizeUser>::OutputSize>

Get the tail of the caveat. Useful e.g. for generating and checking third party caveats.

Source§

impl<C, M> Macaroon<C, M>
where M: Mac + KeySizeUser + KeyInit, C: Caveat + Serialize,

Source

pub fn new<T, K>(id: T, key: K) -> Self
where T: AsRef<str>, K: AsRef<[u8]>,

Create a new macaroon given a key, caveat type, hmac function and token identifier.

To create a macaroon, you need to first define the caveats. To do this, create a type that implements Caveat:

use rustmacaroon::Caveat;
use anyhow::anyhow;
use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize)]
enum MyCaveats {
  Path(String),
  Readonly,
}

struct Request {
  path: String,
  is_write: bool
}

impl Caveat for MyCaveats {
  type Error = anyhow::Error;
  type Context = Request;

  fn verify(&self, ctx: &Self::Context) -> Result<(), Self::Error> {
    match self {
      MyCaveats::Path(path) if path != ctx.path => Err(anyhow!("You can only access path {path}")),
      MyCaveats::Readonly if ctx.is_write => Err(anyhow!("You can only read")),
      _ => Ok(())
    }
  }
}

Note: If you’re only a client and just want to add a caveat but not verify caveats, you do not need to implement the Caveat trait.

When verifying, caveats have access to a user-defined “context”. This is everything the verifier needs to know in order to accurately verify the caveat. For example, in a web server, the context might be the request the user is making.

This caveat type provides the validation logic for your macaroon. Now, you can create a token:

use sha2::Sha256;
use hmac::{Hmac};

let key = b"mysecretkey";

// Note that the token ID ("asdfghjkl" here) should be some (ideally random) byte array or
// string that uniquely identifies this token.
let macaroon: Macaroon<MyCaveats, Hmac<Sha256>> = Macaroon::new(
  "asdfghjkl",
  &key,
);

// Add some caveats:
let macaroon = macaroon
  .attenuate(MyCaveats::Path("/images"))
  .attenuate(MyCaveats::Readonly);

Use verify to check your token’s signature and validate all caveats. verify will only return Ok(()) if the signature is valid and every caveat passes:

// Error: You can only read
assert!(
  macaroon.verify(key, Request {
    path: "/images",
    is_write: true
  }).is_err()
);

// Okay!
assert!(
  macaroon.verify(key, Request {
    path: "/images",
    is_write: false
  }).is_ok()
);
Source

pub fn verify<K>( &self, key: K, ctx: &C::Context, ) -> Result<(), VerificationError<C>>
where K: AsRef<[u8]>,

Check the signature and verify every caveat. See the documentation of Macaroon::new for an example.

Trait Implementations§

Source§

impl<C: Clone, M> Clone for Macaroon<C, M>
where M: OutputSizeUser + Clone,

Source§

fn clone(&self) -> Macaroon<C, M>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<C: Debug, M> Debug for Macaroon<C, M>
where M: OutputSizeUser + Debug,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de, C, M> Deserialize<'de> for Macaroon<C, M>
where M: OutputSizeUser, C: Deserialize<'de>,

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl<C, M> Serialize for Macaroon<C, M>

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more

Auto Trait Implementations§

§

impl<C, M> Freeze for Macaroon<C, M>

§

impl<C, M> RefUnwindSafe for Macaroon<C, M>

§

impl<C, M> Send for Macaroon<C, M>
where C: Send,

§

impl<C, M> Sync for Macaroon<C, M>
where C: Sync,

§

impl<C, M> Unpin for Macaroon<C, M>

§

impl<C, M> UnwindSafe for Macaroon<C, M>

Blanket Implementations§

Source§

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

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

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

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

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

Source§

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

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where 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 for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

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

Source§

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 T
where U: TryFrom<T>,

Source§

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.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,