Skip to content

Commit 9cf7f25

Browse files
committed
feat: add support for third-party requests
1 parent e60393e commit 9cf7f25

File tree

2 files changed

+68
-26
lines changed

2 files changed

+68
-26
lines changed

biscuit_test.py

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def choose_key(kid):
217217
elif kid == 1:
218218
return root.public_key
219219
else:
220-
raise Exception("Unknown key identifier")
220+
raise Exception("Unknown key identifier")
221221

222222
biscuit_builder0 = BiscuitBuilder("user({id})", { 'id': "1234" })
223223
token0 = biscuit_builder0.build(other_root.private_key).to_base64()
@@ -386,10 +386,10 @@ def test_biscuit_inspection():
386386
builder.set_root_key_id(42)
387387
token2 = builder.build(kp.private_key).append(BlockBuilder('test(false);'))
388388
print(token2.to_base64())
389-
389+
390390
utoken1 = UnverifiedBiscuit.from_base64(token1.to_base64())
391391
utoken2 = UnverifiedBiscuit.from_base64(token2.to_base64())
392-
392+
393393
assert utoken1.root_key_id() is None
394394
assert utoken2.root_key_id() == 42
395395

@@ -469,8 +469,10 @@ def test_append_third_party():
469469
biscuit = biscuit_builder.build(root_kp.private_key)
470470

471471
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)
472+
new_block = BlockBuilder("external_fact({fact})", { 'fact': "56" })
473+
third_party_request = biscuit.third_party_request()
474+
third_party_block = third_party_request.create_block(third_party_kp.private_key, new_block)
475+
biscuit_with_third_party_block = biscuit.append_third_party(third_party_kp.public_key, third_party_block)
474476

475477
assert repr(biscuit_with_third_party_block.block_external_key(1)) == repr(third_party_kp.public_key)
476478

@@ -480,8 +482,11 @@ def test_read_third_party_facts():
480482
biscuit = biscuit_builder.build(root_kp.private_key)
481483

482484
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+
new_block = BlockBuilder("external_fact({fact})", { 'fact': "56" })
486+
third_party_request = biscuit.third_party_request()
487+
third_party_block = third_party_request.create_block(third_party_kp.private_key, new_block)
488+
biscuit_with_third_party_block = biscuit.append_third_party(third_party_kp.public_key, third_party_block)
489+
485490

486491
authorizer = AuthorizerBuilder("allow if true").build(biscuit_with_third_party_block)
487492
rule = Rule(f"ext_fact($fact) <- external_fact($fact) trusting {third_party_kp.public_key}")

src/lib.rs

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ use ::biscuit_auth::builder::MapKey;
1111
use ::biscuit_auth::datalog::ExternFunc;
1212
use ::biscuit_auth::AuthorizerBuilder;
1313
use ::biscuit_auth::RootKeyProvider;
14+
use ::biscuit_auth::ThirdPartyBlock;
15+
use ::biscuit_auth::ThirdPartyRequest;
1416
use ::biscuit_auth::UnverifiedBiscuit;
1517
use chrono::DateTime;
1618
use chrono::Duration;
@@ -397,36 +399,36 @@ impl PyBiscuit {
397399
.map(PyBiscuit)
398400
}
399401

400-
/// Create a new `Biscuit` by appending a third party attenuation block
402+
/// Create a new `Biscuit` by appending a third-party attenuation block
401403
///
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
404+
/// :param external_key: the public key of the third-party that signed the block.
405+
/// :type external_key: PublicKey
406+
/// :param block: the third party block to append
407+
/// :type block: ThirdPartyBlock
406408
/// :return: the attenuated biscuit
407409
/// :rtype: Biscuit
408410
pub fn append_third_party(
409411
&self,
410-
kp: &PyKeyPair,
411-
block: &PyBlockBuilder,
412+
external_key: &PyPublicKey,
413+
block: &PyThirdPartyBlock,
412414
) -> 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-
424415
self.0
425-
.append_third_party(kp.public_key().0, third_party_block)
416+
.append_third_party(external_key.0, block.0.clone())
426417
.map_err(|e| BiscuitBuildError::new_err(e.to_string()))
427418
.map(PyBiscuit)
428419
}
429420

421+
/// Create a third-party request for generating third-party blocks.
422+
///
423+
/// :return: the third-party request
424+
/// :rtype: ThirdPartyRequest
425+
pub fn third_party_request(&self) -> PyResult<PyThirdPartyRequest> {
426+
self.0
427+
.third_party_request()
428+
.map_err(|e| BiscuitBuildError::new_err(e.to_string()))
429+
.map(|request| PyThirdPartyRequest(Some(request)))
430+
}
431+
430432
/// The revocation ids of the token, encoded as hexadecimal strings
431433
#[getter]
432434
pub fn revocation_ids(&self) -> Vec<String> {
@@ -1063,6 +1065,41 @@ impl PyBlockBuilder {
10631065
}
10641066
}
10651067

1068+
#[pyclass(name = "ThirdPartyRequest")]
1069+
pub struct PyThirdPartyRequest(Option<ThirdPartyRequest>);
1070+
1071+
#[pymethods]
1072+
impl PyThirdPartyRequest {
1073+
/// Create a third-party block
1074+
///
1075+
/// :param private_key: the third-party's private key used to sign the block
1076+
/// :type external_key: PrivateKey
1077+
/// :param block: the block builder to be signed
1078+
/// :type block: BlockBuilder
1079+
/// :return: a signed block that can be appended to a Biscuit
1080+
/// :rtype: ThirdPartyBlock
1081+
///
1082+
/// :note: this method consumes the `ThirdPartyRequest` object.
1083+
pub fn create_block(
1084+
&mut self,
1085+
private_key: &PyPrivateKey,
1086+
block: &PyBlockBuilder,
1087+
) -> PyResult<PyThirdPartyBlock> {
1088+
self.0
1089+
.take()
1090+
.expect("third party request already consumed")
1091+
.create_block(
1092+
&private_key.0,
1093+
block.0.clone().expect("builder already consumed"),
1094+
)
1095+
.map_err(|e| BiscuitBuildError::new_err(e.to_string()))
1096+
.map(PyThirdPartyBlock)
1097+
}
1098+
}
1099+
1100+
#[pyclass(name = "ThirdPartyBlock")]
1101+
pub struct PyThirdPartyBlock(ThirdPartyBlock);
1102+
10661103
/// ed25519 keypair
10671104
#[pyclass(name = "KeyPair")]
10681105
pub struct PyKeyPair(KeyPair);

0 commit comments

Comments
 (0)