Skip to content

Commit

Permalink
Merge pull request #12 from biscuit-auth/snapshot
Browse files Browse the repository at this point in the history
add support for creating and loading snapshots
  • Loading branch information
divarvel authored Nov 9, 2023
2 parents 39092ca + 068601d commit 34c1aa8
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.2.1

- support for `UnverifiedBiscuit`
- support for snapshots

# 0.2.0

- support for root key id (#5)
Expand Down
50 changes: 50 additions & 0 deletions biscuit_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,56 @@ def test_complete_lifecycle():
assert facts[0].name == "u"
assert facts[0].terms == ["1234"]

def test_snapshot():
private_key = PrivateKey.from_hex("473b5189232f3f597b5c2f3f9b0d5e28b1ee4e7cce67ec6b7fbf5984157a6b97")
root = KeyPair.from_private_key(private_key)

biscuit_builder = BiscuitBuilder("user({id})", { 'id': "1234" })

for right in ["read", "write"]:
biscuit_builder.add_fact(Fact("fact({right})", { 'right': right}))

token = biscuit_builder.build(private_key).append(BlockBuilder('check if user($u)')).to_base64()

parsedToken = Biscuit.from_base64(token, root.public_key)

authorizer = Authorizer("allow if user({id})", { 'id': "1234" })

print(authorizer)
authorizer.add_token(parsedToken)

snapshot = authorizer.base64_snapshot()
parsed = Authorizer.from_base64_snapshot(snapshot)
assert repr(authorizer) == repr(parsed)

policy = parsed.authorize()

assert policy == 0

rule = Rule("u($id) <- user($id), $id == {id}", { 'id': "1234"})
facts = parsed.query(rule)

assert len(facts) == 1
assert facts[0].name == "u"
assert facts[0].terms == ["1234"]

# raw_snapshot() returns a list of bytes, not a `bytes` value directly
return
raw_snapshot = authorizer.raw_snapshot()
parsed_from_raw = Authorizer.from_raw_snapshot(raw_snapshot)
assert repr(authorizer) == repr(parsed_from_raw)

raw_policy = raw_parsed.authorize()

assert raw_policy == 0

rule = Rule("u($id) <- user($id), $id == {id}", { 'id': "1234"})
raw_facts = raw_parsed.query(rule)

assert len(raw_facts) == 1
assert raw_facts[0].name == "u"
assert raw_facts[0].terms == ["1234"]

def test_public_keys():
# Happy path (hex to bytes and back)
public_key_from_hex = PublicKey.from_hex("acdd6d5b53bfee478bf689f8e012fe7988bf755e3d7c5152947abc149bc20189")
Expand Down
6 changes: 6 additions & 0 deletions docs/basic-use.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,9 @@ Query an authorizer
'user'
>>> facts[0].terms
['1234']

Save and load snapshots
-----------------------

>>> snapshot = authorizer.base64_snapshot()
>>> parsed = Authorizer.from_base64_snapshot(snapshot)
47 changes: 47 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,53 @@ impl PyAuthorizer {
.collect())
}

/// Take a snapshot of the authorizer and return it, base64-encoded
///
/// :return: a snapshot as a base64-encoded string
/// :rtype: str
pub fn base64_snapshot(&self) -> PyResult<String> {
self.0
.to_base64_snapshot()
.map_err(|error| BiscuitSerializationError::new_err(error.to_string()))
}

/// Take a snapshot of the authorizer and return it, as raw bytes
///
/// :return: a snapshot as raw bytes
/// :rtype: bytes
pub fn raw_snapshot(&self) -> PyResult<Vec<u8>> {
self.0
.to_raw_snapshot()
.map_err(|error| BiscuitSerializationError::new_err(error.to_string()))
}

/// Build an authorizer from a base64-encoded snapshot
///
/// :param input: base64-encoded snapshot
/// :type input: str
/// :return: the authorizer
/// :rtype: Authorizer
#[classmethod]
pub fn from_base64_snapshot(_: &PyType, input: &str) -> PyResult<Self> {
Ok(PyAuthorizer(
Authorizer::from_base64_snapshot(input)
.map_err(|error| BiscuitValidationError::new_err(error.to_string()))?,
))
}

/// Build an authorizer from a snapshot's raw bytes
///
/// :param input: raw snapshot bytes
/// :type input: bytes
/// :return: the authorizer
/// :rtype: Authorizer
#[classmethod]
pub fn from_raw_snapshot(_: &PyType, input: &[u8]) -> PyResult<Self> {
Ok(PyAuthorizer(Authorizer::from_raw_snapshot(input).map_err(
|error| BiscuitValidationError::new_err(error.to_string()),
)?))
}

fn __repr__(&self) -> String {
self.0.to_string()
}
Expand Down

0 comments on commit 34c1aa8

Please sign in to comment.