Skip to content

Commit

Permalink
perf: cache DID documents (optional) (#105)
Browse files Browse the repository at this point in the history
* chore: add `alg` to `produce_document` and `sign`

* refactor: use `SecretManager::builder()`, configure DID document cache

* feat: apply `did_document_cache` config to `SecretManager`

* ci: allow manual Docker builds

* ci: add TODO as reminder

* chore: pass config for `es256` into `SecretManager` builder

* chore(deps): bump `did_manager`

* chore(deps): bump `did_manager`

* build(deps): bump did_manager

* fix: fix `Mutex<SecretManager>`

* docs: add key types

* docs: config options for DID document cache

* test: fix verification test setup

* build: move `identity_verification` to workspace level

---------

Co-authored-by: Nander Stabel <[email protected]>
  • Loading branch information
daniel-mader and nanderstabel authored Aug 30, 2024
1 parent e8ebbe8 commit 1823810
Show file tree
Hide file tree
Showing 18 changed files with 133 additions and 80 deletions.
2 changes: 1 addition & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ UNICORE__EVENT_STORE__CONNECTION_STRING="postgresql://demo_user:demo_pass@cqrs-p

UNICORE__SECRET_MANAGER__STRONGHOLD_PATH="agent_secret_manager/tests/res/test.stronghold"
UNICORE__SECRET_MANAGER__STRONGHOLD_PASSWORD="secure_password"
UNICORE__SECRET_MANAGER__ISSUER_KEY_ID="9O66nzWqYYy1LmmiOudOlh2SMIaUWoTS"
UNICORE__SECRET_MANAGER__ISSUER_EDDSA_KEY_ID="9O66nzWqYYy1LmmiOudOlh2SMIaUWoTS"
UNICORE__SECRET_MANAGER__ISSUER_DID="did:iota:rms:0x42ad588322e58b3c07aa39e4948d021ee17ecb5747915e9e1f35f028d7ecaf90"
UNICORE__SECRET_MANAGER__ISSUER_FRAGMENT="bQKQRzaop7CgEvqVq8UlgLGsdF-R-hnLFkKFZqW2VN0"
1 change: 1 addition & 0 deletions .github/workflows/build-push-docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
name: Build and push Docker image

on:
# TODO: `workflow_dispatch` should be removed once manual docker builds from branches are not needed anymore
workflow_dispatch:
push:
branches: ["dev"]
Expand Down
22 changes: 12 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ edition = "2021"
rust-version = "1.76.0"

[workspace.dependencies]
did_manager = { git = "https://[email protected]/impierce/did-manager.git", rev = "2bda2b8" }
did_manager = { git = "https://[email protected]/impierce/did-manager.git", tag = "v1.0.0-beta.2" }
siopv2 = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
oid4vci = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
oid4vc-core = { git = "https://[email protected]/impierce/openid4vc.git", rev = "12fed14" }
Expand All @@ -33,9 +33,10 @@ identity_credential = { version = "1.3", default-features = false, features = [
"validator",
"credential",
"presentation",
"domain-linkage"
"domain-linkage",
] }
identity_iota = { version = "1.3" }
identity_verification = { version = "1.3", default-features = false }
jsonwebtoken = "9.3"
lazy_static = "1.4"
rstest = "0.19"
Expand Down
2 changes: 1 addition & 1 deletion agent_api_rest/src/verification/relying_party/redirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pub mod tests {

let provider_manager = ProviderManager::new(
Arc::new(Subject {
secret_manager: secret_manager().await,
secret_manager: Arc::new(tokio::sync::Mutex::new(secret_manager().await)),
}),
vec!["did:key"],
vec![Algorithm::EdDSA],
Expand Down
42 changes: 23 additions & 19 deletions agent_application/CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,36 @@ All environment variables need to be prefixed with `UNICORE__` to prevent confli

## General

| Name | Description | Default value | Accepted values |
| ------------------------------------------------------- | ----------------------------------------------------------------- | ------------- | ---------------------------------------- |
| `UNICORE__LOG_FORMAT` | The format of the log output. | `json` | `json`, `text` |
| `UNICORE__EVENT_STORE__TYPE` | The type of event store to use. | - | `in_memory`, `postgres` |
| `UNICORE__EVENT_STORE__CONNECTION_STRING` | The connection string for the event store database. | - | `postgresql://<user>:<pass>@<host>/<db>` |
| `UNICORE__URL` | The base URL UniCore runs on. | - | `https://my-domain.example.org` |
| `UNICORE__BASE_PATH` | A base path can be set if needed. | - | string |
| `UNICORE__CORS_ENABLED` | Enable CORS (permissive). Only required for browser-based access. | `false` | boolean |
| `UNICORE__DID_METHODS__DID_WEB__ENABLED` | Create and host a `did:web` DID document. | `false` | boolean |
| `UNICORE__SIGNING_ALGORITHMS_SUPPORTED__EDDSA__ENABLED` | Toggles the algorithm allowed for cryptographic operations. | `true` | boolean |
| `UNICORE__DOMAIN_LINKAGE_ENABLED` | Enable domain linkage (only works with `did:web`). | - | boolean |
| `UNICORE__EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS` | The timeout for external server responses (in milliseconds). | `1000` | integer |
| Name | Description | Default value | Accepted values |
| ------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ------------- | ---------------------------------------- |
| `UNICORE__LOG_FORMAT` | The format of the log output. | `json` | `json`, `text` |
| `UNICORE__EVENT_STORE__TYPE` | The type of event store to use. | - | `in_memory`, `postgres` |
| `UNICORE__EVENT_STORE__CONNECTION_STRING` | The connection string for the event store database. | - | `postgresql://<user>:<pass>@<host>/<db>` |
| `UNICORE__URL` | The base URL UniCore runs on. | - | `https://my-domain.example.org` |
| `UNICORE__BASE_PATH` | A base path can be set if needed. | - | string |
| `UNICORE__CORS_ENABLED` | Enable CORS (permissive). Only required for browser-based access. | `false` | boolean |
| `UNICORE__DID_METHODS__DID_WEB__ENABLED` | Create and host a `did:web` DID document. | `false` | boolean |
| `UNICORE__SIGNING_ALGORITHMS_SUPPORTED__EDDSA__ENABLED` | Toggles the algorithm allowed for cryptographic operations. | `true` | boolean |
| `UNICORE__DOMAIN_LINKAGE_ENABLED` | Enable domain linkage (only works with `did:web`). | - | boolean |
| `UNICORE__EXTERNAL_SERVER_RESPONSE_TIMEOUT_MS` | The timeout for external server responses (in milliseconds). | `1000` | integer |
| `UNICORE__DID_DOCUMENT_CACHE__ENABLED` | Enables a simple in-memory cache for DID documents. | `false` | boolean |
| `UNICORE__DID_DOCUMENT_CACHE__TTL` | Sets the expiry for cache entries in milliseconds. | `5000` | integer |
| `UNICORE__DID_DOCUMENT_CACHE__INCLUDE` | An optional list of DIDs to include in the cache. If not specified, all DIDs will be cached. | - | - |

<!-- TODO: How to document all other DID methods? -->
<!-- TODO: VP_FORMATS -->
<!-- TODO: EVENT_PUBLISHERS: even configured through env vars? -->

## Secret Management

| Name | Description | Default value | Accepted values |
| ---------------------------------------------- | -------------------------------------- | ------------- | ----------------------------- |
| `UNICORE__SECRET_MANAGER__STRONGHOLD_PATH` | The path to the stronghold file. | - | `/var/lib/unicore/stronghold` |
| `UNICORE__SECRET_MANAGER__STRONGHOLD_PASSWORD` | The password to unlock the stronghold. | - | - |
| `UNICORE__SECRET_MANAGER__ISSUER_KEY_ID` | The key ID to be used. | - | - |
| `UNICORE__SECRET_MANAGER__ISSUER_DID` | The DID of the issuer. | - | - |
| `UNICORE__SECRET_MANAGER__ISSUER_FRAGMENT` | The fragment to be used. | - | - |
| Name | Description | Default value | Accepted values |
| ---------------------------------------------- | ------------------------------------------------- | ------------- | ----------------------------- |
| `UNICORE__SECRET_MANAGER__STRONGHOLD_PATH` | The path to the stronghold file. | - | `/var/lib/unicore/stronghold` |
| `UNICORE__SECRET_MANAGER__STRONGHOLD_PASSWORD` | The password to unlock the stronghold. | - | - |
| `UNICORE__SECRET_MANAGER__ISSUER_EDDSA_KEY_ID` | The key ID of the EDDSA (Ed25519) key to be used. | - | - |
| `UNICORE__SECRET_MANAGER__ISSUER_ES256_KEY_ID` | The key ID of the ES256 key to be used. | - | - |
| `UNICORE__SECRET_MANAGER__ISSUER_DID` | The DID of the issuer. | - | - |
| `UNICORE__SECRET_MANAGER__ISSUER_FRAGMENT` | The fragment to be used. | - | - |

## Look and Feel

Expand Down
1 change: 1 addition & 0 deletions agent_application/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ agent_verification = { path = "../agent_verification" }
axum.workspace = true
did_manager.workspace = true
identity_document = { version = "1.3" }
identity_verification.workspace = true
serde_json.workspace = true
tokio.workspace = true
tower-http.workspace = true
Expand Down
8 changes: 6 additions & 2 deletions agent_application/example.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ domain_linkage_enabled: false

signing_algorithms_supported:
eddsa:
enabled: true
preferred: true
es256:
enabled: true

# TODO: required to be stated explicitly?
Expand Down Expand Up @@ -68,10 +70,12 @@ credential_configurations:
uri: https://www.impierce.com/external/impierce-logo.png
alt_text: UniCore Logo

did_document_cache:
enabled: false
ttl: 5000

# Key configuration (temporary)
secret_manager:
# Set this to `true` in order to generate a new stronghold file if it does not exist yet.
generate_stronghold: true
stronghold_path: "/tmp/local.stronghold"
# stronghold_password: "" <== Should be injected through the env variable `UNICORE__SECRET_MANAGER__STRONGHOLD_PASSWORD`
# stronghold_password_file: ""
Expand Down
11 changes: 7 additions & 4 deletions agent_application/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ async fn main() -> io::Result<()> {
}

let subject = Arc::new(Subject {
secret_manager: secret_manager().await,
secret_manager: Arc::new(tokio::sync::Mutex::new(secret_manager().await)),
});

let issuance_services = Arc::new(IssuanceServices::new(subject.clone()));
Expand Down Expand Up @@ -81,9 +81,10 @@ async fn main() -> io::Result<()> {
.enabled;

let did_document = if enable_did_web {
let mut secret_manager = subject.secret_manager.lock().await;

Some(
subject
.secret_manager
secret_manager
.produce_document(
did_manager::DidMethod::Web,
Some(did_manager::MethodSpecificParameters::Web { origin: url.origin() }),
Expand All @@ -99,13 +100,15 @@ async fn main() -> io::Result<()> {
};
// Domain Linkage
let did_configuration_resource = if config().domain_linkage_enabled {
let secret_manager = subject.secret_manager.lock().await;

Some(
create_did_configuration_resource(
url.clone(),
did_document
.clone()
.expect("No DID document found to create a DID Configuration Resource for"),
&subject.secret_manager,
&secret_manager,
)
.await
.expect("Failed to create DID Configuration Resource"),
Expand Down
2 changes: 1 addition & 1 deletion agent_issuance/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ oid4vc-manager.workspace = true
serde.workspace = true
serde_json.workspace = true
thiserror.workspace = true
tokio.workspace = true
tracing.workspace = true
url.workspace = true
uuid.workspace = true
Expand All @@ -36,7 +37,6 @@ agent_shared = { path = "../agent_shared", features = ["test_utils"] }
did_manager.workspace = true
lazy_static.workspace = true
serial_test = "3.0"
tokio.workspace = true
tracing-test.workspace = true
async-std = { version = "1.5", features = ["attributes", "tokio1"] }
rstest.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion agent_issuance/src/services.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub mod test_utils {
pub fn test_issuance_services() -> Arc<IssuanceServices> {
Arc::new(IssuanceServices::new(Arc::new(futures::executor::block_on(async {
Subject {
secret_manager: secret_manager().await,
secret_manager: Arc::new(tokio::sync::Mutex::new(secret_manager().await)),
}
}))))
}
Expand Down
Loading

0 comments on commit 1823810

Please sign in to comment.