Skip to content

Commit e60393e

Browse files
committed
feat: add third-party block support
Add methods to create and inspect third party blocks: - `Biscuit::append_third_party` for creating biscuits with third party blocks - `Biscuit::external_key` for retrieving external keys from blocks - Add unit tests covering third party block functionality
1 parent 309dd82 commit e60393e

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

biscuit_test.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -463,3 +463,28 @@ def test(left, right):
463463
policy = authorizer.build_unauthenticated().authorize()
464464
assert policy == 0
465465

466+
def test_append_third_party():
467+
root_kp = KeyPair()
468+
biscuit_builder = BiscuitBuilder("user({id})", { 'id': "1234" })
469+
biscuit = biscuit_builder.build(root_kp.private_key)
470+
471+
third_party_kp = KeyPair()
472+
third_party_block = BlockBuilder("external_fact({fact})", { 'fact': "56" })
473+
biscuit_with_third_party_block = biscuit.append_third_party(third_party_kp, third_party_block)
474+
475+
assert repr(biscuit_with_third_party_block.block_external_key(1)) == repr(third_party_kp.public_key)
476+
477+
def test_read_third_party_facts():
478+
root_kp = KeyPair()
479+
biscuit_builder = BiscuitBuilder("user({id})", { 'id': "1234" })
480+
biscuit = biscuit_builder.build(root_kp.private_key)
481+
482+
third_party_kp = KeyPair()
483+
third_party_block = BlockBuilder("external_fact({fact})", { 'fact': "56" })
484+
biscuit_with_third_party_block = biscuit.append_third_party(third_party_kp, third_party_block)
485+
486+
authorizer = AuthorizerBuilder("allow if true").build(biscuit_with_third_party_block)
487+
rule = Rule(f"ext_fact($fact) <- external_fact($fact) trusting {third_party_kp.public_key}")
488+
facts = authorizer.query(rule)
489+
490+
assert facts[0].terms[0] == "56"

src/lib.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,36 @@ impl PyBiscuit {
397397
.map(PyBiscuit)
398398
}
399399

400+
/// Create a new `Biscuit` by appending a third party attenuation block
401+
///
402+
/// :param kp: keypair used to sign the block
403+
/// :type kp: KeyPair
404+
/// :param block: a builder for the new block
405+
/// :type block: BlockBuilder
406+
/// :return: the attenuated biscuit
407+
/// :rtype: Biscuit
408+
pub fn append_third_party(
409+
&self,
410+
kp: &PyKeyPair,
411+
block: &PyBlockBuilder,
412+
) -> PyResult<PyBiscuit> {
413+
let third_party_block = self
414+
.0
415+
.third_party_request()
416+
.and_then(|req| {
417+
req.create_block(
418+
&kp.private_key().0,
419+
block.0.clone().expect("builder already consumed"),
420+
)
421+
})
422+
.map_err(|e| BiscuitBuildError::new_err(e.to_string()))?;
423+
424+
self.0
425+
.append_third_party(kp.public_key().0, third_party_block)
426+
.map_err(|e| BiscuitBuildError::new_err(e.to_string()))
427+
.map(PyBiscuit)
428+
}
429+
400430
/// The revocation ids of the token, encoded as hexadecimal strings
401431
#[getter]
402432
pub fn revocation_ids(&self) -> Vec<String> {
@@ -407,6 +437,21 @@ impl PyBiscuit {
407437
.collect()
408438
}
409439

440+
/// Get the external key of a block if it exists
441+
///
442+
/// :param index: the block index
443+
/// :type index: int
444+
/// :return: the public key if it exists
445+
/// :rtype: str | None
446+
pub fn block_external_key(&self, index: usize) -> PyResult<Option<PyPublicKey>> {
447+
let opt_key = self
448+
.0
449+
.block_external_key(index)
450+
.map_err(|e| BiscuitBlockError::new_err(e.to_string()))?;
451+
452+
Ok(opt_key.map(PyPublicKey))
453+
}
454+
410455
fn __repr__(&self) -> String {
411456
self.0.print()
412457
}

0 commit comments

Comments
 (0)