diff --git a/README.md b/README.md index 356ebef..6e39784 100644 --- a/README.md +++ b/README.md @@ -40,4 +40,4 @@ $ source .env/bin/activate $ pip install -r requirements-dev.txt ``` -With that, you should be able to run `maturin develop` to build and install the extension. You can then `import biscuit_auth` in a Python shell to play around, or run `pytest` to run the Python tests. \ No newline at end of file +With that, you should be able to run `maturin develop` to build and install the extension. You can then `import biscuit_auth` in a Python shell to play around, or run `pytest` to run the Python tests. diff --git a/biscuit_test.py b/biscuit_test.py index 8d49186..f436141 100644 --- a/biscuit_test.py +++ b/biscuit_test.py @@ -463,3 +463,14 @@ def test(left, right): policy = authorizer.build_unauthenticated().authorize() assert policy == 0 +def test_append_third_party_block(): + root_kp = KeyPair() + external_kp = KeyPair() + + builder = BiscuitBuilder("user({user});", {'user': "123"}) + biscuit = builder.build(root_kp.private_key) + + third_party_block = BlockBuilder("external_fact({fact});", {'fact': "456"}) + new_biscuit = biscuit.append_third_party_block(external_kp, third_party_block) + + assert str(new_biscuit.block_external_key(1)) == str(external_kp.public_key) diff --git a/src/lib.rs b/src/lib.rs index cf049dd..bcefbd7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,6 +83,13 @@ impl From for builder::Algorithm { } } +impl BiscuitBuildError { + /// Helper function to build `BiscuitBuildError` from other errors. + pub fn from_err(error: impl ToString) -> PyErr { + Self::new_err(error.to_string()) + } +} + struct PyKeyProvider { py_value: PyObject, } @@ -397,6 +404,36 @@ impl PyBiscuit { .map(PyBiscuit) } + /// Create a new `Biscuit` by appending a third party attenuation block + /// + /// :param kp: keypair used to sign the block + /// :type kp: KeyPair + /// :param block: a builder for the new block + /// :type block: BlockBuilder + /// :return: the attenuated biscuit + /// :rtype: Biscuit + pub fn append_third_party_block( + &self, + kp: &PyKeyPair, + block: &PyBlockBuilder, + ) -> PyResult { + let third_party_block = self + .0 + .third_party_request() + .and_then(|req| { + req.create_block( + &kp.private_key().0, + block.0.clone().expect("builder already consumed"), + ) + }) + .map_err(BiscuitBuildError::from_err)?; + + self.0 + .append_third_party(kp.public_key().0, third_party_block) + .map_err(BiscuitBuildError::from_err) + .map(PyBiscuit) + } + /// The revocation ids of the token, encoded as hexadecimal strings #[getter] pub fn revocation_ids(&self) -> Vec { @@ -407,6 +444,21 @@ impl PyBiscuit { .collect() } + /// Get the external key of a block if it exists + /// + /// :param index: the block index + /// :type index: int + /// :return: the public key if it exists + /// :rtype: str | None + pub fn block_external_key(&self, index: usize) -> PyResult> { + let opt_key = self + .0 + .block_external_key(index) + .map_err(|e| BiscuitBlockError::new_err(e.to_string()))?; + + Ok(opt_key.map(PyPublicKey)) + } + fn __repr__(&self) -> String { self.0.print() }