diff --git a/examples/edc-example/README.md b/examples/edc-example/README.md index a3b0006a..aa283c5c 100644 --- a/examples/edc-example/README.md +++ b/examples/edc-example/README.md @@ -1,7 +1,8 @@ # TKE-EDC Example -This example uses EDC-IDS Connectors for communication between two Knowledge Engine Runtimes (KERs). -All messages that are sent contain an authentication code. -If a message is received, the authentication code is validated unless it is a meta Knowledge Interaction. +This example focuses on the Eclipse Dataspace Components (EDC) integration of the Knowledge Engine. +If you just want to learn about the functioning of the Knowledge Engine and do not know about EDC, this example is not the right place to start. \ +In this text we assume basic knowledge about EDC (The [adopters manual](https://eclipse-edc.github.io/documentation/for-adopters/) is a good place to start) and International Data Spaces (IDS, see [here](https://internationaldataspaces.org/)). \ +If you are already familiar with the Knowledge Engine you can skip the next part. ## Introduction to the Knowledge Engine The Knowledge Engine is a system for seamlessly connecting data sources. @@ -27,20 +28,18 @@ After they have been registered, they can be executed. For more information on the Knowledge Engine, check out the [documentation](https://docs.knowledge-engine.eu/). -## About the Integration with EDC-IDS +## About the Integration with EDC The current integration between the Knowledge Engine and EDC-IDS focuses on the authentication of messages. All messages that are sent contain an authentication code. -This authentication code is validated whenever the message is received. -This way we can be sure that the message was sent by the correct party, thus it establishes trust within the network. +The TKE-EDC integration is aimed at providing and validating these authentication codes. +The used components of EDC implement the Data Space Protocol (DSP) and the Decentralized Claims Protocol (DCP), an overlay of DSP. +These protocols are used to establish security and trust within the network based on the decentralized identity model (see [here](https://eclipse-edc.github.io/documentation/for-adopters/identity-hub/)). -We currently use the standard EDC-IDS Connector without any modifications. -We use the Connector to establish and check the identity of all parties in the network. -The communication between KERs is still direct, meaning that messages that are sent do not go through the Connector. +! IMPORTANT ! The EDC integration is currently still under development. Expect bugs, frequent changes and updates. + +We currently use the Control Plane, Data Plane and Identity Hub components of EDC, which are all heavily customizable. +The TKE-EDC integration is made specifically for the extended EDC components developed within TNO, that are also publicly available, see the Docker Compose file in this folder. -The authentication tokens are valid for a limited amount of time. -You can set the duration of validity of authentication tokens in the EDC Connector properties file (`edc.transfer.proxy.token.validity.seconds`). -While tokens can expire in the current implementation, there is not yet a mechanism to renew them. -That's why we currently advise you to set it to a high number. ## Running the TKE-EDC example @@ -48,43 +47,28 @@ This example uses 3 knowledge bases as depicted below. ![Picture with 3 knowledge bases. Each knowledge base uses a Smart Connector to communicate with the other knowledge bases.](./illustration-example-situation.png) -One knowledge base asks for information and the other two provide an answer to the question. +One knowledge base (Alice) asks for information and the other two (Bob , Carol) provide an answer to the question. ### Executing the example -Execute the following steps to run the example: -1. In this project, execute a `mvn clean install`. -2. In the `knowledge-directory` directory in this project, execute `docker build . -t testkd:1.3.3-SNAPSHOT`. -3. In the `smart-connector-rest-dist` directory in this project, execute `docker build . -t testsc:1.3.3-SNAPSHOT`. -4. In the `examples/edc-example` directory in this project, execute `docker compose build`. -5. In the `examples/edc-example` directory in this project, execute `docker compose up -d tke-edc-one tke-edc-two tke-edc-three`. This starts three EDC-IDS Connectors. -6. Wait around 10 seconds to give the EDC Connectors time to finish setting up. Then, execute `docker compose up -d` to start three KERs, three linked Knowledge Bases and a Knowledge Directory. - -You can inspect the logs with `docker compose logs -f`. +Example can be executed using Docker, follow these steps: +1. In the `examples/edc-example` directory in this project, execute `docker compose build`. +2. Several containers are dependent on the initialization of others, but there is currently no method implement to start these in the correct order. In the `examples/edc-example` directory in this project, execute + +``` +docker compose up -d bob-identity-hub bob-control-plane alice-identity-hub alice-control-plane authority-identity-hub registration-service nginx-proxy knowledge-directory alice-http-data-plane bob-http-data-plane carol-identity-hub carol-control-plane carol-http-data-plane +``` + +This starts three EDC-IDS Connectors. +3. Wait around 20 seconds to give the EDC Connectors time to finish setting up. Then, execute + +``` +docker compose up alice-ker bob-ker alice-kb bob-kb carol-ker carol-kb knowledge-directory -d +``` + +to start three KERs, three linked Knowledge Bases and a Knowledge Directory. + +You can inspect the logs of the containers using `docker compose logs -f {component-name}`. After a moment (+-30 seconds), the logs will stabilise when the connectors have finished initiating the various data flows. You can then see that one KER (`runtime-1`) asks for information, a second KER (`runtime-2`) answers with `http://example.org/Math, http://example.org/Science` and the third (`runtime-3`) answers with `http://example.org/Magazines, http://example.org/Books`. To stop the example, execute `docker compose down`. - -## Adding another participant to the network -For each additional KER with an EDC-IDS Connector, we need the following files in the `examples/edc-example` directory: -- `connector/configuration/ker-configuration.properties` contains settings for the EDC-IDS Connector -- `connector/configuration/ker-vault.properties` contains a public key - -The `docker-compose.yml` in `examples/edc-example/` should also be modified to include: -- An additional KER (currently named `runtime-1`, `runtime-2`, ...) - - The `image` setting refers to the image build in the execution steps of this document. - - The `depends_on` setting refers to the Docker component for the EDC-IDS Connector - - The `KE_RUNTIME_EXPOSED_URL` is a unique URL for the new KER. - - The EDC related environment variables are: - - `KE_RUNTIME_USE_EDC` -> Turn EDC functionality on or off. - - `KE_EDC_PROTOCOL_URL` -> URL of the protocal API of the associated EDC-IDS connector. - - `KE_EDC_MANAGEMENT_URL` -> URL of the management API of the associated EDC-IDS connector. - - `KE_EDC_DATAPLANE_CONTROL_URL` -> URL of the dataplane control API of the associated EDC-IDS connector. - - `KE_EDC_DATAPLANE_PUBLIC_URL` -> URL of the dataplane public API of the associated EDC-IDS connector. - - `KE_EDC_TOKEN_VALIDATION_ENDPOINT` -> URL of the token validation endpoint of the associated EDC-IDS connector. -- An additional EDC-IDS Connector (currently named `tke-edc-one`, `tke-edc-two`, ...) - - Requires 4 ports to be forwarded - - The `command` used to start this connector refers to the previously mentioned configuration files and thus the names of those files should be modified if you copy the command from another EDC-IDS Connector. - - The `hostname` is used in the properties files to refer to this entity -- An additional knowledge base (`kb1`, `kb2`, ...) - - The `KE_URL` refers to the `KE_RUNTIME_EXPOSED_URL` of the KER Docker component (`runtime-1`, `runtime-2`, ...) \ No newline at end of file diff --git a/examples/edc-example/connector/certs/cert.pem b/examples/edc-example/connector/certs/cert.pem deleted file mode 100644 index c7dc26fa..00000000 --- a/examples/edc-example/connector/certs/cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDazCCAlOgAwIBAgIUZ3/sZXYzW4PjmOXKrZn6WBmUJ+4wDQYJKoZIhvcNAQEL -BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAyMjMxNTA2MDNaFw0zMjAy -MjExNTA2MDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDBl6XaJnXTL+6DWip3aBhU+MzmY4d1V9hbTm1tiZ3g -E0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7EddidN0ITHB9cQNdAfdUJ5njmsGS -PbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7DHacZT/+OztBH1RwkG2ymM94Hf8H -I6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvjX5qASakBtXISKIsOU84N0/2HDN3W -EGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga775bPXN3M+JTSaIKE7dZbKzvx0Zi0 -h5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2YmnneYoVAgMBAAGjUzBRMB0GA1Ud -DgQWBBTvK1wVERwjni4B2vdH7KtEJeVWFzAfBgNVHSMEGDAWgBTvK1wVERwjni4B -2vdH7KtEJeVWFzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBn -QHiPA7OBYukHd9gS7c0HXE+fsWcS3GZeLqcHfQQnV3pte1vTmu9//IVW71wNCJ1/ -rySRyODPQoPehxEcyHwupNZSzXK//nPlTdSgjMfFxscvt1YndyQLQYCfyOJMixAe -Aqrb14GTFHUUrdor0PyElhkULjkOXUrSIsdBrfWrwLTkelE8NK3tb5ZG8KPzD9Jy -+NwEPPr9d+iHkUkM7EFWw/cl56wka9ryBb97RI7DqbO6/j6OXHMk4GByxKv7DSIR -IvF9/Dw20qytajtaHV0pluFcOBuFc0NfiDvCaQlbTsfjzbc6UmZWbOi9YOJl3VQ/ -g3h+15GuzbsSzOCOEYOT ------END CERTIFICATE----- diff --git a/examples/edc-example/connector/certs/cert.pfx b/examples/edc-example/connector/certs/cert.pfx deleted file mode 100644 index 7ac9c73e..00000000 Binary files a/examples/edc-example/connector/certs/cert.pfx and /dev/null differ diff --git a/examples/edc-example/connector/certs/key.pem b/examples/edc-example/connector/certs/key.pem deleted file mode 100644 index e72229e8..00000000 --- a/examples/edc-example/connector/certs/key.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDBl6XaJnXTL+6D -Wip3aBhU+MzmY4d1V9hbTm1tiZ3gE0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7 -EddidN0ITHB9cQNdAfdUJ5njmsGSPbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7 -DHacZT/+OztBH1RwkG2ymM94Hf8HI6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvj -X5qASakBtXISKIsOU84N0/2HDN3WEGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga7 -75bPXN3M+JTSaIKE7dZbKzvx0Zi0h5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2 -YmnneYoVAgMBAAECggEBAJHXiN6bctAyn+DcoHlsNkhtVw+Jk5bXIutGXjHTJtiU -K//siAGC78IZMyXmi0KndPVCdBwShROVW8xWWIiXuZxy2Zvm872xqX4Ah3JsN7/Q -NrXdVBUDo38zwIGkxqIfIz9crZ4An+J/eq5zaTfRHzCLtswMqjRS2hFeBY5cKrBY -4bkSDGTP/c5cP7xS/UwaiTR2Ptd41f4zTyd4l5rl30TYHpazQNlbdxcOV4jh2Rnp -E0+cFEvEfeagVq7RmfBScKG5pk4qcRG0q2QHMyK5y00hdYvhdRjSgN7xIDkeO5B8 -s8/tSLU78nCl2gA9IKxTXYLitpISwZ81Q04mEAKRRtECgYEA+6lKnhn//aXerkLo -ZOLOjWQZhh005jHdNxX7DZqLpTrrfxc8v15KWUkAK1H0QHqYvfPrbbsBV1MY1xXt -sKmkeu/k8fJQzCIvFN4K2J5W5kMfq9PSw5d3XPeDaQuXUVaxBVp0gzPEPHmkKRbA -AkUqY0oJwA9gMKf8dK+flmLZfbsCgYEAxO4Roj2G46/Oox1GEZGxdLpiMpr9rEdR -JlSZ9kMGfddNLV7sFp6yPXDcyc/AOqeNj7tw1MyoT3Ar454+V0q83EZzCXvs4U6f -jUrfFcoVWIwf9AV/J4KWzMIzfqPIeNwqymZKd6BrZgcXXvAEPWt27mwO4a1GhC4G -oZv0t3lAsm8CgYAQ8C0IhSF4tgBN5Ez19VoHpDQflbmowLRt77nNCZjajyOokyzQ -iI0ig0pSoBp7eITtTAyNfyew8/PZDi3IVTKv35OeQTv08VwP4H4EZGve5aetDf3C -kmBDTpl2qYQOwnH5tUPgTMypcVp+NXzI6lTXB/WuCprjy3qvc96e5ZpT3wKBgQC8 -Xny/k9rTL/eYTwgXBiWYYjBL97VudUlKQOKEjNhIxwkrvQBXIrWbz7lh0Tcu49al -BcaHxru4QLO6pkM7fGHq0fh3ufJ8EZjMrjF1xjdk26Q05o0aXe+hLKHVIRVBhlfo -ArB4fRo+HcpdJXjox0KcDQCvHe+1v9DYBTWvymv4QQKBgBy3YH7hKz35DcXvA2r4 -Kis9a4ycuZqTXockO4rkcIwC6CJp9JbHDIRzig8HYOaRqmZ4a+coqLmddXr2uOF1 -7+iAxxG1KzdT6uFNd+e/j2cdUjnqcSmz49PRtdDswgyYhoDT+W4yVGNQ4VuKg6a3 -Z3pC+KTdoHSKeA2FyAGnSUpD ------END PRIVATE KEY----- diff --git a/examples/edc-example/connector/configuration/consumer-configuration.properties b/examples/edc-example/connector/configuration/consumer-configuration.properties deleted file mode 100644 index 5102b3dc..00000000 --- a/examples/edc-example/connector/configuration/consumer-configuration.properties +++ /dev/null @@ -1,25 +0,0 @@ -edc.participant.id=http://runtime-2:8081 -# communication between the docker containers using the hostname of the container -edc.dsp.callback.address=http://two:29194/protocol -web.http.port=29191 -web.http.path=/api -web.http.management.port=29193 -web.http.management.path=/management -web.http.protocol.port=29194 -web.http.protocol.path=/protocol - -# use: host.docker.internal if the docker container needs access localhost -edc.receiver.http.endpoint=http://runtime-2:8081/token -edc.public.key.alias=public-key -edc.transfer.dataplane.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.verifier.publickey.alias=public-key -web.http.public.port=29291 -web.http.public.path=/public -web.http.control.port=29192 -web.http.control.path=/control -edc.dataplane.token.validation.endpoint=http://two:29192/control/token - -# authCode token expiration in seconds -edc.transfer.proxy.token.validity.seconds=999999 -#edc.transfer.proxy.token.validity.seconds=120 diff --git a/examples/edc-example/connector/configuration/consumer-vault.properties b/examples/edc-example/connector/configuration/consumer-vault.properties deleted file mode 100644 index 6ebdebd5..00000000 --- a/examples/edc-example/connector/configuration/consumer-vault.properties +++ /dev/null @@ -1 +0,0 @@ -public-key=-----BEGIN CERTIFICATE-----\r\nMIIDazCCAlOgAwIBAgIUZ3/sZXYzW4PjmOXKrZn6WBmUJ+4wDQYJKoZIhvcNAQEL\r\nBQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM\r\nGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAyMjMxNTA2MDNaFw0zMjAy\r\nMjExNTA2MDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw\r\nHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB\r\nAQUAA4IBDwAwggEKAoIBAQDBl6XaJnXTL+6DWip3aBhU+MzmY4d1V9hbTm1tiZ3g\r\nE0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7EddidN0ITHB9cQNdAfdUJ5njmsGS\r\nPbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7DHacZT/+OztBH1RwkG2ymM94Hf8H\r\nI6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvjX5qASakBtXISKIsOU84N0/2HDN3W\r\nEGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga775bPXN3M+JTSaIKE7dZbKzvx0Zi0\r\nh5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2YmnneYoVAgMBAAGjUzBRMB0GA1Ud\r\nDgQWBBTvK1wVERwjni4B2vdH7KtEJeVWFzAfBgNVHSMEGDAWgBTvK1wVERwjni4B\r\n2vdH7KtEJeVWFzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBn\r\nQHiPA7OBYukHd9gS7c0HXE+fsWcS3GZeLqcHfQQnV3pte1vTmu9//IVW71wNCJ1/\r\nrySRyODPQoPehxEcyHwupNZSzXK//nPlTdSgjMfFxscvt1YndyQLQYCfyOJMixAe\r\nAqrb14GTFHUUrdor0PyElhkULjkOXUrSIsdBrfWrwLTkelE8NK3tb5ZG8KPzD9Jy\r\n+NwEPPr9d+iHkUkM7EFWw/cl56wka9ryBb97RI7DqbO6/j6OXHMk4GByxKv7DSIR\r\nIvF9/Dw20qytajtaHV0pluFcOBuFc0NfiDvCaQlbTsfjzbc6UmZWbOi9YOJl3VQ/\r\ng3h+15GuzbsSzOCOEYOT\r\n-----END CERTIFICATE----- diff --git a/examples/edc-example/connector/configuration/provider-configuration.properties b/examples/edc-example/connector/configuration/provider-configuration.properties deleted file mode 100644 index dfa93ae1..00000000 --- a/examples/edc-example/connector/configuration/provider-configuration.properties +++ /dev/null @@ -1,25 +0,0 @@ -edc.participant.id=http://runtime-1:8081 -# communication between the docker containers using the hostname of the container -edc.dsp.callback.address=http://one:19194/protocol -web.http.port=19191 -web.http.path=/api -web.http.management.port=19193 -web.http.management.path=/management -web.http.protocol.port=19194 -web.http.protocol.path=/protocol - -# use: host.docker.internal if the docker container needs access localhost -edc.receiver.http.endpoint=http://runtime-1:8081/token -edc.public.key.alias=public-key -edc.transfer.dataplane.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.verifier.publickey.alias=public-key -web.http.public.port=19291 -web.http.public.path=/public -web.http.control.port=19192 -web.http.control.path=/control -edc.dataplane.token.validation.endpoint=http://one:19192/control/token - -# authCode token expiration in seconds -edc.transfer.proxy.token.validity.seconds=999999 -#edc.transfer.proxy.token.validity.seconds=120 diff --git a/examples/edc-example/connector/configuration/provider-vault.properties b/examples/edc-example/connector/configuration/provider-vault.properties deleted file mode 100644 index 6ebdebd5..00000000 --- a/examples/edc-example/connector/configuration/provider-vault.properties +++ /dev/null @@ -1 +0,0 @@ -public-key=-----BEGIN CERTIFICATE-----\r\nMIIDazCCAlOgAwIBAgIUZ3/sZXYzW4PjmOXKrZn6WBmUJ+4wDQYJKoZIhvcNAQEL\r\nBQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM\r\nGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAyMjMxNTA2MDNaFw0zMjAy\r\nMjExNTA2MDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw\r\nHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB\r\nAQUAA4IBDwAwggEKAoIBAQDBl6XaJnXTL+6DWip3aBhU+MzmY4d1V9hbTm1tiZ3g\r\nE0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7EddidN0ITHB9cQNdAfdUJ5njmsGS\r\nPbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7DHacZT/+OztBH1RwkG2ymM94Hf8H\r\nI6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvjX5qASakBtXISKIsOU84N0/2HDN3W\r\nEGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga775bPXN3M+JTSaIKE7dZbKzvx0Zi0\r\nh5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2YmnneYoVAgMBAAGjUzBRMB0GA1Ud\r\nDgQWBBTvK1wVERwjni4B2vdH7KtEJeVWFzAfBgNVHSMEGDAWgBTvK1wVERwjni4B\r\n2vdH7KtEJeVWFzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBn\r\nQHiPA7OBYukHd9gS7c0HXE+fsWcS3GZeLqcHfQQnV3pte1vTmu9//IVW71wNCJ1/\r\nrySRyODPQoPehxEcyHwupNZSzXK//nPlTdSgjMfFxscvt1YndyQLQYCfyOJMixAe\r\nAqrb14GTFHUUrdor0PyElhkULjkOXUrSIsdBrfWrwLTkelE8NK3tb5ZG8KPzD9Jy\r\n+NwEPPr9d+iHkUkM7EFWw/cl56wka9ryBb97RI7DqbO6/j6OXHMk4GByxKv7DSIR\r\nIvF9/Dw20qytajtaHV0pluFcOBuFc0NfiDvCaQlbTsfjzbc6UmZWbOi9YOJl3VQ/\r\ng3h+15GuzbsSzOCOEYOT\r\n-----END CERTIFICATE----- diff --git a/examples/edc-example/connector/configuration/three-configuration.properties b/examples/edc-example/connector/configuration/three-configuration.properties deleted file mode 100644 index 6b0e231d..00000000 --- a/examples/edc-example/connector/configuration/three-configuration.properties +++ /dev/null @@ -1,25 +0,0 @@ -edc.participant.id=http://runtime-3:8081 -# communication between the docker containers using the hostname of the container -edc.dsp.callback.address=http://three:39194/protocol -web.http.port=39191 -web.http.path=/api -web.http.management.port=39193 -web.http.management.path=/management -web.http.protocol.port=39194 -web.http.protocol.path=/protocol - -# use: host.docker.internal if the docker container needs access localhost -edc.receiver.http.endpoint=http://runtime-3:8081/token -edc.public.key.alias=public-key -edc.transfer.dataplane.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.verifier.publickey.alias=public-key -web.http.public.port=39291 -web.http.public.path=/public -web.http.control.port=39192 -web.http.control.path=/control -edc.dataplane.token.validation.endpoint=http://three:39192/control/token - -# authCode token expiration in seconds -edc.transfer.proxy.token.validity.seconds=999999 - diff --git a/examples/edc-example/connector/configuration/three-vault.properties b/examples/edc-example/connector/configuration/three-vault.properties deleted file mode 100644 index 6ebdebd5..00000000 --- a/examples/edc-example/connector/configuration/three-vault.properties +++ /dev/null @@ -1 +0,0 @@ -public-key=-----BEGIN CERTIFICATE-----\r\nMIIDazCCAlOgAwIBAgIUZ3/sZXYzW4PjmOXKrZn6WBmUJ+4wDQYJKoZIhvcNAQEL\r\nBQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM\r\nGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAyMjMxNTA2MDNaFw0zMjAy\r\nMjExNTA2MDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw\r\nHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB\r\nAQUAA4IBDwAwggEKAoIBAQDBl6XaJnXTL+6DWip3aBhU+MzmY4d1V9hbTm1tiZ3g\r\nE0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7EddidN0ITHB9cQNdAfdUJ5njmsGS\r\nPbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7DHacZT/+OztBH1RwkG2ymM94Hf8H\r\nI6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvjX5qASakBtXISKIsOU84N0/2HDN3W\r\nEGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga775bPXN3M+JTSaIKE7dZbKzvx0Zi0\r\nh5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2YmnneYoVAgMBAAGjUzBRMB0GA1Ud\r\nDgQWBBTvK1wVERwjni4B2vdH7KtEJeVWFzAfBgNVHSMEGDAWgBTvK1wVERwjni4B\r\n2vdH7KtEJeVWFzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBn\r\nQHiPA7OBYukHd9gS7c0HXE+fsWcS3GZeLqcHfQQnV3pte1vTmu9//IVW71wNCJ1/\r\nrySRyODPQoPehxEcyHwupNZSzXK//nPlTdSgjMfFxscvt1YndyQLQYCfyOJMixAe\r\nAqrb14GTFHUUrdor0PyElhkULjkOXUrSIsdBrfWrwLTkelE8NK3tb5ZG8KPzD9Jy\r\n+NwEPPr9d+iHkUkM7EFWw/cl56wka9ryBb97RI7DqbO6/j6OXHMk4GByxKv7DSIR\r\nIvF9/Dw20qytajtaHV0pluFcOBuFc0NfiDvCaQlbTsfjzbc6UmZWbOi9YOJl3VQ/\r\ng3h+15GuzbsSzOCOEYOT\r\n-----END CERTIFICATE----- diff --git a/examples/edc-example/connector/libs/connector.jar b/examples/edc-example/connector/libs/connector.jar deleted file mode 100644 index 8fbed623..00000000 Binary files a/examples/edc-example/connector/libs/connector.jar and /dev/null differ diff --git a/examples/edc-example/data/alice/alice_vc.json b/examples/edc-example/data/alice/alice_vc.json new file mode 100644 index 00000000..c5e6d870 --- /dev/null +++ b/examples/edc-example/data/alice/alice_vc.json @@ -0,0 +1,41 @@ + [ + { + "participantContextId": "alice", + "id": "03d712fe-410e-41d0-8355-7febea29c172", + "metadata": { + "credentialObjectId": "6621363b-1c65-48a1-8df4-ecb11ea9ca52" + }, + "issuancePolicy": null, + "reissuancePolicy": null, + "verifiableCredential": { + "rawVc": "eyJraWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5I2F1dGhvcml0eS1rZXkiLCJhbGciOiJFZDI1NTE5In0.eyJzdWIiOiJkaWQ6d2ViOmhvc3QtYWxpY2UiLCJuYmYiOjE3NjI3OTA0OTIsImlzcyI6ImRpZDp3ZWI6aG9zdC1hdXRob3JpdHkiLCJleHAiOjE3NjI3OTA1NTIsImlhdCI6MTc2Mjc5MDQ5MiwidmMiOnsiY3JlZGVudGlhbFN1YmplY3QiOlt7ImlkIjoiZGlkOndlYjpob3N0LWFsaWNlIiwibWVtYmVyc2hpcFR5cGUiOiJmdWxsTWVtYmVyIiwid2Vic2l0ZSI6ImV4YW1wbGUuY29tIiwiY29udGFjdCI6ImFsaWNlLW1haWxAZXhhbXBsZS5jb20iLCJzaW5jZSI6IjIwMjUtMDEtMDFUMDA6MDA6MDAifV0sImlzc3VhbmNlRGF0ZSI6IjIwMjUtMTEtMTBUMTY6MDE6MzIuNTYyMjE1MDYxWiIsIm5hbWUiOm51bGwsImRlc2NyaXB0aW9uIjpudWxsLCJpZCI6ImFmYzYyMTc5LTkzOGYtNDJmYy04MTRmLWEzOTI3MDZmM2E4NyIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJNZW1iZXJzaGlwQ3JlZGVudGlhbCJdLCJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3RyYWN0dXN4LXRydXN0L3YwLjgiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpc3N1ZXIiOnsiaWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnt9fSwiZGF0YU1vZGVsVmVyc2lvbiI6IlZfMV8xIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI4LTA4LTA2VDE2OjAxOjMyLjU2MjIxNTgxOFoiLCJjcmVkZW50aWFsU3RhdHVzIjpbXX0sImp0aSI6IjFmODVjYjdkLTAzNWQtNDI2YS04N2E4LTViNjFmNmQ5ZjVmYSJ9.8gqcaTg1CnmnjIFLE4V42tJrHjSE4CA0sAgzVJdRxOhk3eOGAmJeRzTdP4prgnCWuV9_PJpwy5ViAsSwInP1Ag", + "format": "VC1_0_JWT", + "credential": { + "credentialSubject": [ + { + "id": "did:web:host-alice", + "membershipType": "fullMember", + "website": "example.com", + "contact": "alice-mail@example.com", + "since": "2025-01-01T00:00:00" + } + ], + "id": "afc62179-938f-42fc-814f-a392706f3a87", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": { + "id": "did:web:host-authority", + "additionalProperties": {} + }, + "issuanceDate": "2025-11-10T16:01:32.562215061Z", + "expirationDate": "2028-08-06T16:01:32.562215818Z", + "credentialStatus": [], + "description": null, + "name": null, + "dataModelVersion": "V_1_1" + } + } + } + ] \ No newline at end of file diff --git a/examples/edc-example/data/alice/config/alice-controlplane.yaml b/examples/edc-example/data/alice/config/alice-controlplane.yaml new file mode 100644 index 00000000..3cda9f64 --- /dev/null +++ b/examples/edc-example/data/alice/config/alice-controlplane.yaml @@ -0,0 +1,52 @@ +# API definition +web.http: + port: 9080 + path: "/api" + control: + port: 9081 + path: "/api/control" + management: + port: 9082 + path: "/api/management" + # auth: #TODO + protocol: + port: 9083 + path: "/api/dsp" + catalog: + port: 9084 + path: "/api/catalog" + # auth: #TODO + +# CORS +edc.web.rest.cors: + enabled: true + headers: "origin,content-type,accept,authorization,x-api-key" + +# Connector-level identifiers & callback +edc.participant.id: "did:web:host-alice" +edc.dsp.callback.address: "http://localhost:9083/api/dsp" + +# DID & identity +edc.iam: + credential.revocation.mimetype: "application/json" + issuer.id: "did:web:host-alice" + did.web.use.https: false + sts.oauth: + token.url: "http://localhost:7094/api/v1/sts/token" + client.id: "did:web:host-alice" + client.secret.alias: "alice-sts-client-secret" + # Only used when *not* relying on the HashiCorp vault: + client.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + +# Self-description metadata - required with DE-EDC control plane image +edc.selfdescription: + logo: "https://static.wikia.nocookie.net/fictionalcompanies/images/c/c2/ACME_Corporation.png" + name: "Alice" + description: "Demo agent Alice" + +# Registration & trusted issuers +edc.ih.dcp.trusted.issuers: "did:web:host-authority" +edc.registration.service: + url: "http://localhost:9051/api/registration" + autoregister: true + id: "did:web:host-authority" diff --git a/examples/edc-example/data/alice/config/alice-dataplane.yaml b/examples/edc-example/data/alice/config/alice-dataplane.yaml new file mode 100644 index 00000000..58104682 --- /dev/null +++ b/examples/edc-example/data/alice/config/alice-dataplane.yaml @@ -0,0 +1,20 @@ +web.http: + port: 8090 + path: "/api" + + control: + port: 8091 + path: "/api/control" + + public: + port: 8094 + path: "/api/v1/public" + +edc: + dpf.selector.url: "http://localhost:9081/api/control/v1/dataplanes" + + component.id: "f45cacf3-f81b-4c1f-9b93-6f8603fb44c6" + + transfer.proxy.token: + signer.privatekey.alias: "private-key" + verifier.publickey.alias: "public-key" diff --git a/examples/edc-example/data/alice/config/alice-identityhub.yaml b/examples/edc-example/data/alice/config/alice-identityhub.yaml new file mode 100644 index 00000000..b1d4f109 --- /dev/null +++ b/examples/edc-example/data/alice/config/alice-identityhub.yaml @@ -0,0 +1,88 @@ +web.http: + port: 7090 + path: "/api" + + # This contains both the Presentation & Storage API (Github Identity Hub API documentation), + # now referred to as the Credentials API. Possibly also the same as the DCP API as mentioned + # in the Adopters manual. + credentials: + port: 7091 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/resolution`. + path: "/api/credentials" + identity: + port: 7092 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/management`. + path: "/api/identity" + did: + port: 7093 + path: "/" + sts: + port: 7094 + path: "/api/v1/sts" + jwks: + port: 7095 + path: "/api/jwks" + issueradmin: + port: 7096 + path: "/api/issueradmin" + issuance: + port: 7097 + path: "/api/issuance" + statuslist: + port: 7098 + path: "/statuslist" + +edc: + web.rest.cors: + enabled: true + headers: "origin, content-type, accept, authorization, x-api-key" + origins: "*" + methods: "GET, POST, DELETE, PUT, OPTIONS, PATCH" + + iam.did.web.use.https: false + + # Can probably be removed as the accounts sts api has been removed + api.accounts.key: "YaO5UMkYg2w586Cg017iy6Q7A6-EyuOt" + + issuer.statuslist.signing.key.alias: "alice-signing-key" + + ih: + # this value can be removed once the official issuance implementation fully replaces the ad-hoc one. + issuer.participant.id: "alice" + api: + participants: + # This is used as the participant context ID within the Identity Hub. + # It therefore is present in path of URLs to the API of this Hub + # instance, base64 encoded. + # Not the same as the participant ID (as assigned to the control plane), + # which is a did:web. + alice: + name: "alice" + did: "did:web:host-alice" + active: true + roles: # Required but can be empty + password: "$2a$10$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" + private.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSURxUFUvdHlNakVhOGw4TmN3bXhia1ZMendnYWxjc002RGxkejNBbmtscDYKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo= + public.key: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQVNWRmlUcW90aE55WVZqN0gyNXdUSUdLa2N5ZGFBUklzTTBEWDcwODlDdlk9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo= + sts.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + credentials: "data/alice_vc.json" # Required! + api.key.override: "YWxpY2U=.c3VwZXItc2VjcmV0LWtleQo=" + services: + dsp: + endpoint: "http://localhost:9083/api/dsp" + id: "dsp" + type: "DSPMessaging" + credential: + endpoint: "http://localhost:7091/api/resolution/v1/participants/YWxpY2U=" + id: "CredentialService" + type: "CredentialService" + issuerservice: + endpoint: "http://localhost:7097/api/issuance/v1alpha/participants/YWxpY2U=" + id: "IssuerService" + type: "IssuerService" + + + + diff --git a/examples/edc-example/data/alice/keys/alice-key.pem b/examples/edc-example/data/alice/keys/alice-key.pem new file mode 100644 index 00000000..81166e3a --- /dev/null +++ b/examples/edc-example/data/alice/keys/alice-key.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIDqPU/tyMjEa8l8NcwmxbkVLzwgalcsM6Dldz3Anklp6 +-----END PRIVATE KEY----- diff --git a/examples/edc-example/data/alice/keys/alice-pub.pem b/examples/edc-example/data/alice/keys/alice-pub.pem new file mode 100644 index 00000000..59171d98 --- /dev/null +++ b/examples/edc-example/data/alice/keys/alice-pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEASVFiTqothNyYVj7H25wTIGKkcydaARIsM0DX7089CvY= +-----END PUBLIC KEY----- diff --git a/examples/edc-example/data/authority/authority_vc.json b/examples/edc-example/data/authority/authority_vc.json new file mode 100644 index 00000000..a7e7b769 --- /dev/null +++ b/examples/edc-example/data/authority/authority_vc.json @@ -0,0 +1,164 @@ +[ + { + "participantContextId": "authority", + "id": "ecc9c1f9-f2ce-46bb-9f68-e45c75e510d4", + "metadata": { + "published": true, + "credentialObjectId": "6621363b-1c65-48a1-8df4-ecb11ea9ca52" + }, + "issuancePolicy": null, + "reissuancePolicy": null, + "verifiableCredential": { + "rawVc": "eyJraWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5I2F1dGhvcml0eS1rZXkiLCJhbGciOiJFZDI1NTE5In0.eyJzdWIiOiJkaWQ6d2ViOmhvc3QtYm9iIiwibmJmIjoxNzYyNzkwMjM2LCJpc3MiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiZXhwIjoxNzYyNzkwMjk2LCJpYXQiOjE3NjI3OTAyMzYsInZjIjp7ImNyZWRlbnRpYWxTdWJqZWN0IjpbeyJpZCI6ImRpZDp3ZWI6aG9zdC1ib2IiLCJtZW1iZXJzaGlwVHlwZSI6ImZ1bGxNZW1iZXIiLCJ3ZWJzaXRlIjoiZXhhbXBsZS5jb20iLCJjb250YWN0IjoiYm9iLW1haWxAZXhhbXBsZS5jb20iLCJzaW5jZSI6IjIwMjUtMDEtMDFUMDA6MDA6MDAifV0sImlzc3VhbmNlRGF0ZSI6IjIwMjUtMTEtMTBUMTU6NTc6MTYuMzQyMjA5ODA4WiIsIm5hbWUiOm51bGwsImRlc2NyaXB0aW9uIjpudWxsLCJpZCI6IjY1NTViMGU3LWE1YjAtNDY4Yi1iZmRkLTQxNTMxNzZhMDE2OCIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJNZW1iZXJzaGlwQ3JlZGVudGlhbCJdLCJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3RyYWN0dXN4LXRydXN0L3YwLjgiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpc3N1ZXIiOnsiaWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnt9fSwiZGF0YU1vZGVsVmVyc2lvbiI6IlZfMV8xIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI4LTA4LTA2VDE1OjU3OjE2LjM0MjIxMjkwMFoiLCJjcmVkZW50aWFsU3RhdHVzIjpbXX0sImp0aSI6IjIxOTBmMmE3LThjNjAtNDM1YS04YmQyLTNiZDM4NmZmYjE0ZCJ9.HuNWLA6g--9u_Sn9mnDRRbgNzXts5PtZiDhDZC5KvnBhz_E2cgxryLH_0z5BoqJ4_6R4i40jI0qsjhFvWQkJDQ", + "format": "VC1_0_JWT", + "credential": { + "credentialSubject": [ + { + "id": "did:web:host-bob", + "membershipType": "fullMember", + "website": "example.com", + "contact": "bob-mail@example.com", + "since": "2025-01-01T00:00:00" + } + ], + "id": "6555b0e7-a5b0-468b-bfdd-4153176a0168", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": { + "id": "did:web:host-authority", + "additionalProperties": {} + }, + "issuanceDate": "2025-11-10T15:57:16.342209808Z", + "expirationDate": "2028-08-06T15:57:16.342212900Z", + "credentialStatus": [], + "description": null, + "name": null, + "dataModelVersion": "V_1_1" + } + } + }, + { + "participantContextId": "authority", + "id": "9ae83563-b095-40fc-b241-7d69e9a25c3d", + "metadata": { + "published": true, + "credentialObjectId": "6621363b-1c65-48a1-8df4-ecb11ea9ca52" + }, + "issuancePolicy": null, + "reissuancePolicy": null, + "verifiableCredential": { + "rawVc": "eyJraWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5I2F1dGhvcml0eS1rZXkiLCJhbGciOiJFZDI1NTE5In0.eyJzdWIiOiJkaWQ6d2ViOmhvc3QtY2Fyb2wiLCJuYmYiOjE3NjQ5MjQ3MTgsImlzcyI6ImRpZDp3ZWI6aG9zdC1hdXRob3JpdHkiLCJleHAiOjE3NjQ5MjQ3NzgsImlhdCI6MTc2NDkyNDcxOCwidmMiOnsiY3JlZGVudGlhbFN1YmplY3QiOlt7ImlkIjoiZGlkOndlYjpob3N0LWNhcm9sIiwibWVtYmVyc2hpcFR5cGUiOiJmdWxsTWVtYmVyIiwid2Vic2l0ZSI6ImV4YW1wbGUuY29tIiwiY29udGFjdCI6ImNhcm9sLW1haWxAZXhhbXBsZS5jb20iLCJzaW5jZSI6IjIwMjUtMDEtMDFUMDA6MDA6MDAifV0sImlzc3VhbmNlRGF0ZSI6IjIwMjUtMTItMDVUMDg6NTE6NTguNDQ3MDg0MDQ1WiIsIm5hbWUiOm51bGwsImRlc2NyaXB0aW9uIjpudWxsLCJpZCI6ImNjY2VhYzcwLTUxZWItNDVhNS1iZGM1LTQ5YTJiYTUxYzI5MyIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJNZW1iZXJzaGlwQ3JlZGVudGlhbCJdLCJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3RyYWN0dXN4LXRydXN0L3YwLjgiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpc3N1ZXIiOnsiaWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnt9fSwiZGF0YU1vZGVsVmVyc2lvbiI6IlZfMV8xIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI4LTA4LTMxVDA4OjUxOjU4LjQ0NzA4ODEwNVoiLCJjcmVkZW50aWFsU3RhdHVzIjpbXX0sImp0aSI6IjAxNjA5MjYxLWEzMzYtNDZiYy1hY2MzLTk0MTQ3NGE0OGNmZSJ9.UiH53TRuPeHRr-xuC5dH8q_W9dhEzhhGA-9oTLsOCcaYAG4xoaHFCwv50bpNsh8FLRpQrPqkXxo8sYNzSt3ZDA", + "format": "VC1_0_JWT", + "credential": { + "credentialSubject": [ + { + "id": "did:web:host-carol", + "membershipType": "fullMember", + "website": "example.com", + "contact": "carol-mail@example.com", + "since": "2025-01-01T00:00:00" + } + ], + "id": "ccceac70-51eb-45a5-bdc5-49a2ba51c293", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": { + "id": "did:web:host-authority", + "additionalProperties": {} + }, + "issuanceDate": "2025-12-05T08:51:58.447084045Z", + "expirationDate": "2028-08-31T08:51:58.447088105Z", + "credentialStatus": [], + "description": null, + "name": null, + "dataModelVersion": "V_1_1" + } + } + }, + { + "participantContextId": "authority", + "id": "fea87c30-05ed-4304-a19e-b614f010c466", + "metadata": { + "publicUrl": "http://authority:7078/statuslist/436db3f8-d7ea-4664-83b3-b27ac711da85", + "published": true, + "isActive": true, + "currentIndex": 2, + "bitstringSize": 16384 + }, + "issuancePolicy": null, + "reissuancePolicy": null, + "verifiableCredential": { + "rawVc": "eyJraWQiOiJkaWQ6d2ViOmF1dGhvcml0eSNhdXRob3JpdHkta2V5IiwiYWxnIjoiRWQyNTUxOSJ9.eyJzdWIiOiI1YjJlZTI2Ny0xNzFhLTQ1YzEtODI5ZS1lM2MwOTNiY2UwYzUiLCJuYmYiOjE3NTAwNzUyMDQsImlzcyI6ImRpZDp3ZWI6YXV0aG9yaXR5IiwiZXhwIjoxNzgxNjExMjA0LCJpYXQiOjE3NTAwNzUyMDQsInZjIjp7Imlzc3VhbmNlRGF0ZSI6IjIwMjUtMDYtMTZUMTI6MDA6MDQuNjc4NTIxNzgxWiIsImNyZWRlbnRpYWxTdWJqZWN0Ijp7InN0YXR1c1B1cnBvc2UiOiJyZXZvY2F0aW9uIiwidHlwZSI6IkJpdHN0cmluZ1N0YXR1c0xpc3QiLCJlbmNvZGVkTGlzdCI6InVINHNJQUFBQUFBQUFfMk5nR0FXallCU01nbEV3Q2tiQlNBTUFucnJvOFFBSUFBQSJ9LCJpZCI6IjQzNmRiM2Y4LWQ3ZWEtNDY2NC04M2IzLWIyN2FjNzExZGE4NSIsInR5cGUiOlsiQml0c3RyaW5nU3RhdHVzTGlzdCJdLCJAY29udGV4dCI6WyJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpc3N1ZXIiOiJkaWQ6d2ViOmF1dGhvcml0eSIsImV4cGlyYXRpb25EYXRlIjoiMjAyNi0wNi0xNlQxMjowMDowNC42Nzg1MjE3ODFaIn19.uSnViCWw0U-hOvG9c0NJMEqlOiUwlTA_zX6uWdM6fVxCnb13cXZsbg4_FzM8YEu2tMuH9yl0FF-ON6ehDBM9AA", + "format": "VC1_0_JWT", + "credential": { + "credentialSubject": [ + { + "statusPurpose": "revocation", + "type": "BitstringStatusList", + "encodedList": "uH4sIAAAAAAAA_2NgGAWjYBSMglEwCkbBSAMAnrro8QAIAAA", + "id": "5b2ee267-171a-45c1-829e-e3c093bce0c5" + } + ], + "id": "436db3f8-d7ea-4664-83b3-b27ac711da85", + "type": [ + "BitstringStatusList" + ], + "issuer": { + "id": "did:web:host-authority", + "additionalProperties": {} + }, + "issuanceDate": "2025-06-16T12:00:04.678521781Z", + "expirationDate": "2026-06-16T12:00:04.678521781Z", + "credentialStatus": [], + "description": null, + "name": null, + "dataModelVersion": "V_1_1", + "credentialSchema": [] + } + } + }, + { + "participantContextId": "authority", + "id": "dd35f14d-ed3d-48bc-a4f0-684370b70183", + "metadata": { + "published": true, + "credentialObjectId": "6621363b-1c65-48a1-8df4-ecb11ea9ca52" + }, + "issuancePolicy": null, + "reissuancePolicy": null, + "verifiableCredential": { + "rawVc": "eyJraWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5I2F1dGhvcml0eS1rZXkiLCJhbGciOiJFZDI1NTE5In0.eyJzdWIiOiJkaWQ6d2ViOmhvc3QtYWxpY2UiLCJuYmYiOjE3NjI3OTA0OTIsImlzcyI6ImRpZDp3ZWI6aG9zdC1hdXRob3JpdHkiLCJleHAiOjE3NjI3OTA1NTIsImlhdCI6MTc2Mjc5MDQ5MiwidmMiOnsiY3JlZGVudGlhbFN1YmplY3QiOlt7ImlkIjoiZGlkOndlYjpob3N0LWFsaWNlIiwibWVtYmVyc2hpcFR5cGUiOiJmdWxsTWVtYmVyIiwid2Vic2l0ZSI6ImV4YW1wbGUuY29tIiwiY29udGFjdCI6ImFsaWNlLW1haWxAZXhhbXBsZS5jb20iLCJzaW5jZSI6IjIwMjUtMDEtMDFUMDA6MDA6MDAifV0sImlzc3VhbmNlRGF0ZSI6IjIwMjUtMTEtMTBUMTY6MDE6MzIuNTYyMjE1MDYxWiIsIm5hbWUiOm51bGwsImRlc2NyaXB0aW9uIjpudWxsLCJpZCI6ImFmYzYyMTc5LTkzOGYtNDJmYy04MTRmLWEzOTI3MDZmM2E4NyIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJNZW1iZXJzaGlwQ3JlZGVudGlhbCJdLCJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3RyYWN0dXN4LXRydXN0L3YwLjgiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpc3N1ZXIiOnsiaWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnt9fSwiZGF0YU1vZGVsVmVyc2lvbiI6IlZfMV8xIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI4LTA4LTA2VDE2OjAxOjMyLjU2MjIxNTgxOFoiLCJjcmVkZW50aWFsU3RhdHVzIjpbXX0sImp0aSI6IjFmODVjYjdkLTAzNWQtNDI2YS04N2E4LTViNjFmNmQ5ZjVmYSJ9.8gqcaTg1CnmnjIFLE4V42tJrHjSE4CA0sAgzVJdRxOhk3eOGAmJeRzTdP4prgnCWuV9_PJpwy5ViAsSwInP1Ag", + "format": "VC1_0_JWT", + "credential": { + "credentialSubject": [ + { + "id": "did:web:host-alice", + "membershipType": "fullMember", + "website": "example.com", + "contact": "alice-mail@example.com", + "since": "2025-01-01T00:00:00" + } + ], + "id": "afc62179-938f-42fc-814f-a392706f3a87", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": { + "id": "did:web:host-authority", + "additionalProperties": {} + }, + "issuanceDate": "2025-11-10T16:01:32.562215061Z", + "expirationDate": "2028-08-06T16:01:32.562215818Z", + "credentialStatus": [], + "description": null, + "name": null, + "dataModelVersion": "V_1_1" + } + } + } +] \ No newline at end of file diff --git a/examples/edc-example/data/authority/config/authority-identityhub.yaml b/examples/edc-example/data/authority/config/authority-identityhub.yaml new file mode 100644 index 00000000..fe8d55c9 --- /dev/null +++ b/examples/edc-example/data/authority/config/authority-identityhub.yaml @@ -0,0 +1,123 @@ +web.http: + port: 7090 + path: "/api" + + # This contains both the Presentation & Storage API (Github Identity Hub API documentation), + # now referred to as the Credentials API. Possibly also the same as the DCP API as mentioned + # in the Adopters manual. + credentials: + port: 7091 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/resolution`. + path: "/api/credentials" + identity: + port: 7092 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/management`. + path: "/api/identity" + did: + port: 7093 + path: "/" + sts: + port: 7094 + path: "/api/v1/sts" + issueradmin: + port: 7096 + path: "/api/issueradmin" + issuance: + port: 7097 + path: "/api/issuance" + statuslist: + port: 7078 + path: "/statuslist" + dataspaces: + port: 7099 + path: "/dataspaces" + +edc: + web.rest.cors: + enabled: true + headers: "origin, content-type, accept, authorization, x-api-key" + + iam.did.web.use.https: false + + # Can probably be removed as the accounts STS API has been removed + api.accounts.key: "YaO5UMkYg2w586Cg017iy6Q7A6-EyuOt" + + issuer.statuslist.signing.key.alias: "authority-signing-key" + + ih: + # This value can be removed once the official issuance implementation fully replaces the ad-hoc one. + issuer.participant.id: "authority" + api: + participants: + # This is used as the participant context ID within the Identity Hub. + # It therefore is present in path of URLs to the API of this Hub + # instance, base64 encoded. + # Not the same as the participant ID (as assigned to the control plane), + # which is a did:web. + authority: + name: "authority" + did: "did:web:host-authority" + active: true + roles: # Required but can be empty + password: "$2a$10$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" + private.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSUxyQ0hnWC9RbysyVTExMWJWc3pVVW5zUkRMalJsWlcvdVo3VVkveDAxV2UKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo= + public.key: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQUlTdDk3M1ZMMHpnRE1mN1U4TFdiYnpRVS9UNzM3VDdwUnFIY3lBTFMrU1U9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo= + sts.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + api.key.override: "YXV0aG9yaXR5.c3VwZXItc2VjcmV0LWtleQo=" + credentials: "data/authority_vc.json" # Required! + services: + credential: + endpoint: "http://localhost:7071/api/resolution/v1/participants/YXV0aG9yaXR5" + id: "CredentialService" + type: "CredentialService" + issuerservice: + endpoint: "http://localhost:7077/api/issuance/v1alpha/participants/YXV0aG9yaXR5" + id: "IssuerService" + type: "IssuerService" + + + issuers: + authority: + holders: + bob: + id: bob + did: did:web:host-bob + alice: + id: alice + did: did:web:host-alice + carol: + id: carol + did: did:web:host-carol + attestation.definitions: + "1": + type: membershipAttestation + id: att-01 + configuration: "{}" + credential.definitions: + "1": + id: 6621363b-1c65-48a1-8df4-ecb11ea9ca52 + type: MembershipCredential + attestations: att-01 + format: VC1_0_JWT + json.schema: "{}" + validity: 31556926 + mapping.definitions: + "1": + input: membershipType + output: credentialSubject.membershipType + required: true + "2": + input: since + output: credentialSubject.since + required: true + "3": + input: name + output: name + required: true + "4": + input: dataspaceName + output: credentialSubject.dataspaceMembership.dataspaceName + required: true + diff --git a/examples/edc-example/data/authority/config/authority-registration-service.yaml b/examples/edc-example/data/authority/config/authority-registration-service.yaml new file mode 100644 index 00000000..5859144c --- /dev/null +++ b/examples/edc-example/data/authority/config/authority-registration-service.yaml @@ -0,0 +1,26 @@ +web.http: + port: 9050 + path: "/api" + + registration: + port: 9051 + path: "/api/registration" + +edc.web.rest.cors: + enabled: true + headers: "origin,content-type,accept,authorization,x-api-key" + +edc.participant.id: "did:web:host-authority" + +edc.iam: + credential.revocation.mimetype: "application/json" + issuer.id: "did:web:host-authority" + did.web.use.https: false + sts.oauth: + token.url: "http://localhost:7074/api/v1/sts/token" + client.id: "did:web:host-authority" + client.secret.alias: "authority" + # Only used when *not* backed by a HashiCorp vault: + client.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + +edc.ih.dcp.trusted.issuers: "did:web:host-authority" \ No newline at end of file diff --git a/examples/edc-example/data/authority/keys/authority-key.pem b/examples/edc-example/data/authority/keys/authority-key.pem new file mode 100644 index 00000000..25e57798 --- /dev/null +++ b/examples/edc-example/data/authority/keys/authority-key.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEILrCHgX/Qo+2U111bVszUUnsRDLjRlZW/uZ7UY/x01We +-----END PRIVATE KEY----- diff --git a/examples/edc-example/data/authority/keys/authority-pub.pem b/examples/edc-example/data/authority/keys/authority-pub.pem new file mode 100644 index 00000000..17f97777 --- /dev/null +++ b/examples/edc-example/data/authority/keys/authority-pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAISt973VL0zgDMf7U8LWbbzQU/T737T7pRqHcyALS+SU= +-----END PUBLIC KEY----- diff --git a/examples/edc-example/data/bob/bob_vc.json b/examples/edc-example/data/bob/bob_vc.json new file mode 100644 index 00000000..1b2932f6 --- /dev/null +++ b/examples/edc-example/data/bob/bob_vc.json @@ -0,0 +1,41 @@ +[ + { + "participantContextId": "bob", + "id": "1c8fe5d5-2b29-4392-bce5-34b0c54c8686", + "metadata": { + "credentialObjectId": "6621363b-1c65-48a1-8df4-ecb11ea9ca52" + }, + "issuancePolicy": null, + "reissuancePolicy": null, + "verifiableCredential": { + "rawVc": "eyJraWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5I2F1dGhvcml0eS1rZXkiLCJhbGciOiJFZDI1NTE5In0.eyJzdWIiOiJkaWQ6d2ViOmhvc3QtYm9iIiwibmJmIjoxNzYyNzkwMjM2LCJpc3MiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiZXhwIjoxNzYyNzkwMjk2LCJpYXQiOjE3NjI3OTAyMzYsInZjIjp7ImNyZWRlbnRpYWxTdWJqZWN0IjpbeyJpZCI6ImRpZDp3ZWI6aG9zdC1ib2IiLCJtZW1iZXJzaGlwVHlwZSI6ImZ1bGxNZW1iZXIiLCJ3ZWJzaXRlIjoiZXhhbXBsZS5jb20iLCJjb250YWN0IjoiYm9iLW1haWxAZXhhbXBsZS5jb20iLCJzaW5jZSI6IjIwMjUtMDEtMDFUMDA6MDA6MDAifV0sImlzc3VhbmNlRGF0ZSI6IjIwMjUtMTEtMTBUMTU6NTc6MTYuMzQyMjA5ODA4WiIsIm5hbWUiOm51bGwsImRlc2NyaXB0aW9uIjpudWxsLCJpZCI6IjY1NTViMGU3LWE1YjAtNDY4Yi1iZmRkLTQxNTMxNzZhMDE2OCIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJNZW1iZXJzaGlwQ3JlZGVudGlhbCJdLCJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3RyYWN0dXN4LXRydXN0L3YwLjgiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpc3N1ZXIiOnsiaWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnt9fSwiZGF0YU1vZGVsVmVyc2lvbiI6IlZfMV8xIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI4LTA4LTA2VDE1OjU3OjE2LjM0MjIxMjkwMFoiLCJjcmVkZW50aWFsU3RhdHVzIjpbXX0sImp0aSI6IjIxOTBmMmE3LThjNjAtNDM1YS04YmQyLTNiZDM4NmZmYjE0ZCJ9.HuNWLA6g--9u_Sn9mnDRRbgNzXts5PtZiDhDZC5KvnBhz_E2cgxryLH_0z5BoqJ4_6R4i40jI0qsjhFvWQkJDQ", + "format": "VC1_0_JWT", + "credential": { + "credentialSubject": [ + { + "id": "did:web:host-bob", + "membershipType": "fullMember", + "website": "example.com", + "contact": "bob-mail@example.com", + "since": "2025-01-01T00:00:00" + } + ], + "id": "6555b0e7-a5b0-468b-bfdd-4153176a0168", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": { + "id": "did:web:host-authority", + "additionalProperties": {} + }, + "issuanceDate": "2025-11-10T15:57:16.342209808Z", + "expirationDate": "2028-08-06T15:57:16.342212900Z", + "credentialStatus": [], + "description": null, + "name": null, + "dataModelVersion": "V_1_1" + } + } + } +] \ No newline at end of file diff --git a/examples/edc-example/data/bob/config/bob-controlplane.yaml b/examples/edc-example/data/bob/config/bob-controlplane.yaml new file mode 100644 index 00000000..e8d485f5 --- /dev/null +++ b/examples/edc-example/data/bob/config/bob-controlplane.yaml @@ -0,0 +1,52 @@ +# API definition +web.http: + port: 9080 + path: "/api" + control: + port: 9081 + path: "/api/control" + management: + port: 9082 + path: "/api/management" + # auth: #TODO + protocol: + port: 9083 + path: "/api/dsp" + catalog: + port: 9084 + path: "/api/catalog" + # auth: #TODO + +# CORS +edc.web.rest.cors: + enabled: true + headers: "origin,content-type,accept,authorization,x-api-key" + +# Connector-level identifiers & callback +edc.participant.id: "did:web:host-bob" +edc.dsp.callback.address: "http://localhost:9083/api/dsp" + +# DID & identity +edc.iam: + credential.revocation.mimetype: "application/json" + issuer.id: "did:web:host-bob" + did.web.use.https: false + sts.oauth: + token.url: "http://localhost:7094/api/v1/sts/token" + client.id: "did:web:host-bob" + client.secret.alias: "bob-sts-client-secret" + # Only used when *not* backed by a HashiCorp vault: + client.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + +# Self-description metadata - required with DE-EDC control plane image +edc.selfdescription: + logo: "https://static.wikia.nocookie.net/fictionalcompanies/images/c/c2/ACME_Corporation.png" + name: "Bob" + description: "Demo agent Bob" + +# Registration & trusted issuers +edc.ih.dcp.trusted.issuers: "did:web:host-authority" +edc.registration.service: + url: "http://localhost:9051/api/registration" + autoregister: true + id: "did:web:host-authority" diff --git a/examples/edc-example/data/bob/config/bob-dataplane.yaml b/examples/edc-example/data/bob/config/bob-dataplane.yaml new file mode 100644 index 00000000..a3d23f27 --- /dev/null +++ b/examples/edc-example/data/bob/config/bob-dataplane.yaml @@ -0,0 +1,20 @@ +web.http: + port: 8090 + path: "/api" + + control: + port: 8091 + path: "/api/control" + + public: + port: 8094 + path: "/api/v1/public" + +edc: + dpf.selector.url: "http://localhost:9081/api/control/v1/dataplanes" + + component.id: "4b6fa2b2-784f-47a8-84e0-c9d55fa23bd2" + + transfer.proxy.token: + signer.privatekey.alias: "private-key" + verifier.publickey.alias: "public-key" diff --git a/examples/edc-example/data/bob/config/bob-identityhub.yaml b/examples/edc-example/data/bob/config/bob-identityhub.yaml new file mode 100644 index 00000000..210285f5 --- /dev/null +++ b/examples/edc-example/data/bob/config/bob-identityhub.yaml @@ -0,0 +1,84 @@ +web.http: + port: 7090 + path: "/api" + + # This contains both the Presentation & Storage API (Github Identity Hub API documentation), + # now referred to as the Credentials API. Possibly also the same as the DCP API as mentioned + # in the Adopters manual. + credentials: + port: 7091 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/resolution`. + path: "/api/credentials" + identity: + port: 7092 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/management`. + path: "/api/identity" + did: + port: 7093 + path: "/" + sts: + port: 7094 + path: "/api/v1/sts" + jwks: + port: 7095 + path: "/api/jwks" + issueradmin: + port: 7096 + path: "/api/issueradmin" + issuance: + port: 7097 + path: "/api/issuance" + statuslist: + port: 7098 + path: "/statuslist" + +edc: + web.rest.cors: + enabled: true + headers: "origin, content-type, accept, authorization, x-api-key" + origins: "*" + methods: "GET, POST, DELETE, PUT, OPTIONS, PATCH" + + iam.did.web.use.https: false + + # Can probably be removed as the accounts STS API has been removed + api.accounts.key: "YaO5UMkYg2w586Cg017iy6Q7A6-EyuOt" + + issuer.statuslist.signing.key.alias: "bob-signing-key" + + ih: + # This value can be removed once the official issuance implementation fully replaces the ad-hoc one. + issuer.participant.id: "bob" + api: + participants: + # This is used as the participant context ID within the Identity Hub. + # It therefore is present in path of URLs to the API of this Hub + # instance, base64 encoded. + # Not the same as the participant ID (as assigned to the control plane), + # which is a did:web. + bob: + name: "bob" + did: "did:web:host-bob" + active: true + roles: # Required but can be empty + password: "$2a$10$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" + private.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSUVMelhlUWRTeW9TaVVqaHFKMkVxUndKOTV0WGtLM1RYMG1DNnd1K21Ra1AKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo= + public.key: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQWJqVlQ2Y1NiWEozTHhVY3hwQ0pVTklsUkJpMG15RDVUZ29xSC9NZ05GL1U9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo= + sts.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + api.key.override: "Ym9i.c3VwZXItc2VjcmV0LWtleQo=" + credentials: "data/bob_vc.json" # Required! + services: + dsp: + endpoint: "http://localhost:9083/api/dsp" + id: "dsp" + type: "DSPMessaging" + credential: + endpoint: "http://localhost:7091/api/resolution/v1/participants/Ym9i" + id: "CredentialService" + type: "CredentialService" + issuerservice: + endpoint: "http://localhost:7097/api/issuance/v1alpha/participants/Ym9i" + id: "IssuerService" + type: "IssuerService" diff --git a/examples/edc-example/data/bob/keys/bob-key.pem b/examples/edc-example/data/bob/keys/bob-key.pem new file mode 100644 index 00000000..27f15529 --- /dev/null +++ b/examples/edc-example/data/bob/keys/bob-key.pem @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEIELzXeQdSyoSiUjhqJ2EqRwJ95tXkK3TX0mC6wu+mQkP +-----END PRIVATE KEY----- diff --git a/examples/edc-example/data/bob/keys/bob-pub.pem b/examples/edc-example/data/bob/keys/bob-pub.pem new file mode 100644 index 00000000..ea4b3e08 --- /dev/null +++ b/examples/edc-example/data/bob/keys/bob-pub.pem @@ -0,0 +1,3 @@ +-----BEGIN PUBLIC KEY----- +MCowBQYDK2VwAyEAbjVT6cSbXJ3LxUcxpCJUNIlRBi0myD5TgoqH/MgNF/U= +-----END PUBLIC KEY----- diff --git a/examples/edc-example/data/carol/carol_vc.json b/examples/edc-example/data/carol/carol_vc.json new file mode 100644 index 00000000..3266c620 --- /dev/null +++ b/examples/edc-example/data/carol/carol_vc.json @@ -0,0 +1,41 @@ +[ + { + "participantContextId": "carol", + "id": "9ae83563-b095-40fc-b241-7d69e9a25c3d", + "metadata": { + "credentialObjectId": "6621363b-1c65-48a1-8df4-ecb11ea9ca52" + }, + "issuancePolicy": null, + "reissuancePolicy": null, + "verifiableCredential": { + "rawVc": "eyJraWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5I2F1dGhvcml0eS1rZXkiLCJhbGciOiJFZDI1NTE5In0.eyJzdWIiOiJkaWQ6d2ViOmhvc3QtY2Fyb2wiLCJuYmYiOjE3NjQ5MjQ3MTgsImlzcyI6ImRpZDp3ZWI6aG9zdC1hdXRob3JpdHkiLCJleHAiOjE3NjQ5MjQ3NzgsImlhdCI6MTc2NDkyNDcxOCwidmMiOnsiY3JlZGVudGlhbFN1YmplY3QiOlt7ImlkIjoiZGlkOndlYjpob3N0LWNhcm9sIiwibWVtYmVyc2hpcFR5cGUiOiJmdWxsTWVtYmVyIiwid2Vic2l0ZSI6ImV4YW1wbGUuY29tIiwiY29udGFjdCI6ImNhcm9sLW1haWxAZXhhbXBsZS5jb20iLCJzaW5jZSI6IjIwMjUtMDEtMDFUMDA6MDA6MDAifV0sImlzc3VhbmNlRGF0ZSI6IjIwMjUtMTItMDVUMDg6NTE6NTguNDQ3MDg0MDQ1WiIsIm5hbWUiOm51bGwsImRlc2NyaXB0aW9uIjpudWxsLCJpZCI6ImNjY2VhYzcwLTUxZWItNDVhNS1iZGM1LTQ5YTJiYTUxYzI5MyIsInR5cGUiOlsiVmVyaWZpYWJsZUNyZWRlbnRpYWwiLCJNZW1iZXJzaGlwQ3JlZGVudGlhbCJdLCJAY29udGV4dCI6WyJodHRwczovL3czaWQub3JnL3RyYWN0dXN4LXRydXN0L3YwLjgiLCJodHRwczovL3d3dy53My5vcmcvMjAxOC9jcmVkZW50aWFscy92MSJdLCJpc3N1ZXIiOnsiaWQiOiJkaWQ6d2ViOmhvc3QtYXV0aG9yaXR5IiwiYWRkaXRpb25hbFByb3BlcnRpZXMiOnt9fSwiZGF0YU1vZGVsVmVyc2lvbiI6IlZfMV8xIiwiZXhwaXJhdGlvbkRhdGUiOiIyMDI4LTA4LTMxVDA4OjUxOjU4LjQ0NzA4ODEwNVoiLCJjcmVkZW50aWFsU3RhdHVzIjpbXX0sImp0aSI6IjAxNjA5MjYxLWEzMzYtNDZiYy1hY2MzLTk0MTQ3NGE0OGNmZSJ9.UiH53TRuPeHRr-xuC5dH8q_W9dhEzhhGA-9oTLsOCcaYAG4xoaHFCwv50bpNsh8FLRpQrPqkXxo8sYNzSt3ZDA", + "format": "VC1_0_JWT", + "credential": { + "credentialSubject": [ + { + "id": "did:web:host-carol", + "membershipType": "fullMember", + "website": "example.com", + "contact": "carol-mail@example.com", + "since": "2025-01-01T00:00:00" + } + ], + "id": "ccceac70-51eb-45a5-bdc5-49a2ba51c293", + "type": [ + "VerifiableCredential", + "MembershipCredential" + ], + "issuer": { + "id": "did:web:host-authority", + "additionalProperties": {} + }, + "issuanceDate": "2025-12-05T08:51:58.447084045Z", + "expirationDate": "2028-08-31T08:51:58.447088105Z", + "credentialStatus": [], + "description": null, + "name": null, + "dataModelVersion": "V_1_1" + } + } + } +] \ No newline at end of file diff --git a/examples/edc-example/data/carol/config/carol-controlplane.yaml b/examples/edc-example/data/carol/config/carol-controlplane.yaml new file mode 100644 index 00000000..571a5cb5 --- /dev/null +++ b/examples/edc-example/data/carol/config/carol-controlplane.yaml @@ -0,0 +1,52 @@ +# API definition +web.http: + port: 9080 + path: "/api" + control: + port: 9081 + path: "/api/control" + management: + port: 9082 + path: "/api/management" + # auth: #TODO + protocol: + port: 9083 + path: "/api/dsp" + catalog: + port: 9084 + path: "/api/catalog" + # auth: #TODO + +# CORS +edc.web.rest.cors: + enabled: true + headers: "origin,content-type,accept,authorization,x-api-key" + +# Connector-level identifiers & callback +edc.participant.id: "did:web:host-carol" +edc.dsp.callback.address: "http://localhost:9083/api/dsp" + +# DID & identity +edc.iam: + credential.revocation.mimetype: "application/json" + issuer.id: "did:web:host-carol" + did.web.use.https: false + sts.oauth: + token.url: "http://localhost:7094/api/v1/sts/token" + client.id: "did:web:host-carol" + client.secret.alias: "carol-sts-client-secret" + # Only used when *not* relying on the HashiCorp vault: + client.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + +# Self-description metadata - required with DE-EDC control plane image +edc.selfdescription: + logo: "https://static.wikia.nocookie.net/fictionalcompanies/images/c/c2/ACME_Corporation.png" + name: "Carol" + description: "Demo agent Carol" + +# Registration & trusted issuers +edc.ih.dcp.trusted.issuers: "did:web:host-authority" +edc.registration.service: + url: "http://localhost:9051/api/registration" + autoregister: true + id: "did:web:host-authority" diff --git a/examples/edc-example/data/carol/config/carol-dataplane.yaml b/examples/edc-example/data/carol/config/carol-dataplane.yaml new file mode 100644 index 00000000..58104682 --- /dev/null +++ b/examples/edc-example/data/carol/config/carol-dataplane.yaml @@ -0,0 +1,20 @@ +web.http: + port: 8090 + path: "/api" + + control: + port: 8091 + path: "/api/control" + + public: + port: 8094 + path: "/api/v1/public" + +edc: + dpf.selector.url: "http://localhost:9081/api/control/v1/dataplanes" + + component.id: "f45cacf3-f81b-4c1f-9b93-6f8603fb44c6" + + transfer.proxy.token: + signer.privatekey.alias: "private-key" + verifier.publickey.alias: "public-key" diff --git a/examples/edc-example/data/carol/config/carol-identityhub.yaml b/examples/edc-example/data/carol/config/carol-identityhub.yaml new file mode 100644 index 00000000..40a86a8e --- /dev/null +++ b/examples/edc-example/data/carol/config/carol-identityhub.yaml @@ -0,0 +1,88 @@ +web.http: + port: 7090 + path: "/api" + + # This contains both the Presentation & Storage API (Github Identity Hub API documentation), + # now referred to as the Credentials API. Possibly also the same as the DCP API as mentioned + # in the Adopters manual. + credentials: + port: 7091 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/resolution`. + path: "/api/credentials" + identity: + port: 7092 + # This is a deviation from the Data Ecosystems EDC demo configuration, which + # uses path `/api/management`. + path: "/api/identity" + did: + port: 7093 + path: "/" + sts: + port: 7094 + path: "/api/v1/sts" + jwks: + port: 7095 + path: "/api/jwks" + issueradmin: + port: 7096 + path: "/api/issueradmin" + issuance: + port: 7097 + path: "/api/issuance" + statuslist: + port: 7098 + path: "/statuslist" + +edc: + web.rest.cors: + enabled: true + headers: "origin, content-type, accept, authorization, x-api-key" + origins: "*" + methods: "GET, POST, DELETE, PUT, OPTIONS, PATCH" + + iam.did.web.use.https: false + + # Can probably be removed as the accounts sts api has been removed + api.accounts.key: "YaO5UMkYg2w586Cg017iy6Q7A6-EyuOt" + + issuer.statuslist.signing.key.alias: "carol-signing-key" + + ih: + # this value can be removed once the official issuance implementation fully replaces the ad-hoc one. + issuer.participant.id: "carol" + api: + participants: + # This is used as the participant context ID within the Identity Hub. + # It therefore is present in path of URLs to the API of this Hub + # instance, base64 encoded. + # Not the same as the participant ID (as assigned to the control plane), + # which is a did:web. + carol: + name: "carol" + did: "did:web:host-carol" + active: true + roles: # Required but can be empty + password: "$2a$10$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" + private.key: LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1DNENBUUF3QlFZREsyVndCQ0lFSURxUFUvdHlNakVhOGw4TmN3bXhia1ZMendnYWxjc002RGxkejNBbmtscDYKLS0tLS1FTkQgUFJJVkFURSBLRVktLS0tLQo= + public.key: LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUNvd0JRWURLMlZ3QXlFQVNWRmlUcW90aE55WVZqN0gyNXdUSUdLa2N5ZGFBUklzTTBEWDcwODlDdlk9Ci0tLS0tRU5EIFBVQkxJQyBLRVktLS0tLQo= + sts.secret: "1yj1R5jqQr1Zy1M7wg9y8uJjHsUQQH1LOp3oF0IFxeo=" + credentials: "data/carol_vc.json" # Required! + api.key.override: "YWxpY2U=.c3VwZXItc2VjcmV0LWtleQo=" + services: + dsp: + endpoint: "http://localhost:9083/api/dsp" + id: "dsp" + type: "DSPMessaging" + credential: + endpoint: "http://localhost:7091/api/resolution/v1/participants/YWxpY2U=" + id: "CredentialService" + type: "CredentialService" + issuerservice: + endpoint: "http://localhost:7097/api/issuance/v1alpha/participants/YWxpY2U=" + id: "IssuerService" + type: "IssuerService" + + + + diff --git a/examples/edc-example/data/nginx/nginx.conf b/examples/edc-example/data/nginx/nginx.conf new file mode 100644 index 00000000..a05eb701 --- /dev/null +++ b/examples/edc-example/data/nginx/nginx.conf @@ -0,0 +1,56 @@ + +# Knowledge Directory +server { + listen 80; + server_name host-authority; + + location / { + proxy_pass http://authority-identity-hub:7093; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +# Alice +server { + listen 80; + server_name host-alice; + + location / { + proxy_pass http://alice-identity-hub:7093; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +# Bob +server { + listen 80; + server_name host-bob; + + location / { + proxy_pass http://bob-identity-hub:7093; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} + +# Carol +server { + listen 80; + server_name host-carol; + + location / { + proxy_pass http://carol-identity-hub:7093; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + } +} diff --git a/examples/edc-example/docker-compose.yaml b/examples/edc-example/docker-compose.yaml new file mode 100644 index 00000000..7c6eaa64 --- /dev/null +++ b/examples/edc-example/docker-compose.yaml @@ -0,0 +1,472 @@ +# Notes on networking between containers: +# - All containers belonging to one participant in the TKE network (KE runtime or Data +# Plane, KB, Control Plane, Identity Hub) are assigned to a separate Compose network, +# simulating as if these are on different premises. +# - Ports that are exposed to localhost by containers, are those that would be +# exposed to the internet in real applications. Those that should not be exposed +# to the internet are not exposed here either, but they are of course still +# accesible by containers in the same Compose network. +# - Identity Hub containers are assigned ports starting with 7. +# - Knowledge Engine runtimes, Data Planes and directory are assigned ports starting +# with 8. +# - Control Planes are assigned ports starting with 9. +# +# - It is required for the setup to add to your /etc/hosts file: +# 127.0.0.1 host-authority +# 127.0.0.1 host-alice +# 127.0.0.1 host-bob +# 127.0.0.1 host-carol +# + + +networks: + # Add a network per participant as if they are on different premises. + network-alice: + name: network-alice + external: false + network-bob: + name: network-bob + external: false + network-carol: + name: network-carol + external: false + network-authority: + name: network-authority + external: false + + +services: + nginx-proxy: + container_name: nginx-proxy + image: nginx:latest + ports: + - "80:80" + volumes: + - ./data/nginx/nginx.conf:/etc/nginx/conf.d/default.conf + networks: + - network-alice + - network-bob + - network-carol + - network-authority + + # region: -- Knowledge Directory & Authority + + knowledge-directory: + container_name: knowledge-directory + image: testkd:1.3.3-SNAPSHOT + networks: + - network-authority + ports: + - "8282:8282" + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + + authority-identity-hub: + container_name: authority-identity-hub + image: docker.nexus.dataspac.es/edc/edc-identity-hub:0.5.0-SNAPSHOT + networks: + - network-authority + ports: + - "7091:7091" # Credential API / Presentation + Storage API / DCP API? + - "7094:7094" # Token API + - "7097:7097" # Issuance API + - "7078:7078" # Statuslist API, at 7078 is required due to pregenerated VC's? + - "7099:7099" # Dataspaces API + - "7096:7096" # Issuer Admin API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_HOSTNAME: authority-identity-hub + EDC_IH_API_PARTICIPANTS_AUTHORITY_SERVICES_CREDENTIAL_ENDPOINT: "http://host.docker.internal:7091/api/credentials/v1/participants/YXV0aG9yaXR5" + EDC_IH_API_PARTICIPANTS_AUTHORITY_SERVICES_ISSUERSERVICE_ENDPOINT: "http://host.docker.internal:7097/api/issuance/v1alpha/participants/YXV0aG9yaXR5" + EDC_IH_API_PARTICIPANTS_AUTHORITY_PASSWORD: "$$2a$$10$$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" # Escape $ here for docker compose + EDC_FS_YAML_CONFIG: "/data/config/authority-identityhub.yaml" + volumes: + - ./data/authority:/data:rw + + registration-service: + container_name: registration-service + image: docker.nexus.dataspac.es/edc/edc-registration-service:0.5.0-SNAPSHOT + networks: + - network-authority + ports: + - "9050:9050" # General + - "9051:9051" # Registration API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_IAM_STS_OAUTH_TOKEN_URL: "http://host.docker.internal:7094/api/v1/sts/token" + EDC_FS_YAML_CONFIG: "/data/config/authority-registration-service.yaml" + volumes: + - ./data/authority:/data:rw + + # endregion: -- Knowledge Directory & Authority + + # region: -- (Asking) Participant Alice + + alice-kb: + container_name: alice-kb + build: ../common/asking_kb + networks: + - network-alice + environment: + KE_URL: http://alice-ker:8280/rest + KB_ID: http://example.org/kb1 + PREFIXES: '{ "ex": "http://example.org/" }' + GRAPH_PATTERN: ?a ex:relatedTo ?b . + + alice-ker: + container_name: alice-ker + image: docker.io/library/testsc:1.3.3-SNAPSHOT + networks: + - network-alice + ports: + - "8081:8081" + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + KE_RUNTIME_PORT: 8081 # The port that the KE uses to listen for inter-KE-runtime communication. + KE_RUNTIME_EXPOSED_URL: http://host-alice:8081 # The URL where the runtime is available for inter-runtime communication from the outside. + KD_URL: http://host-authority:8282 + JAVA_TOOL_OPTIONS: "-Dorg.slf4j.simpleLogger.defaultLogLevel=info" + KE_RUNTIME_USE_EDC: true + KE_EDC_PARTICIPANT_ID: "did:web:host-alice" + KE_EDC_PROTOCOL_URL: "http://host-alice:9183/api/dsp" + KE_EDC_MANAGEMENT_URL: "http://alice-control-plane:9082/api/management" + KE_EDC_DATAPLANE_CONTROL_URL: "http://alice-http-data-plane:8091/api/control/transfer" + KE_EDC_DATAPLANE_PUBLIC_URL: "http://host-alice:8194/api/v1/public" + KE_EDC_TOKEN_VALIDATION_ENDPOINT: "http://alice-http-data-plane:8091/api/control/token" + depends_on: # Necessary? + - alice-control-plane + + alice-control-plane: + container_name: alice-control-plane + image: docker.nexus.dataspac.es/edc/edc-control-plane:0.5.0-SNAPSHOT + networks: + - network-alice + ports: + # Control planes expose their DSP protocol API and Catalog API to the internet. + # - The Catalog API serves catalog requests by other parties. + # - The DSP protocol API is used by other control planes for contract agreements and transfer processes. + - "9183:9083" # DSP protocol API + - "9184:9084" # Catalog API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_IAM_STS_OAUTH_TOKEN_URL: "http://alice-identity-hub:7094/api/v1/sts/token" + EDC_DSP_CALLBACK_ADDRESS: "http://host-alice:9183/api/dsp" + EDC_REGISTRATION_SERVICE_URL: "http://host-authority:9051/api/registration" + EDC_FS_YAML_CONFIG: "/data/config/alice-controlplane.yaml" + volumes: + - ./data/alice:/data:rw + + alice-http-data-plane: + container_name: alice-http-data-plane + image: docker.nexus.dataspac.es/edc/edc-http-data-plane:0.5.0-SNAPSHOT + networks: + - network-alice + ports: + - "8194:8194" # Public API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + WEB_HTTP_PUBLIC_PORT: 8194 + EDC_DPF_SELECTOR_URL: "http://alice-control-plane:9081/api/control/v1/dataplanes" + EDC_CONTROL_ENDPOINT: "http://alice-http-data-plane:8091/api/control" + # set hostname, which is to create callback addresses. + EDC_HOSTNAME: "host-alice" + EDC_FS_YAML_CONFIG: "/data/config/alice-dataplane.yaml" + volumes: + - ./data/alice:/data:rw + + alice-identity-hub: + image: docker.nexus.dataspac.es/edc/edc-identity-hub:0.5.0-SNAPSHOT + container_name: alice-identity-hub + networks: + - network-alice + ports: + - "7191:7091" # Credential API / Presentation + Storage API / DCP API? + - "7197:7097" # Issuance API + - "7196:7096" # Issuer Admin API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_IH_API_PARTICIPANTS_ALICE_SERVICES_CREDENTIAL_ENDPOINT: "http://host-alice:7191/api/credentials/v1/participants/YWxpY2U=" + EDC_IH_API_PARTICIPANTS_ALICE_SERVICES_DSP_ENDPOINT: "http://host-alice:9183/api/dsp" + EDC_IH_API_PARTICIPANTS_ALICE_SERVICES_ISSUERSERVICE_ENDPOINT: "http://host-alice:7197/api/issuance/v1alpha/participants/YWxpY2U=" + EDC_IH_API_PARTICIPANTS_ALICE_PASSWORD: "$$2a$$10$$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" + EDC_HOSTNAME: alice + EDC_FS_YAML_CONFIG: "/data/config/alice-identityhub.yaml" + volumes: + - ./data/alice:/data:rw + + # endregion: -- (Asking) Participant Alice + + # region: -- (Answering) participant Bob + + bob-kb: + container_name: bob-kb + build: ../common/answering_kb + networks: + - network-bob + environment: + KE_URL: http://bob-ker:8280/rest + KB_ID: http://example.org/kb2 + PREFIXES: | + { + "ex": "http://example.org/" + } + GRAPH_PATTERN: | + ?a ex:relatedTo ?b . + KB_DATA: | + [ + { + "a": "", + "b": "" + } + ] + + bob-ker: + container_name: bob-ker + image: docker.io/library/testsc:1.3.3-SNAPSHOT + networks: + - network-bob + ports: + - "8082:8082" + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + KE_RUNTIME_PORT: 8082 # The port that the KE uses to listen for inter-KE-runtime communication. + KE_RUNTIME_EXPOSED_URL: http://host-bob:8082 # The URL where the runtime is available for inter-runtime communication from the outside. + KD_URL: http://host-authority:8282 + JAVA_TOOL_OPTIONS: "-Dorg.slf4j.simpleLogger.defaultLogLevel=info" + KE_RUNTIME_USE_EDC: true + KE_EDC_PARTICIPANT_ID: "did:web:host-bob" + KE_EDC_PROTOCOL_URL: "http://host-bob:9283/api/dsp" + KE_EDC_MANAGEMENT_URL: "http://bob-control-plane:9082/api/management" + KE_EDC_DATAPLANE_CONTROL_URL: "http://bob-http-data-plane:8091/api/control/transfer" + KE_EDC_DATAPLANE_PUBLIC_URL: "http://host-bob:8294/api/v1/public" + KE_EDC_TOKEN_VALIDATION_ENDPOINT: "http://bob-http-data-plane:8091/api/control/token" + depends_on: # Necessary? + - bob-control-plane + + bob-control-plane: + container_name: bob-control-plane + image: docker.nexus.dataspac.es/edc/edc-control-plane:0.5.0-SNAPSHOT + networks: + - network-bob + ports: + # Control planes expose their DSP protocol API and Catalog API to the internet. + # - The Catalog API serves catalog requests by other parties. + # - The DSP protocol API is used by other control planes for contract agreements and transfer processes. + - "9283:9083" # DSP protocol API + - "9284:9084" # Catalog API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_IAM_STS_OAUTH_TOKEN_URL: "http://bob-identity-hub:7094/api/v1/sts/token" + EDC_DSP_CALLBACK_ADDRESS: "http://host-bob:9283/api/dsp" + EDC_REGISTRATION_SERVICE_URL: "http://host-authority:9051/api/registration" + EDC_FS_YAML_CONFIG: "/data/config/bob-controlplane.yaml" + volumes: + - ./data/bob:/data:rw + + bob-http-data-plane: + container_name: bob-http-data-plane + image: docker.nexus.dataspac.es/edc/edc-http-data-plane:0.5.0-SNAPSHOT + networks: + - network-bob + ports: + - "8294:8294" # Public API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + WEB_HTTP_PUBLIC_PORT: 8294 + EDC_DPF_SELECTOR_URL: "http://bob-control-plane:9081/api/control/v1/dataplanes" + EDC_CONTROL_ENDPOINT: "http://bob-http-data-plane:8091/api/control" + # set hostname, which is to create callback addresses. + EDC_HOSTNAME: "host-bob" + EDC_FS_YAML_CONFIG: "/data/config/bob-dataplane.yaml" + volumes: + - ./data/bob:/data:rw + + bob-identity-hub: + image: docker.nexus.dataspac.es/edc/edc-identity-hub:0.5.0-SNAPSHOT + container_name: bob-identity-hub + networks: + - network-bob + ports: + - "7291:7091" # Credential API / Presentation + Storage API / DCP API? + - "7297:7097" # Issuance API + - "7296:7096" # Issuer Admin API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_IH_API_PARTICIPANTS_BOB_SERVICES_CREDENTIAL_ENDPOINT: "http://host-bob:7291/api/credentials/v1/participants/Ym9i" + EDC_IH_API_PARTICIPANTS_BOB_SERVICES_DSP_ENDPOINT: "http://host-bob:9283/api/dsp" + EDC_IH_API_PARTICIPANTS_BOB_SERVICES_ISSUERSERVICE_ENDPOINT: "http://host-bob:7297/api/issuance/v1alpha/participants/Ym9i" + EDC_IH_API_PARTICIPANTS_BOB_PASSWORD: "$$2a$$10$$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" + EDC_HOSTNAME: bob + EDC_FS_YAML_CONFIG: "/data/config/bob-identityhub.yaml" + volumes: + - ./data/bob:/data:rw + + # endregion: -- (Answering) Participant Bob + + # region: -- (Answering) Participant Carol + + carol-kb: + container_name: carol-kb + build: ../common/answering_kb + networks: + - network-carol + environment: + KE_URL: http://carol-ker:8280/rest + KB_ID: http://example.org/kb3 + PREFIXES: | + { + "ex": "http://example.org/" + } + GRAPH_PATTERN: | + ?a ex:relatedTo ?b . + KB_DATA: | + [ + { + "a": "", + "b": "" + } + ] + + carol-ker: + container_name: carol-ker + image: docker.io/library/testsc:1.3.3-SNAPSHOT + networks: + - network-carol + ports: + - "8083:8083" + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + KE_RUNTIME_PORT: 8083 # The port that the KE uses to listen for inter-KE-runtime communication. + KE_RUNTIME_EXPOSED_URL: http://host-carol:8083 # The URL where the runtime is available for inter-runtime communication from the outside. + KD_URL: http://host-authority:8282 + JAVA_TOOL_OPTIONS: "-Dorg.slf4j.simpleLogger.defaultLogLevel=info" + KE_RUNTIME_USE_EDC: true + KE_EDC_PARTICIPANT_ID: "did:web:host-carol" + KE_EDC_PROTOCOL_URL: "http://host-carol:9383/api/dsp" + KE_EDC_MANAGEMENT_URL: "http://carol-control-plane:9082/api/management" + KE_EDC_DATAPLANE_CONTROL_URL: "http://carol-http-data-plane:8091/api/control/transfer" + KE_EDC_DATAPLANE_PUBLIC_URL: "http://host-carol:8394/api/v1/public" + KE_EDC_TOKEN_VALIDATION_ENDPOINT: "http://carol-http-data-plane:8091/api/control/token" + depends_on: # Necessary? + - carol-control-plane + + carol-control-plane: + container_name: carol-control-plane + image: docker.nexus.dataspac.es/edc/edc-control-plane:0.5.0-SNAPSHOT + networks: + - network-carol + ports: + # Control planes expose their DSP protocol API and Catalog API to the internet. + # - The Catalog API serves catalog requests by other parties. + # - The DSP protocol API is used by other control planes for contract agreements and transfer processes. + - "9383:9083" # DSP protocol API + - "9384:9084" # Catalog API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_IAM_STS_OAUTH_TOKEN_URL: "http://carol-identity-hub:7094/api/v1/sts/token" + EDC_DSP_CALLBACK_ADDRESS: "http://host-carol:9383/api/dsp" + EDC_REGISTRATION_SERVICE_URL: "http://host-authority:9051/api/registration" + EDC_FS_YAML_CONFIG: "/data/config/carol-controlplane.yaml" + volumes: + - ./data/carol:/data:rw + + carol-http-data-plane: + container_name: carol-http-data-plane + image: docker.nexus.dataspac.es/edc/edc-http-data-plane:0.5.0-SNAPSHOT + networks: + - network-carol + ports: + - "8394:8394" # Public API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + WEB_HTTP_PUBLIC_PORT: 8394 + EDC_DPF_SELECTOR_URL: "http://carol-control-plane:9081/api/control/v1/dataplanes" + EDC_CONTROL_ENDPOINT: "http://carol-http-data-plane:8091/api/control" + # set hostname, which is to create callback addresses. + EDC_HOSTNAME: "host-carol" + EDC_FS_YAML_CONFIG: "/data/config/carol-dataplane.yaml" + volumes: + - ./data/carol:/data:rw + + carol-identity-hub: + image: docker.nexus.dataspac.es/edc/edc-identity-hub:0.5.0-SNAPSHOT + container_name: carol-identity-hub + networks: + - network-carol + ports: + - "7391:7091" # Credential API / Presentation + Storage API / DCP API? + - "7397:7097" # Issuance API + - "7396:7096" # Issuer Admin API + extra_hosts: + - "host-alice:host-gateway" + - "host-bob:host-gateway" + - "host-carol:host-gateway" + - "host-authority:host-gateway" + environment: + EDC_IH_API_PARTICIPANTS_CAROL_SERVICES_CREDENTIAL_ENDPOINT: "http://host-carol:7391/api/credentials/v1/participants/Y2Fyb2w=" # REQUIRES CHANGING OF URL TO PARTICIPANT CONTEXT NAME + EDC_IH_API_PARTICIPANTS_CAROL_SERVICES_DSP_ENDPOINT: "http://host-carol:9383/api/dsp" + EDC_IH_API_PARTICIPANTS_CAROL_SERVICES_ISSUERSERVICE_ENDPOINT: "http://host-carol:7397/api/issuance/v1alpha/participants/Y2Fyb2w=" + EDC_IH_API_PARTICIPANTS_CAROL_PASSWORD: "$$2a$$10$$KcjjniNy/p45X3yOWcDOY.lZ7ziNpA9pngh218lVMzdRqgYl0Wf06" + EDC_HOSTNAME: carol + EDC_FS_YAML_CONFIG: "/data/config/carol-identityhub.yaml" + volumes: + - ./data/carol:/data:rw + + # endregion: -- (Answering) Participant Carol + + diff --git a/examples/edc-example/docker-compose.yml b/examples/edc-example/docker-compose.yml deleted file mode 100644 index 50c9c566..00000000 --- a/examples/edc-example/docker-compose.yml +++ /dev/null @@ -1,180 +0,0 @@ -services: - - # This is the knowledge directory, facilitating discovery between different - # runtimes. It exposes its service over port 8282. - knowledge-directory: - image: ghcr.io/tno/knowledge-engine/knowledge-directory:1.3.3-SNAPSHOT - networks: - - tke-edc-manager_default - - # These services are seperate Knowledge Engine runtime, which can host - # multiple smart connectors. Note that the REST API port is a DIFFERENT port - # number than the ones configured below. It is still the default 8280. - runtime-1: - image: ghcr.io/tno/knowledge-engine/smart-connector:1.3.3-SNAPSHOT - networks: - - tke-edc-manager_default - environment: - KE_RUNTIME_PORT: 8081 # The port that the KE uses to listen for inter-KE-runtime communication. - KE_RUNTIME_EXPOSED_URL: http://runtime-1:8081 # The URL where the runtime is available for inter-runtime communication from the outside. - KD_URL: http://knowledge-directory:8282 - JAVA_TOOL_OPTIONS: "-Dorg.slf4j.simpleLogger.defaultLogLevel=info" - KE_RUNTIME_USE_EDC: true - KE_EDC_PROTOCOL_URL: "http://one:19194/protocol" - KE_EDC_MANAGEMENT_URL: "http://one:19193/management" - KE_EDC_DATAPLANE_CONTROL_URL: "http://one:19192/control/transfer" - KE_EDC_DATAPLANE_PUBLIC_URL: "http://one:19191/public" - KE_EDC_TOKEN_VALIDATION_ENDPOINT: "http://one:19192/control/token" - depends_on: - - tke-edc-one - runtime-2: - image: ghcr.io/tno/knowledge-engine/smart-connector:1.3.3-SNAPSHOT - networks: - - tke-edc-manager_default - environment: - KE_RUNTIME_PORT: 8081 - KE_RUNTIME_EXPOSED_URL: http://runtime-2:8081 - KD_URL: http://knowledge-directory:8282 - JAVA_TOOL_OPTIONS: "-Dorg.slf4j.simpleLogger.defaultLogLevel=info" - KE_RUNTIME_USE_EDC: true - KE_EDC_PROTOCOL_URL: "http://two:29194/protocol" - KE_EDC_MANAGEMENT_URL: "http://two:29193/management" - KE_EDC_DATAPLANE_CONTROL_URL: "http://two:29192/control/transfer" - KE_EDC_DATAPLANE_PUBLIC_URL: "http://two:29191/public" - KE_EDC_TOKEN_VALIDATION_ENDPOINT: "http://two:29192/control/token" - depends_on: - - tke-edc-two - runtime-3: - image: ghcr.io/tno/knowledge-engine/smart-connector:1.3.3-SNAPSHOT - networks: - - tke-edc-manager_default - environment: - KE_RUNTIME_PORT: 8081 - KE_RUNTIME_EXPOSED_URL: http://runtime-3:8081 - KD_URL: http://knowledge-directory:8282 - JAVA_TOOL_OPTIONS: "-Dorg.slf4j.simpleLogger.defaultLogLevel=info" - KE_RUNTIME_USE_EDC: true - KE_EDC_PROTOCOL_URL: "http://three:39194/protocol" - KE_EDC_MANAGEMENT_URL: "http://three:39193/management" - KE_EDC_DATAPLANE_CONTROL_URL: "http://three:39192/control/transfer" - KE_EDC_DATAPLANE_PUBLIC_URL: "http://three:39191/public" - KE_EDC_TOKEN_VALIDATION_ENDPOINT: "http://three:39192/control/token" - depends_on: - - tke-edc-three - tke-edc-one: - image: openjdk:17 - entrypoint: ["/bin/sh","-c"] - hostname: one - networks: - - tke-edc-manager_default - ports: - - "19191:19191" - - "19192:19192" - - "19193:19193" - - "19194:19194" - command: - - | - java -Dedc.keystore=/edc/certs/cert.pfx -Dedc.keystore.password=123456 -Dedc.vault=/edc/configuration/provider-vault.properties -Dedc.fs.config=/edc/configuration/provider-configuration.properties -jar /edc/libs/connector.jar - volumes: - - ./connector/certs:/edc/certs - - ./connector/libs:/edc/libs - - ./connector/configuration:/edc/configuration - extra_hosts: - - "host.docker.internal:host-gateway" - tke-edc-two: - image: openjdk:17 - entrypoint: [ "/bin/sh","-c" ] - hostname: two - networks: - - tke-edc-manager_default - ports: - - "29191:29191" - - "29192:29192" - - "29193:29193" - - "29194:29194" - command: - - | - java -Dedc.keystore=/edc/certs/cert.pfx -Dedc.keystore.password=123456 -Dedc.vault=/edc/configuration/consumer-vault.properties -Dedc.fs.config=/edc/configuration/consumer-configuration.properties -jar /edc/libs/connector.jar - volumes: - - ./connector/certs:/edc/certs - - ./connector/libs:/edc/libs - - ./connector/configuration:/edc/configuration - extra_hosts: - - "host.docker.internal:host-gateway" - tke-edc-three: - image: openjdk:17 - entrypoint: [ "/bin/sh","-c" ] - hostname: three - networks: - - tke-edc-manager_default - ports: - - "39191:39191" - - "39192:39192" - - "39193:39193" - - "39194:39194" - command: - - | - java -Dedc.keystore=/edc/certs/cert.pfx -Dedc.keystore.password=123456 -Dedc.vault=/edc/configuration/three-vault.properties -Dedc.fs.config=/edc/configuration/three-configuration.properties -jar /edc/libs/connector.jar - volumes: - - ./connector/certs:/edc/certs - - ./connector/libs:/edc/libs - - ./connector/configuration:/edc/configuration - extra_hosts: - - "host.docker.internal:host-gateway" - # These Knowledge Bases use the different runtimes, and exchange data with eachother. - kb1: # linked to edc consumer - build: ../common/asking_kb - networks: - - tke-edc-manager_default - environment: - KE_URL: http://runtime-1:8280/rest - KB_ID: http://example.org/kb1 - PREFIXES: | - { - "ex": "http://example.org/" - } - GRAPH_PATTERN: | - ?a ex:relatedTo ?b . - kb2: # linked to edc provider - build: ../common/answering_kb - networks: - - tke-edc-manager_default - environment: - KE_URL: http://runtime-2:8280/rest - KB_ID: http://example.org/kb2 - PREFIXES: | - { - "ex": "http://example.org/" - } - GRAPH_PATTERN: | - ?a ex:relatedTo ?b . - KB_DATA: | - [ - { - "a": "", - "b": "" - } - ] - kb3: # linked to edc provider - build: ../common/answering_kb - networks: - - tke-edc-manager_default - environment: - KE_URL: http://runtime-3:8280/rest - KB_ID: http://example.org/kb3 - PREFIXES: | - { - "ex": "http://example.org/" - } - GRAPH_PATTERN: | - ?a ex:relatedTo ?b . - KB_DATA: | - [ - { - "a": "", - "b": "" - } - ] -networks: - tke-edc-manager_default: - external: false diff --git a/examples/edc-example/edc.c4 b/examples/edc-example/edc.c4 new file mode 100644 index 00000000..b72a0292 --- /dev/null +++ b/examples/edc-example/edc.c4 @@ -0,0 +1,109 @@ +specification { + element participant { + description 'A TKE+EDC participant' + style { + shape person + color amber + } + } + element participantSystem + element knowledgeNetwork + element component + element KER { + title 'Knowledge Engine Runtime' + description 'Runtime containing the Smart Connector' + style { + icon tech:java + shape browser + } + } + element controlPlane { + title 'EDC Control Plane' + style { + icon tech:docker + color secondary + } + } + element identityHub { + title 'EDC Identity Hub' + style { + icon tech:docker + color secondary + } + } +} + +model { + Alice = participant 'User Alice' + Bob = participant 'User Bob' + Carol = participant 'User Carol' + + kn = knowledgeNetwork 'Knowledge Network' { + kd = component 'Knowledge Directory' + + AliceSystem = participantSystem { + kerAlice = KER + cpAlice = controlPlane { + description 'Control Plane for Alice' + } + ihAlice = identityHub { + description 'Identity Hub for Alice' + } + + cpAlice -> kerAlice "manages data transfers" + ihAlice -> cpAlice "manages credentials for" + } + + BobSystem = participantSystem 'TKE+EDC' { + kerBob = KER + cpBob = controlPlane { + description 'Control Plane for Bob' + } + ihBob = identityHub { + description 'Identity Hub for Bob' + } + + cpBob -> kerBob "manages data transfers" + ihBob -> cpBob "manages credentials for" + } + + CarolSystem = participantSystem { + kerCarol = KER + cpCarol = controlPlane { + description 'Control Plane for Carol' + } + ihCarol = identityHub { + description 'Identity Hub for Carol' + } + + cpCarol -> kerCarol "manages data transfers" + ihCarol -> cpCarol "manages credentials for" + } + } + + Alice -> kerAlice 'uses' + Bob -> kerBob 'uses' + Carol -> kerCarol 'uses' + Alice -> kn 'participates in' + Bob -> kn 'participates in' + Carol -> kn 'participates in' +} + +views { + view index { + title 'EDC Example' + + include * + } + + view network { + title 'Network' + + include Alice, Bob, Carol + include kn.AliceSystem.*, kn.BobSystem.*, kn.CarolSystem.* + + style Alice, Bob, Carol { + color muted + } + } +} \ No newline at end of file diff --git a/examples/edc-example/edc/certs/cert.pem b/examples/edc-example/edc/certs/cert.pem deleted file mode 100644 index c7dc26fa..00000000 --- a/examples/edc-example/edc/certs/cert.pem +++ /dev/null @@ -1,21 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDazCCAlOgAwIBAgIUZ3/sZXYzW4PjmOXKrZn6WBmUJ+4wDQYJKoZIhvcNAQEL -BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM -GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAyMjMxNTA2MDNaFw0zMjAy -MjExNTA2MDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw -HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDBl6XaJnXTL+6DWip3aBhU+MzmY4d1V9hbTm1tiZ3g -E0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7EddidN0ITHB9cQNdAfdUJ5njmsGS -PbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7DHacZT/+OztBH1RwkG2ymM94Hf8H -I6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvjX5qASakBtXISKIsOU84N0/2HDN3W -EGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga775bPXN3M+JTSaIKE7dZbKzvx0Zi0 -h5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2YmnneYoVAgMBAAGjUzBRMB0GA1Ud -DgQWBBTvK1wVERwjni4B2vdH7KtEJeVWFzAfBgNVHSMEGDAWgBTvK1wVERwjni4B -2vdH7KtEJeVWFzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBn -QHiPA7OBYukHd9gS7c0HXE+fsWcS3GZeLqcHfQQnV3pte1vTmu9//IVW71wNCJ1/ -rySRyODPQoPehxEcyHwupNZSzXK//nPlTdSgjMfFxscvt1YndyQLQYCfyOJMixAe -Aqrb14GTFHUUrdor0PyElhkULjkOXUrSIsdBrfWrwLTkelE8NK3tb5ZG8KPzD9Jy -+NwEPPr9d+iHkUkM7EFWw/cl56wka9ryBb97RI7DqbO6/j6OXHMk4GByxKv7DSIR -IvF9/Dw20qytajtaHV0pluFcOBuFc0NfiDvCaQlbTsfjzbc6UmZWbOi9YOJl3VQ/ -g3h+15GuzbsSzOCOEYOT ------END CERTIFICATE----- diff --git a/examples/edc-example/edc/certs/cert.pfx b/examples/edc-example/edc/certs/cert.pfx deleted file mode 100644 index 7ac9c73e..00000000 Binary files a/examples/edc-example/edc/certs/cert.pfx and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/checksums/checksums.lock b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/checksums/checksums.lock deleted file mode 100644 index cb9b2a8f..00000000 Binary files a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/checksums/checksums.lock and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/executionHistory/executionHistory.lock b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/executionHistory/executionHistory.lock deleted file mode 100644 index 959e6b66..00000000 Binary files a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/executionHistory/executionHistory.lock and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/fileChanges/last-build.bin b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/fileChanges/last-build.bin deleted file mode 100644 index f76dd238..00000000 Binary files a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/fileChanges/last-build.bin and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/fileHashes/fileHashes.lock b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/fileHashes/fileHashes.lock deleted file mode 100644 index dd67b2cb..00000000 Binary files a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/fileHashes/fileHashes.lock and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/gc.properties b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/8.13/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index eea4dc9b..00000000 Binary files a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/buildOutputCleanup/cache.properties b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index 87ae10a0..00000000 --- a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Jul 07 17:25:01 CEST 2025 -gradle.version=8.13 diff --git a/examples/edc-example/edc/consumer-pull-backend-service/.gradle/vcs-1/gc.properties b/examples/edc-example/edc/consumer-pull-backend-service/.gradle/vcs-1/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/edc-example/edc/consumer-pull-backend-service/bin/main/org/eclipse/edc/BackendService.class b/examples/edc-example/edc/consumer-pull-backend-service/bin/main/org/eclipse/edc/BackendService.class deleted file mode 100644 index cf55124e..00000000 Binary files a/examples/edc-example/edc/consumer-pull-backend-service/bin/main/org/eclipse/edc/BackendService.class and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/bin/main/org/eclipse/edc/handler/ReceiverHandler.class b/examples/edc-example/edc/consumer-pull-backend-service/bin/main/org/eclipse/edc/handler/ReceiverHandler.class deleted file mode 100644 index 166848b7..00000000 Binary files a/examples/edc-example/edc/consumer-pull-backend-service/bin/main/org/eclipse/edc/handler/ReceiverHandler.class and /dev/null differ diff --git a/examples/edc-example/edc/consumer-pull-backend-service/build.gradle.kts b/examples/edc-example/edc/consumer-pull-backend-service/build.gradle.kts deleted file mode 100644 index 76eeccf6..00000000 --- a/examples/edc-example/edc/consumer-pull-backend-service/build.gradle.kts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (c) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation - * - */ - -plugins { - id("java") -} - -tasks.withType { - manifest { - attributes["Main-Class"] = "org.eclipse.edc.BackendService" - } -} \ No newline at end of file diff --git a/examples/edc-example/edc/consumer-pull-backend-service/src/main/java/org/eclipse/edc/BackendService.java b/examples/edc-example/edc/consumer-pull-backend-service/src/main/java/org/eclipse/edc/BackendService.java deleted file mode 100644 index e9aabb6b..00000000 --- a/examples/edc-example/edc/consumer-pull-backend-service/src/main/java/org/eclipse/edc/BackendService.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation - * - */ - -package org.eclipse.edc; - -import com.sun.net.httpserver.HttpServer; -import org.eclipse.edc.handler.ReceiverHandler; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.util.Optional; - -public class BackendService { - - static final String HTTP_PORT = "server.port"; - - public static void main(String[] args) { - int port = Integer.parseInt(Optional.ofNullable(System.getenv(HTTP_PORT)).orElse("4000")); - var server = createHttpServer(port); - server.createContext("/receiver", new ReceiverHandler()); - server.setExecutor(null); - server.start(); - System.out.println("server started at " + port); - } - - private static HttpServer createHttpServer(int port) { - try { - return HttpServer.create(new InetSocketAddress(port), 0); - } catch (IOException e) { - throw new RuntimeException("Unable to start server at port " + port, e); - } - } -} diff --git a/examples/edc-example/edc/consumer-pull-backend-service/src/main/java/org/eclipse/edc/handler/ReceiverHandler.java b/examples/edc-example/edc/consumer-pull-backend-service/src/main/java/org/eclipse/edc/handler/ReceiverHandler.java deleted file mode 100644 index 4a5499fa..00000000 --- a/examples/edc-example/edc/consumer-pull-backend-service/src/main/java/org/eclipse/edc/handler/ReceiverHandler.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation - * - */ - -package org.eclipse.edc.handler; - -import com.sun.net.httpserver.HttpExchange; -import com.sun.net.httpserver.HttpHandler; - -import java.io.IOException; - -public class ReceiverHandler implements HttpHandler { - - /** - * This method just prints the request body to the console and returns a 200 OK response. - */ - @Override - public void handle(HttpExchange exchange) throws IOException { - System.out.println("Request Body: " + new String(exchange.getRequestBody().readAllBytes())); - exchange.sendResponseHeaders(200, 0); - } -} diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/checksums.lock b/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/checksums.lock deleted file mode 100644 index a18f5ea3..00000000 Binary files a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/checksums.lock and /dev/null differ diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/md5-checksums.bin b/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/md5-checksums.bin deleted file mode 100644 index d415ae92..00000000 Binary files a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/md5-checksums.bin and /dev/null differ diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/sha1-checksums.bin b/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/sha1-checksums.bin deleted file mode 100644 index 10c9e0e4..00000000 Binary files a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/checksums/sha1-checksums.bin and /dev/null differ diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/fileChanges/last-build.bin b/examples/edc-example/edc/http-pull-connector/.gradle/8.13/fileChanges/last-build.bin deleted file mode 100644 index f76dd238..00000000 Binary files a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/fileChanges/last-build.bin and /dev/null differ diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/fileHashes/fileHashes.lock b/examples/edc-example/edc/http-pull-connector/.gradle/8.13/fileHashes/fileHashes.lock deleted file mode 100644 index 0dda8538..00000000 Binary files a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/fileHashes/fileHashes.lock and /dev/null differ diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/8.13/gc.properties b/examples/edc-example/edc/http-pull-connector/.gradle/8.13/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/examples/edc-example/edc/http-pull-connector/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index 677c45b1..00000000 Binary files a/examples/edc-example/edc/http-pull-connector/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/buildOutputCleanup/cache.properties b/examples/edc-example/edc/http-pull-connector/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index 55a8ec89..00000000 --- a/examples/edc-example/edc/http-pull-connector/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon Jul 07 17:24:30 CEST 2025 -gradle.version=8.13 diff --git a/examples/edc-example/edc/http-pull-connector/.gradle/vcs-1/gc.properties b/examples/edc-example/edc/http-pull-connector/.gradle/vcs-1/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/examples/edc-example/edc/http-pull-connector/build.gradle.kts b/examples/edc-example/edc/http-pull-connector/build.gradle.kts deleted file mode 100644 index d75a45f7..00000000 --- a/examples/edc-example/edc/http-pull-connector/build.gradle.kts +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2022 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * - * This program and the accompanying materials are made available under the - * terms of the Apache License, Version 2.0 which is available at - * https://www.apache.org/licenses/LICENSE-2.0 - * - * SPDX-License-Identifier: Apache-2.0 - * - * Contributors: - * Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - initial API and implementation - * - */ - -plugins { - `java-library` - id("application") - id("com.github.johnrengelman.shadow") version "8.1.1" -} - -dependencies { - implementation(libs.edc.control.plane.core) - implementation(libs.edc.dsp) - implementation(libs.edc.configuration.filesystem) - implementation(libs.edc.vault.filesystem) - implementation(libs.edc.iam.mock) - implementation(libs.edc.management.api) - implementation(libs.edc.transfer.data.plane) - implementation(libs.edc.transfer.pull.http.receiver) - - implementation(libs.edc.data.plane.selector.api) - implementation(libs.edc.data.plane.selector.core) - implementation(libs.edc.data.plane.selector.client) - - implementation(libs.edc.data.plane.api) - implementation(libs.edc.data.plane.core) - implementation(libs.edc.data.plane.http) -} - -application { - mainClass.set("$group.boot.system.runtime.BaseRuntime") -} - -var distTar = tasks.getByName("distTar") -var distZip = tasks.getByName("distZip") - -tasks.withType { - mergeServiceFiles() - archiveFileName.set("pull-connector.jar") - dependsOn(distTar, distZip) -} diff --git a/examples/edc-example/edc/http-pull-consumer/consumer-configuration.properties b/examples/edc-example/edc/http-pull-consumer/consumer-configuration.properties deleted file mode 100644 index 64a00dc6..00000000 --- a/examples/edc-example/edc/http-pull-consumer/consumer-configuration.properties +++ /dev/null @@ -1,19 +0,0 @@ -edc.participant.id=consumer -edc.ids.id=urn:connector:consumer -edc.dsp.callback.address=http://localhost:29194/protocol -web.http.port=29191 -web.http.path=/api -web.http.management.port=29193 -web.http.management.path=/management -web.http.protocol.port=29194 -web.http.protocol.path=/protocol -edc.receiver.http.endpoint=http://localhost:4000/receiver/urn:connector:provider/callback -edc.public.key.alias=public-key -edc.transfer.dataplane.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.verifier.publickey.alias=public-key -web.http.public.port=29291 -web.http.public.path=/public -web.http.control.port=29192 -web.http.control.path=/control -edc.dataplane.token.validation.endpoint=http://localhost:29192/control/token diff --git a/examples/edc-example/edc/http-pull-consumer/consumer-vault.properties b/examples/edc-example/edc/http-pull-consumer/consumer-vault.properties deleted file mode 100644 index 6ebdebd5..00000000 --- a/examples/edc-example/edc/http-pull-consumer/consumer-vault.properties +++ /dev/null @@ -1 +0,0 @@ -public-key=-----BEGIN CERTIFICATE-----\r\nMIIDazCCAlOgAwIBAgIUZ3/sZXYzW4PjmOXKrZn6WBmUJ+4wDQYJKoZIhvcNAQEL\r\nBQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM\r\nGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAyMjMxNTA2MDNaFw0zMjAy\r\nMjExNTA2MDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw\r\nHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB\r\nAQUAA4IBDwAwggEKAoIBAQDBl6XaJnXTL+6DWip3aBhU+MzmY4d1V9hbTm1tiZ3g\r\nE0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7EddidN0ITHB9cQNdAfdUJ5njmsGS\r\nPbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7DHacZT/+OztBH1RwkG2ymM94Hf8H\r\nI6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvjX5qASakBtXISKIsOU84N0/2HDN3W\r\nEGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga775bPXN3M+JTSaIKE7dZbKzvx0Zi0\r\nh5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2YmnneYoVAgMBAAGjUzBRMB0GA1Ud\r\nDgQWBBTvK1wVERwjni4B2vdH7KtEJeVWFzAfBgNVHSMEGDAWgBTvK1wVERwjni4B\r\n2vdH7KtEJeVWFzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBn\r\nQHiPA7OBYukHd9gS7c0HXE+fsWcS3GZeLqcHfQQnV3pte1vTmu9//IVW71wNCJ1/\r\nrySRyODPQoPehxEcyHwupNZSzXK//nPlTdSgjMfFxscvt1YndyQLQYCfyOJMixAe\r\nAqrb14GTFHUUrdor0PyElhkULjkOXUrSIsdBrfWrwLTkelE8NK3tb5ZG8KPzD9Jy\r\n+NwEPPr9d+iHkUkM7EFWw/cl56wka9ryBb97RI7DqbO6/j6OXHMk4GByxKv7DSIR\r\nIvF9/Dw20qytajtaHV0pluFcOBuFc0NfiDvCaQlbTsfjzbc6UmZWbOi9YOJl3VQ/\r\ng3h+15GuzbsSzOCOEYOT\r\n-----END CERTIFICATE----- diff --git a/examples/edc-example/edc/http-pull-provider/provider-configuration.properties b/examples/edc-example/edc/http-pull-provider/provider-configuration.properties deleted file mode 100644 index 7e1c5001..00000000 --- a/examples/edc-example/edc/http-pull-provider/provider-configuration.properties +++ /dev/null @@ -1,20 +0,0 @@ -edc.participant.id=provider -edc.ids.id=urn:connector:provider -edc.dsp.callback.address=http://localhost:19194/protocol -web.http.port=19191 -web.http.path=/api -web.http.management.port=19193 -web.http.management.path=/management -web.http.protocol.port=19194 -web.http.protocol.path=/protocol -# todo change to runtime-1 -edc.receiver.http.endpoint=http://localhost:4000/receiver/urn:connector:provider/callback -edc.public.key.alias=public-key -edc.transfer.dataplane.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.signer.privatekey.alias=1 -edc.transfer.proxy.token.verifier.publickey.alias=public-key -web.http.public.port=19291 -web.http.public.path=/public -web.http.control.port=19192 -web.http.control.path=/control -edc.dataplane.token.validation.endpoint=http://localhost:19192/control/token diff --git a/examples/edc-example/edc/http-pull-provider/provider-vault.properties b/examples/edc-example/edc/http-pull-provider/provider-vault.properties deleted file mode 100644 index 6ebdebd5..00000000 --- a/examples/edc-example/edc/http-pull-provider/provider-vault.properties +++ /dev/null @@ -1 +0,0 @@ -public-key=-----BEGIN CERTIFICATE-----\r\nMIIDazCCAlOgAwIBAgIUZ3/sZXYzW4PjmOXKrZn6WBmUJ+4wDQYJKoZIhvcNAQEL\r\nBQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM\r\nGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yMjAyMjMxNTA2MDNaFw0zMjAy\r\nMjExNTA2MDNaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw\r\nHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggEiMA0GCSqGSIb3DQEB\r\nAQUAA4IBDwAwggEKAoIBAQDBl6XaJnXTL+6DWip3aBhU+MzmY4d1V9hbTm1tiZ3g\r\nE0VbUrvGO3LoYaxpPv6zFmsg3uJv6JxVAde7EddidN0ITHB9cQNdAfdUJ5njmsGS\r\nPbdQuOQTHw0aG7/QvTI/nsvfEE6e0lbV/0e7DHacZT/+OztBH1RwkG2ymM94Hf8H\r\nI6x7q6yfRTAZOqeOMrPCYTcluAgE9NskoPvjX5qASakBtXISKIsOU84N0/2HDN3W\r\nEGMXvoHUQu6vrij6BwiwxKaw1AKwWENKoga775bPXN3M+JTSaIKE7dZbKzvx0Zi0\r\nh5X+bxc3BJi3Z/CsUBCzE+Y0SFetOiYmyl/2YmnneYoVAgMBAAGjUzBRMB0GA1Ud\r\nDgQWBBTvK1wVERwjni4B2vdH7KtEJeVWFzAfBgNVHSMEGDAWgBTvK1wVERwjni4B\r\n2vdH7KtEJeVWFzAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBn\r\nQHiPA7OBYukHd9gS7c0HXE+fsWcS3GZeLqcHfQQnV3pte1vTmu9//IVW71wNCJ1/\r\nrySRyODPQoPehxEcyHwupNZSzXK//nPlTdSgjMfFxscvt1YndyQLQYCfyOJMixAe\r\nAqrb14GTFHUUrdor0PyElhkULjkOXUrSIsdBrfWrwLTkelE8NK3tb5ZG8KPzD9Jy\r\n+NwEPPr9d+iHkUkM7EFWw/cl56wka9ryBb97RI7DqbO6/j6OXHMk4GByxKv7DSIR\r\nIvF9/Dw20qytajtaHV0pluFcOBuFc0NfiDvCaQlbTsfjzbc6UmZWbOi9YOJl3VQ/\r\ng3h+15GuzbsSzOCOEYOT\r\n-----END CERTIFICATE----- diff --git a/knowledge-directory/src/main/resources/openapi-kd.yaml b/knowledge-directory/src/main/resources/openapi-kd.yaml index 64fa9d95..2c33e485 100644 --- a/knowledge-directory/src/main/resources/openapi-kd.yaml +++ b/knowledge-directory/src/main/resources/openapi-kd.yaml @@ -143,9 +143,15 @@ components: lastRenew: type: string format: date-time + edcParticipantId: + type: string + format: uri edcConnectorUrl: type: string format: uri + edcDataPlaneUrl: + type: string + format: uri required: - exposedUrl - protocolVersion diff --git a/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java b/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java index 17f7f7d9..e7b3eede 100644 --- a/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java +++ b/smart-connector-api/src/main/java/eu/knowledge/engine/smartconnector/api/SmartConnectorConfig.java @@ -63,6 +63,12 @@ public class SmartConnectorConfig { * Key to configure if a KER should use the EDC functionality or not. */ public static final String CONF_KEY_KE_RUNTIME_USE_EDC = "ke.runtime.use.edc"; + + /** + * Key to configure the EDC participant ID for this KER, matching the participant ID + * of its control plane and identity hub. + */ + public static final String CONF_KEY_KE_EDC_PARTICIPANT_ID = "ke.edc.participant.id"; /** * Key to configure where a KER can reach the protocol API of its own control plane if using EDC. @@ -74,20 +80,10 @@ public class SmartConnectorConfig { */ public static final String CONF_KEY_KE_EDC_MANAGEMENT_URL = "ke.edc.management.url"; - /** - * Key to configure where a KER can reach its data plane control API if using EDC. - */ - public static final String CONF_KEY_KE_EDC_DATAPLANE_CONTROL_URL = "ke.edc.dataplane.control.url"; - /** * Key to configure where a KER can reach its data plane public API if using EDC. */ public static final String CONF_KEY_KE_EDC_DATAPLANE_PUBLIC_URL = "ke.edc.dataplane.public.url"; - - /** - * Key to configure the URL where a KER can do token validation through the control plane if using EDC. - */ - public static final String CONF_KEY_KE_EDC_TOKEN_VALIDATION_ENDPOINT = "ke.edc.token.validation.endpoint"; /** * Key to configure the default reasoner level (1-5) that is used in the current diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorClient.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorClient.java deleted file mode 100644 index af8ae96c..00000000 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorClient.java +++ /dev/null @@ -1,313 +0,0 @@ -package eu.knowledge.engine.smartconnector.edc; - -import org.awaitility.Awaitility; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.time.Duration; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.concurrent.Executors; - -import static eu.knowledge.engine.smartconnector.edc.JsonUtil.findByJsonPointerExpression; - -public class EdcConnectorClient { - - private final Logger log = LoggerFactory.getLogger(EdcConnectorClient.class); - private final String edcConnectorManagementUrl; - private final HttpClient httpClient; - - public EdcConnectorClient(String edcConnectorManagementUrl) { - this.edcConnectorManagementUrl = edcConnectorManagementUrl; - var executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - this.httpClient = HttpClient.newBuilder().executor(executorService).build(); - } - - /** - * Each TKE needs to register a dataplane whenever it wants to expose assets. - * This function registers a data plane for HttpProxy/HttpData. - */ - public String registerDataPlane(String dataPlaneId, String dataPlaneControlUrl, String dataPlanePublicUrl) { - var url = getManagementUrl("/v2/dataplanes"); - log.info("registerDataPlane at: {}", url); - var payload = """ - { - "@context": { - "edc": "https://w3id.org/edc/v0.0.1/ns/" - }, - "@id": "%s", - "url": "%s", - "allowedSourceTypes": [ - "HttpData" - ], - "allowedDestTypes": [ - "HttpProxy", - "HttpData" - ], - "properties": { - "https://w3id.org/edc/v0.0.1/ns/publicApiUrl": "%s" - } - } - """.formatted(dataPlaneId, dataPlaneControlUrl, dataPlanePublicUrl); - HttpResponse response = httpPost(url, payload); - log.info("Register data plane response: {}", response.body()); - return response.body(); - } - - /** - * Register an assert given the provided assetId and tkeUrl. - */ - public String registerAsset(String assetId, String tkeUrl, String tkeAssetName) { - var url = getManagementUrl("/v3/assets"); - log.info("registerAsset at: {}", url); - var payload = """ - { - "@context": { - "@vocab" : "https://w3id.org/edc/v0.0.1/ns/" - }, - "@id": "%s", - "properties": { - "name": "%s", - "contenttype": "application/json" - }, - "dataAddress": { - "type": "HttpData", - "name": "%s", - "baseUrl": "%s", - "proxyPath": "true" - } - } - """.formatted(assetId, tkeAssetName, tkeAssetName, tkeUrl); - HttpResponse response = httpPost(url, payload); - log.info("Register asset response: {}", response.body()); - return response.body(); - } - - /** - * The policy defines permissions which can be applied to an asset. - * - * @return - */ - public String registerPolicy(String policyId) { - var url = getManagementUrl("/v2/policydefinitions"); - log.info("getManagementUrl at: {}", url); - - var payload = """ - { - "@context": { - "edc": "https://w3id.org/edc/v0.0.1/ns/", - "odrl": "http://www.w3.org/ns/odrl/2/" - }, - "@id": "%s", - "policy": { - "@type": "set", - "odrl:permission": [], - "odrl:prohibition": [], - "odrl:obligation": [] - } - } - """.formatted(policyId); - HttpResponse response = httpPost(url, payload); - log.info("Register policy response: {}", response.body()); - return response.body(); - } - - public String registerContractDefinition(String contractDefinitionId, String accessPolicyId, String contractPolicyId) { - var url = getManagementUrl("/v2/contractdefinitions"); - log.info("registerContractDefinition at: {}", url); - var payload = """ - { - "@context": { - "edc": "https://w3id.org/edc/v0.0.1/ns/" - }, - "@id": "%s", - "accessPolicyId": "%s", - "contractPolicyId": "%s", - "assetsSelector": [] - } - """.formatted(contractDefinitionId, accessPolicyId, contractPolicyId); - HttpResponse response = httpPost(url, payload); - log.info("Register contract definition response: {}", response.body()); - return response.body(); - } - - /** - * Catalog requests are sent to ones own connector. - * - * @param counterPartyAddress - * @return - */ - public String catalogRequest(String counterPartyAddress) { - var url = getManagementUrl("/v2/catalog/request"); - log.info("catalogRequest at: {}", url); - var payload = """ - { - "@context": { - "@vocab": "https://w3id.org/edc/v0.0.1/ns/" - }, - "counterPartyAddress": "%s", - "protocol": "dataspace-protocol-http" - } - """.formatted(counterPartyAddress); - HttpResponse postResponse = httpPost(url, payload); - log.info("Catalog request response: {}", postResponse.body()); - return postResponse.body(); - } - - /** - * In order to request any data, a contract gets negotiated, and an agreement is resulting has to be negotiated between providers and consumers. - *

- * The consumer now needs to initiate a contract negotiation sequence with the provider. That sequence looks as follows: - *

- * Consumer sends a contract offer to the provider (currently, this has to be equal to the provider's offer!) - * Provider validates the received offer against its own offer - * Provider either sends an agreement or a rejection, depending on the validation result - * In case of successful validation, provider and consumer store the received agreement for later reference - * - * @return - */ - public String negotiateContract(String consumerParticipantId, String providerParticipantId, String counterPartyAddress, String assetId) { - var catalogRequest = catalogRequest(counterPartyAddress); - String catalogOfferIdForAsset = findByJsonPointerExpression(catalogRequest, "/dcat:dataset/odrl:hasPolicy/@id"); - - var url = getManagementUrl("/v2/contractnegotiations"); - log.info("negotiateContract at: {}", url); - var payload = """ - { - "@context": { - "@vocab": "https://w3id.org/edc/v0.0.1/ns/" - }, - "@type": "NegotiationInitiateRequestDto", - "consumerId": "%s", - "connectorId": "%s", - "providerId": "%s", - "counterPartyAddress": "%s", - "protocol": "dataspace-protocol-http", - "policy": { - "@context": "http://www.w3.org/ns/odrl.jsonld", - "@id": "%s", - "@type": "Set", - "permission": [], - "prohibition": [], - "obligation": [], - "target": "%s" - } - } - """.formatted(consumerParticipantId, providerParticipantId, providerParticipantId, counterPartyAddress, catalogOfferIdForAsset, assetId); - - HttpResponse postResponse = httpPost(url, payload); - log.info("Negotiate contract response: {}", postResponse.body()); - return postResponse.body(); - } - - public String contractAgreement(String json) { - String contractAgreementId = findByJsonPointerExpression(json, "/@id"); - var url = getManagementUrl("/v2/contractnegotiations/" + contractAgreementId); - log.info("contractAgreement at: {}", url); - final List responses = new ArrayList<>(); - - Awaitility.await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(10)).until(() -> { - HttpResponse response = httpGet(url); - responses.add(response.body()); - String state = findByJsonPointerExpression(response.body(), "/state"); - return Objects.equals(state, "FINALIZED"); - }); - - return responses.get(responses.size() - 1); - } - - public String transferProcess(String counterPartyAddress, String counterPartyParticipantId, String contractAgreementId, String assetId) { - var url = getManagementUrl("/v2/transferprocesses"); - log.info("transferProcess at: {}", url); - var payload = """ - { - "@context": { - "@vocab": "https://w3id.org/edc/v0.0.1/ns/" - }, - "@type": "TransferRequestDto", - "counterPartyAddress": "%s", - "connectorId": "%s", - "contractId": "%s", - "assetId": "%s", - "protocol": "dataspace-protocol-http", - "dataDestination": { - "type": "HttpProxy" - } - } - """.formatted(counterPartyAddress, counterPartyParticipantId, contractAgreementId, assetId); - HttpResponse postResponse = httpPost(url, payload); - log.info("Transfer process response: {}", postResponse.body()); - return postResponse.body(); - } - - /** - * Contract the EDC connector URL for the /management endpoint. - */ - private String getManagementUrl(String suffix) { - return edcConnectorManagementUrl + suffix; - } - - private HttpResponse httpGet(String url) { - return httpGet(url, "application/json"); - } - - private HttpResponse httpGet(String url, String accept) { - log.info("Calling: {}", url); - - HttpRequest request = HttpRequest.newBuilder() - .uri(toURI(url)) - .headers("Accept", accept) - .GET() - .build(); - - return sendRequest(request); - } - - private HttpResponse httpPost(String url, String payload) { - return httpPost(url, "application/json", payload); - } - - private HttpResponse httpPost(String url, String contentType, String payload) { - log.info("Calling: {}, Payload: {}", url, payload); - - HttpRequest request = HttpRequest.newBuilder() - .uri(toURI(url)) - .headers("Content-Type", contentType) - .POST(HttpRequest.BodyPublishers.ofString(payload)) - .build(); - - return sendRequest(request); - } - - private HttpResponse sendRequest(HttpRequest request) { - try { - HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); - int statusCode = response.statusCode(); - - if (statusCode >= 200 && statusCode <= 299) { - return response; - } else if (response.statusCode() >= 400 && statusCode <= 499) { - throw new RuntimeException("HttpClient exception, request failed with statusCode: " + statusCode + ", response: " + response.body()); - } else if (response.statusCode() >= 500) { - throw new RuntimeException("HttpServer exception, request failed with statusCode: " + statusCode + ", response: " + response.body()); - } - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } - return null; - } - - private URI toURI(String url) { - try { - return new URI(url); - } catch (Exception e) { - throw new RuntimeException(e.getMessage(), e); - } - } - -} \ No newline at end of file diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorProperties.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorProperties.java deleted file mode 100644 index 07fc7c72..00000000 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorProperties.java +++ /dev/null @@ -1,19 +0,0 @@ -package eu.knowledge.engine.smartconnector.edc; - -public record EdcConnectorProperties(String participantId, String protocolUrl, String managementUrl, String dataPlaneId, - String dataPlaneControlUrl, String dataPlanePublicUrl, String tokenValidationEndpoint, String tkeAssetUrl, String tkeAssetName) { - - public EdcConnectorProperties(String participantId, String protocolUrl) { - this( - participantId, - protocolUrl, - "", - "tke-dataplane", - "", - "", - "", - "https://www.knowledge-engine.eu/", - "TNO Knowledge Engine Runtime" - ); - } -} \ No newline at end of file diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorService.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorService.java index d4ccc7ac..7c2059dd 100644 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorService.java +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/EdcConnectorService.java @@ -2,13 +2,29 @@ import jakarta.inject.Inject; import jakarta.inject.Named; + +import org.awaitility.Awaitility; +import org.eclipse.microprofile.config.Config; +import org.eclipse.microprofile.config.ConfigProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import eu.knowledge.engine.smartconnector.api.SmartConnectorConfig; + +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; +import java.util.concurrent.Executors; + +import static eu.knowledge.engine.smartconnector.edc.JsonUtil.findByJsonPointerExpression; /** * The EdcConnectorService can manage all the configuration of and @@ -18,72 +34,218 @@ @Named public class EdcConnectorService { - private final Logger log = LoggerFactory.getLogger(EdcConnectorService.class); - private final Map connectors = new HashMap<>(); - private final Map configuration = new HashMap<>(); + private final Logger LOG = LoggerFactory.getLogger(EdcConnectorService.class); + + private final HttpClient httpClient; + private Map participants = new HashMap<>(); - // these are all static for every connector - public final static String DATA_PLANE_ID = "tke-dataplane"; - public final static String ASSET_NAME = "TNO Knowledge Engine Runtime"; - public final static String ASSET_URL = "https://www.knowledge-engine.eu/"; + private final URI managementUrl; + private final ParticipantProperties myProperties; + + // KER properties + private URI assetUrl; + private String assetName = "TNO Knowledge Engine Runtime API"; @Inject - public EdcConnectorService(List configuration) { - for (EdcConnectorProperties connector : configuration) { - addConnector(connector); - } + public EdcConnectorService(URI assetUrl) { + Config config = ConfigProvider.getConfig(); + + this.managementUrl = toURI(config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_MANAGEMENT_URL).getValue()); + URI configParticipantId = toURI(config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_PARTICIPANT_ID).getValue()); + URI configProtocolUrl = toURI(config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_PROTOCOL_URL).getValue()); + URI configDataPlanePublicUrl = toURI(config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_DATAPLANE_PUBLIC_URL).getValue()); + this.myProperties = new ParticipantProperties(configParticipantId, configProtocolUrl, configDataPlanePublicUrl); + this.assetUrl = assetUrl; + + LOG.info("Adding connector for [participant id: {}] with [management url: {}]", + this.myProperties.participantId(), this.managementUrl); + var executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + this.httpClient = HttpClient.newBuilder().executor(executorService).build(); + this.participants.put(this.myProperties.participantId(), + new ParticipantProperties(this.myProperties.participantId(), this.myProperties.protocolUrl(), this.myProperties.dataPlanePublicUrl())); } - public void addConnector(EdcConnectorProperties connector) { - log.info("Adding connector for [participant id: {}] with [management url: {}]", - connector.participantId(), connector.managementUrl()); - connectors.put(connector.participantId(), new EdcConnectorClient(connector.managementUrl())); - configuration.put(connector.participantId(), connector); + public void registerParticipant(ParticipantProperties participant) { + LOG.info("Registering EDC participant with participant id {}", participant.participantId()); + participants.put(participant.participantId(), participant); } /** - * Configure the connector with the provided connector's participantId - * - * @param participantId connector to configure + * Configure the connector. * @return map with all the responses */ - public HashMap configureConnector(String participantId) { - log.info("configureConnector for participantId: {}", participantId); - EdcConnectorProperties properties = configuration.get(participantId); - EdcConnectorClient connector = connectors.get(participantId); - - String existingAssetId = getAssetIdFromCatalogForAssetName(properties.participantId(), - properties.participantId(), properties.tkeAssetName()); - if (existingAssetId != null) { - log.info("Connector already configured and TKE asset present for participantId: {}", participantId); - throw new RuntimeException("Connector already configured and TKE asset present."); - } + public void configureConnector() { + LOG.info("configuring connector of {}", this.myProperties.participantId()); + String assetId = UUID.randomUUID().toString(); + String policyId = UUID.randomUUID().toString(); + String contractId = UUID.randomUUID().toString(); - // properties needed when creating a data plane. - var dataPlaneId = EdcConnectorService.DATA_PLANE_ID; - var dataPlaneControlUrl = properties.dataPlaneControlUrl(); - var dataPlanePublicUrl = properties.dataPlanePublicUrl(); - // properties needed when creating an asset. - var assetId = UUID.randomUUID().toString(); // generate an unique assetId - var tkeAssetUrl = EdcConnectorService.ASSET_URL; - var tkeAssetName = EdcConnectorService.ASSET_NAME; - // properties needed when creating a policy and contract definition. - var policyId = UUID.randomUUID().toString(); - var contractId = UUID.randomUUID().toString(); - - // Create the mandatory edc resources. - var map = new HashMap(); - map.put("registerDataPlane", connector.registerDataPlane(dataPlaneId, dataPlaneControlUrl, dataPlanePublicUrl)); - map.put("registerPolicy", connector.registerPolicy(policyId)); - map.put("registerAsset", connector.registerAsset(assetId, tkeAssetUrl, tkeAssetName)); - map.put("registerContractDefinition", connector.registerContractDefinition(contractId, policyId, policyId)); - return map; - } - - public String getAssetIdFromCatalogForAssetName(String participantId, String counterPartyParticipantId, - String assetName) { - String response = catalogRequest(participantId, counterPartyParticipantId); - return JsonUtil.findByJsonPointerExpression(response, "/dcat:dataset/@id"); + LOG.info("Registering KER API asset"); + this.registerAsset(assetId, this.assetUrl, this.assetName); + LOG.info("Registering Policy"); + this.registerPolicy(policyId); + LOG.info("Registering Contract Definition"); + this.registerContractDefinition(contractId, policyId, policyId, assetId); + } + + + /** + * Create and start a transfer process with another participant by + * requesting their catalog, setting up a contract agreement and starting + * the actual transfer process. + * + * @param counterPartyParticipantId the participant ID of the counter party + * + * @return the started transfer process + */ + public TransferProcess createTransferProcess(URI counterPartyParticipantId) { + ParticipantProperties counterParty = participants.get(counterPartyParticipantId); + String catalogJson = catalogRequest(counterParty); + String assetId = findByJsonPointerExpression(catalogJson, "/dcat:dataset/@id"); + String policyId = findByJsonPointerExpression(catalogJson, "/dcat:dataset/odrl:hasPolicy/@id"); + String contractAgreementId = negotiateContract(counterParty, assetId, policyId); + String transferId = transferProcess(counterParty, contractAgreementId); + String edrsJson = getEndpointDataReference(transferId); + + String authToken = findByJsonPointerExpression(edrsJson, "/authorization"); + String counterPartyDataPlaneUrl = findByJsonPointerExpression(edrsJson, "/endpoint"); + LOG.info("EDC Data Transfer with Remote KER {} started with Contract Agreement Id: {} and Transfer Id: {}", + counterPartyParticipantId, contractAgreementId, transferId); + return new TransferProcess(this.myProperties.participantId(), counterPartyParticipantId, contractAgreementId, counterPartyDataPlaneUrl, authToken); + } + + + /** + * Negotiate a contract between two connectors for the provided asset + * identifier. + * + * @param counterParty participant to whom the request should be made + * @param assetId describes what asset the participant wants to use + * @param policyId describes the policy assigned to the counterparty's asset + * + * @return contract agreement ID + */ + private String negotiateContract(ParticipantProperties counterParty, String assetId, String policyId) { + // Send contract agreement request + String url = getManagementUrl("/v3/contractnegotiations"); + String payload = """ + { + "@context": { + "edc": "https://w3id.org/edc/v0.0.1/ns/", + "odrl": "http://www.w3.org/ns/odrl/2/" + }, + "@type": "ContractRequest", + "counterPartyAddress": "%s", + "protocol": "dataspace-protocol-http", + "policy": { + "@context": "http://www.w3.org/ns/odrl.jsonld", + "@id": "%s", + "@type": "Offer", + "assigner": "%s", + "target": "%s" + } + } + """.formatted(counterParty.protocolUrl(), policyId, counterParty.participantId(), assetId); + + LOG.info("Negotiate contract at: {}, Request: {}", url, payload); + HttpResponse postResponse = httpPost(url, payload); + + LOG.info("Negotiate contract response: {}", postResponse.body()); + + String contractAgreementId = findByJsonPointerExpression(postResponse.body(), "/@id"); + + // Poll for contract agreement finalization and return + String url_with_id = getManagementUrl("/v3/contractnegotiations/" + contractAgreementId); + LOG.info("contractAgreement at: {}", url_with_id); + + final List responses = new ArrayList<>(); + Awaitility.await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(10)).until(() -> { + HttpResponse response = httpGet(url_with_id); + responses.add(response.body()); + String state = findByJsonPointerExpression(response.body(), "/state"); + LOG.error(state); + return Objects.equals(state, "FINALIZED"); + }); + + return contractAgreementId; + } + + private String registerAsset(String assetId, URI tkeUrl, String tkeAssetName) { + String url = getManagementUrl("/v3/assets"); + String payload = """ + { + "@context": [ + "https://w3id.org/edc/connector/management/v0.0.1" + ], + "@id": "%s", + "properties": { + "name": "%s", + "contenttype": "application/json" + }, + "dataAddress": { + "type": "HttpData", + "name": "%s", + "baseUrl": "%s", + "proxyMethod": "true", + "proxyPath": "true", + "proxyBody": "true" + } + } + """.formatted(assetId, tkeAssetName, tkeAssetName, tkeUrl); + LOG.info("Registering asset at: {}, Request: {}", url, payload); + HttpResponse response = httpPost(url, payload); + LOG.info("Registering asset response: {}", response.body()); + return response.body(); + } + + private String registerPolicy(String policyId) { + String url = getManagementUrl("/v3/policydefinitions"); + String payload = """ + { + "@context": { + "edc": "https://w3id.org/edc/v0.0.1/ns/", + "odrl": "http://www.w3.org/ns/odrl/2/" + }, + "@id": "%s", + "policy": { + "@context": "http://www.w3.org/ns/odrl.jsonld", + "@type": "Set", + "odrl:permission": [], + "odrl:prohibition": [], + "odrl:obligation": [] + } + } + """.formatted(policyId); + LOG.info("Registering policy at: {} Request: {}", url, payload); + HttpResponse response = httpPost(url, payload); + LOG.info("Registering policy response: {}", response.body()); + return response.body(); + } + + private String registerContractDefinition(String contractDefinitionId, String accessPolicyId, + String contractPolicyId, String assetId) { + String url = getManagementUrl("/v3/contractdefinitions"); + String payload = """ + { + "@context": { + "edc": "https://w3id.org/edc/v0.0.1/ns/" + }, + "@id": "%s", + "accessPolicyId": "%s", + "contractPolicyId": "%s", + "assetsSelector": [ + { + "operandLeft": "id", + "operator": "=", + "operandRight": "%s" + } + ] + } + """.formatted(contractDefinitionId, accessPolicyId, contractPolicyId, assetId); + LOG.info("Registering contract definition at: {} Request: {}", url, payload); + HttpResponse response = httpPost(url, payload); + LOG.info("Registering contract definition response: {}", response.body()); + return response.body(); } /** @@ -92,65 +254,132 @@ public String getAssetIdFromCatalogForAssetName(String participantId, String cou * what assets are provided by a connector. Asset identifiers can later be used * to negotiate contracts between parties. * - * @param participantId from which connector the request should be - * made * @param counterPartyParticipantId to whom the request should be make * @return response */ - public String catalogRequest(String participantId, String counterPartyParticipantId) { - log.info("catalogRequest for participantId: {}", participantId); - EdcConnectorClient connector = connectors.get(participantId); - EdcConnectorProperties counterPartyProperties = configuration.get( - counterPartyParticipantId); + private String catalogRequest(ParticipantProperties counterParty) { + LOG.info("Catalog request: {}", counterParty.participantId()); + String url = getManagementUrl("/v3/catalog/request"); + String payload = """ + { + "@context": { + "edc": "https://w3id.org/edc/v0.0.1/ns/" + }, + "counterPartyAddress": "%s", + "counterPartyId": "%s", + "protocol": "dataspace-protocol-http" + } + """.formatted(counterParty.protocolUrl(), counterParty.participantId()); + LOG.info("Requesting catalog at: {}, Request: {}", url, payload); + HttpResponse postResponse = httpPost(url, payload); + LOG.info("Requesting Catalog response: {}", postResponse.body()); + return postResponse.body(); + } + + + private String transferProcess(ParticipantProperties counterParty, String contractAgreementId) { + LOG.info("transferProcess for participantId: {}, counterPartyParticipantId: {}, contractAgreementId: {}", + this.myProperties.participantId(), counterParty.participantId(), contractAgreementId); - var counterPartyProtocolUrl = counterPartyProperties.protocolUrl(); - return connector.catalogRequest(counterPartyProtocolUrl); + var url = getManagementUrl("/v3/transferprocesses"); + var payload = """ + { + "@context": { + "@vocab": "https://w3id.org/edc/v0.0.1/ns/" + }, + "counterPartyAddress": "%s", + "contractId": "%s", + "protocol": "dataspace-protocol-http", + "transferType": "HttpData-PULL", + "dataDestination": { + "type": "HttpProxy" + } + } + """.formatted(counterParty.protocolUrl(), contractAgreementId); + LOG.info("Start transfer process at: {}, Request: {}", url, payload); + HttpResponse postResponse = httpPost(url, payload); + LOG.info("Start transfer process response: {}", postResponse.body()); + + String transferId = findByJsonPointerExpression(postResponse.body(), "/@id"); + + String url_with_id = getManagementUrl("/v3/transferprocesses/" + transferId); + final List responses = new ArrayList<>(); + + Awaitility.await().pollInterval(Duration.ofSeconds(1)).atMost(Duration.ofSeconds(10)).until(() -> { + HttpResponse response = httpGet(url_with_id); + responses.add(response.body()); + String state = findByJsonPointerExpression(response.body(), "/state"); + LOG.error(state); + return Objects.equals(state, "STARTED"); + }); + + return transferId; + } + + private String getEndpointDataReference(String transferId) { + String url = getManagementUrl("/v3/edrs/" + transferId + "/dataaddress"); + LOG.info("Get endpoint data reference"); + HttpResponse response = httpGet(url); + LOG.info(response.body()); + return response.body(); } /** - * Negotiate a contract between two connectors for the provided asset - * identifier. - * - * @param participantId from which connector the request should be - * made - * @param counterPartyParticipantId to whom the request should be make - * @param assetId determines what asset the participant wants - * to use - * @return response + * Contract the EDC connector URL for the /management endpoint. */ - public String negotiateContract(String participantId, String counterPartyParticipantId, String assetId) { - log.info("negotiateContract for participantId: {}, counterPartyParticipantId: {}, assetId: {}", participantId, - counterPartyParticipantId, assetId); - EdcConnectorProperties participantProperties = configuration.get(participantId); - EdcConnectorProperties counterPartyProperties = configuration.get(counterPartyParticipantId); - EdcConnectorClient connector = connectors.get(participantId); - - // note that the counterparty protocol url could also be extract from the - // catalog request - var counterPartyAddress = counterPartyProperties.protocolUrl(); // dsp protocol address of the - // counterparty/provider - var consumerId = participantProperties.participantId(); - var providerId = counterPartyProperties.participantId(); - - // The consumer will negotiate a contract using its own connector, the - // counterPartyAddress - // is the party which we need to negotiate the contract with. - String negotiateContract = connector.negotiateContract(consumerId, providerId, counterPartyAddress, assetId); - return connector.contractAgreement(negotiateContract); - } - - public String transferProcess(String participantId, String counterPartyParticipantId, String contractAgreementId, - String assetId) { - log.info( - "transferProcess for participantId: {}, counterPartyParticipantId: {}, contractAgreementId: {}, assetId: {}", - participantId, counterPartyParticipantId, contractAgreementId, assetId); - EdcConnectorProperties counterPartyProperties = configuration.get(counterPartyParticipantId); - EdcConnectorClient connector = connectors.get(participantId); - - var counterPartyAddress = counterPartyProperties.protocolUrl(); // dsp protocol address of the - // counterparty/provider - var providerId = counterPartyProperties.participantId(); - - return connector.transferProcess(counterPartyAddress, providerId, contractAgreementId, assetId); + private String getManagementUrl(String suffix) { + return this.managementUrl + suffix; + } + + private HttpResponse httpGet(String url) { + HttpRequest request = HttpRequest.newBuilder() + .uri(toURI(url)) + .headers("Accept", "application/json") + .GET() + .build(); + + return sendRequest(request); + } + + private HttpResponse httpPost(String url, String payload) { + HttpRequest request = HttpRequest.newBuilder() + .uri(toURI(url)) + .headers("Content-Type", "application/json") + .POST(HttpRequest.BodyPublishers.ofString(payload)) + .build(); + + return sendRequest(request); + } + + private HttpResponse sendRequest(HttpRequest request) { + try { + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + int statusCode = response.statusCode(); + + if (statusCode >= 200 && statusCode <= 299) { + return response; + } else if (response.statusCode() >= 400 && statusCode <= 499) { + throw new RuntimeException("HttpClient exception, request failed with statusCode: " + statusCode + + ", response: " + response.body()); + } else if (response.statusCode() >= 500) { + throw new RuntimeException("HttpServer exception, request failed with statusCode: " + statusCode + + ", response: " + response.body()); + } + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + return null; + } + + private URI toURI(String url) { + try { + return new URI(url); + } catch (Exception e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + public ParticipantProperties getMyProperties() { + return this.myProperties; } } \ No newline at end of file diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/InMemoryTokenManager.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/InMemoryTokenManager.java deleted file mode 100644 index 6e8827ba..00000000 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/InMemoryTokenManager.java +++ /dev/null @@ -1,51 +0,0 @@ -package eu.knowledge.engine.smartconnector.edc; - -import jakarta.annotation.Nullable; -import jakarta.inject.Named; - -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; - -/** - * We store token data in memory here. - * For a production grade system it makes sense to store the data in a (persistent) datastore. - */ -@Named -public class InMemoryTokenManager { - - private final List tokens = new ArrayList<>(); - private final List transferProcessInitiations = new ArrayList<>(); - - public void tokenReceived(Token token) { - tokens.add(token); - } - - public List getTokensFor(@Nullable String participantId, @Nullable String counterPartyParticipantId) { - if (participantId == null && counterPartyParticipantId == null) { - return tokens; - } - - Stream transferProcessesStream = transferProcessInitiations.stream() - .filter((it) -> Objects.equals(it.participantId(), participantId)); - - if (counterPartyParticipantId != null) { - transferProcessesStream = transferProcessesStream.filter((it) -> Objects.equals(it.counterPartyParticipantId(), counterPartyParticipantId)); - } - - List transferProcessIds = transferProcessesStream.map(TransferProcess::transferProcessResponseId).toList(); - - // Get all the tokens belonging to the transferProcesses between participantId and counterPartyParticipantId - List list = transferProcessIds.stream() - .flatMap((transferProcessId) -> - tokens.stream().filter((token) -> Objects.equals(transferProcessId, token.id())) - ).toList(); - - return list; - } - - public void transferProcessInitiated(TransferProcess transferProcess) { - transferProcessInitiations.add(transferProcess); - } -} \ No newline at end of file diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/ParticipantProperties.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/ParticipantProperties.java new file mode 100644 index 00000000..fdbeb476 --- /dev/null +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/ParticipantProperties.java @@ -0,0 +1,7 @@ +package eu.knowledge.engine.smartconnector.edc; + +import java.net.URI; + +public record ParticipantProperties(URI participantId, URI protocolUrl, URI dataPlanePublicUrl) { + +} diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/Token.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/Token.java deleted file mode 100644 index c801e29f..00000000 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/Token.java +++ /dev/null @@ -1,17 +0,0 @@ -package eu.knowledge.engine.smartconnector.edc; - -import static eu.knowledge.engine.smartconnector.edc.JsonUtil.findByJsonPointerExpression; - -public record Token(String tokenJson, String id, String contractId, String authKey, String authCode, String endpoint) { - - public Token(String tokenJson) { - this( - tokenJson, - findByJsonPointerExpression(tokenJson, "/id"), - findByJsonPointerExpression(tokenJson, "/contractId"), - findByJsonPointerExpression(tokenJson, "/authKey"), - findByJsonPointerExpression(tokenJson, "/authCode"), - findByJsonPointerExpression(tokenJson, "/endpoint") - ); - } -} \ No newline at end of file diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/TransferProcess.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/TransferProcess.java index d5678754..e98487a6 100644 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/TransferProcess.java +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/edc/TransferProcess.java @@ -1,16 +1,8 @@ package eu.knowledge.engine.smartconnector.edc; -import static eu.knowledge.engine.smartconnector.edc.JsonUtil.findByJsonPointerExpression; +import java.net.URI; -public record TransferProcess(String participantId, String counterPartyParticipantId, String contractAgreementId, String responseJson, String transferProcessResponseId) { +public record TransferProcess(URI participantId, URI counterPartyParticipantId, String contractAgreementId, + String counterPartyDataPlaneUrl, String authToken) { - public TransferProcess(String participantId, String counterPartyParticipantId, String contractAgreementId, String responseJson) { - this( - participantId, - counterPartyParticipantId, - contractAgreementId, - contractAgreementId, - findByJsonPointerExpression(responseJson, "/@id") - ); - } } \ No newline at end of file diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java index cc6d8f29..97af2661 100644 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/KnowledgeDirectoryConnection.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import eu.knowledge.engine.smartconnector.edc.ParticipantProperties; import eu.knowledge.engine.smartconnector.runtime.KeRuntime; import eu.knowledge.engine.smartconnector.runtime.messaging.inter_ker.api.RFC3339DateFormat; import eu.knowledge.engine.smartconnector.runtime.messaging.kd.model.KnowledgeEngineRuntimeConnectionDetails; @@ -52,15 +53,15 @@ public static enum State { private State currentState; private final URI kdUrl; private final URI myExposedUrl; - private final URI myEdcConnectorUrl; + private final ParticipantProperties myEdcProperties; private final Object lock = new Object(); private ScheduledFuture scheduledFuture; - public KnowledgeDirectoryConnection(URI kdUrl, URI myExposedUrl, URI myEdcConnectorUrl) { + public KnowledgeDirectoryConnection(URI kdUrl, URI myExposedUrl, ParticipantProperties myEdcProperties) { this.myExposedUrl = myExposedUrl; - this.myEdcConnectorUrl = myEdcConnectorUrl; this.currentState = State.UNREGISTERED; + this.myEdcProperties = myEdcProperties; var builder = HttpClient.newBuilder(); @@ -192,7 +193,11 @@ private void tryRegister() { KnowledgeEngineRuntimeConnectionDetails ker = new KnowledgeEngineRuntimeConnectionDetails(); ker.setExposedUrl(myExposedUrl); ker.setProtocolVersion(PROTOCOL_VERSION); - ker.setEdcConnectorUrl(myEdcConnectorUrl); + if (this.myEdcProperties != null) { + ker.setEdcParticipantId(this.myEdcProperties.participantId()); + ker.setEdcConnectorUrl(this.myEdcProperties.protocolUrl()); + ker.setEdcDataPlaneUrl(this.myEdcProperties.dataPlanePublicUrl()); + } try { HttpRequest registerRequest = HttpRequest diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/MessageDispatcher.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/MessageDispatcher.java index 172cf173..771d2553 100644 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/MessageDispatcher.java +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/MessageDispatcher.java @@ -17,6 +17,7 @@ import org.slf4j.LoggerFactory; import eu.knowledge.engine.smartconnector.api.SmartConnector; +import eu.knowledge.engine.smartconnector.edc.ParticipantProperties; import eu.knowledge.engine.smartconnector.messaging.KnowledgeMessage; import eu.knowledge.engine.smartconnector.runtime.KeRuntime; import eu.knowledge.engine.smartconnector.runtime.KnowledgeDirectoryProxy; @@ -125,10 +126,12 @@ public void start() throws Exception { remoteSmartConnectorConnectionsManager = new RemoteKerConnectionManager(this, this.myExposedUrl, this.useEdc); getRemoteSmartConnectorConnectionsManager().start(); - URI myEdcConnectorUrl = remoteSmartConnectorConnectionsManager.getEdcConnectorUrl(); // Start Knowledge Directory Connection Manager - this.knowledgeDirectoryConnectionManager = new KnowledgeDirectoryConnection(kdUrl, myExposedUrl, myEdcConnectorUrl); - + ParticipantProperties edcProperties = null; + if (this.useEdc) + edcProperties = remoteSmartConnectorConnectionsManager.getMyEdcProperties(); + + this.knowledgeDirectoryConnectionManager = new KnowledgeDirectoryConnection(kdUrl, myExposedUrl, edcProperties); this.getKnowledgeDirectoryConnectionManager().start(); // Start HTTP Server diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnection.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnection.java index 98f58bf8..88c62433 100644 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnection.java +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnection.java @@ -1,9 +1,7 @@ package eu.knowledge.engine.smartconnector.runtime.messaging; import static eu.knowledge.engine.smartconnector.runtime.messaging.Utils.stripUserInfoFromURI; -import static eu.knowledge.engine.smartconnector.edc.JsonUtil.findByJsonPointerExpression; -import java.io.FileInputStream; import java.io.IOException; import java.net.Authenticator; import java.net.PasswordAuthentication; @@ -20,11 +18,8 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; -import java.util.Properties; -import org.eclipse.microprofile.config.Config; import org.eclipse.microprofile.config.ConfigProvider; -import org.eclipse.microprofile.config.ConfigValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,8 +37,7 @@ import eu.knowledge.engine.smartconnector.runtime.messaging.inter_ker.api.RFC3339DateFormat; import eu.knowledge.engine.smartconnector.runtime.messaging.inter_ker.model.KnowledgeEngineRuntimeDetails; import eu.knowledge.engine.smartconnector.runtime.messaging.kd.model.KnowledgeEngineRuntimeConnectionDetails; -import eu.knowledge.engine.smartconnector.edc.EdcConnectorService; -import eu.knowledge.engine.smartconnector.edc.InMemoryTokenManager; +import eu.knowledge.engine.smartconnector.edc.TransferProcess; /** * This class is responsible for sending messages to a single remote Knowledge @@ -54,10 +48,6 @@ public class RemoteKerConnection { public static final Logger LOG = LoggerFactory.getLogger(RemoteKerConnection.class); - private URI myExposedUri = null; - private EdcConnectorService edcService; - private InMemoryTokenManager tokenManager; - private final KnowledgeEngineRuntimeConnectionDetails remoteKerConnectionDetails; private final URI remoteKerUri; private KnowledgeEngineRuntimeDetails remoteKerDetails; @@ -70,36 +60,26 @@ public class RemoteKerConnection { private int errorCounter = 0; private LocalDateTime logStillIgnoringAfter = null; - // edc info - /** - * The transfer id of this KERs data transfer with this Remote KER. - */ - private String transferId; - - /** - * The contract agreement id this KERs EDC Connector agreed upon with this - * Remote KERs EDC Connector. - */ - private String contractAgreementId; + private TransferProcess transferProcess; - /** - * The authentication token which proves this KER has a valid EDC contract with - * this remote KER. - */ - private String authToken; - private String validationEndpoint; - - public RemoteKerConnection(MessageDispatcher dispatcher, URI myExposedUri, EdcConnectorService edcService, - InMemoryTokenManager tokenManager, KnowledgeEngineRuntimeConnectionDetails kerConnectionDetails) { - this.myExposedUri = myExposedUri; + public RemoteKerConnection(MessageDispatcher dispatcher, KnowledgeEngineRuntimeConnectionDetails kerConnectionDetails, + TransferProcess transferProcess) { this.dispatcher = dispatcher; this.remoteKerConnectionDetails = kerConnectionDetails; - this.edcService = edcService; - this.tokenManager = tokenManager; + this.transferProcess = transferProcess; var builder = HttpClient.newBuilder(); - if (kerConnectionDetails.getExposedUrl().getUserInfo() != null) { + if (this.transferProcess != null) { + URI uri = null; + try { + uri = new URI(this.transferProcess.counterPartyDataPlaneUrl()); + } catch (URISyntaxException e) { + LOG.error("ERROR: %s".formatted(e)); + } + this.remoteKerUri = uri; + } + else if (kerConnectionDetails.getExposedUrl().getUserInfo() != null) { this.remoteKerUri = stripUserInfoFromURI(kerConnectionDetails.getExposedUrl()); String[] userInfo = kerConnectionDetails.getExposedUrl().getUserInfo().split(":"); if (userInfo.length == 2) { @@ -127,34 +107,6 @@ protected PasswordAuthentication getPasswordAuthentication() { objectMapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS).findAndRegisterModules() .setDateFormat(new RFC3339DateFormat()); - - if (!(this.edcService == null || this.tokenManager == null)) { - Config config = ConfigProvider.getConfig(); - ConfigValue tokenValidationEndpoint = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_TOKEN_VALIDATION_ENDPOINT); - this.validationEndpoint = tokenValidationEndpoint.getValue(); - setupTransferProcess(); - } - } - - /** - * Make sure we have a valid authToken to communicate with the remote KER. This - * involves fetching their catalog, negotiating a contract, starting a transfer - * process and receiving the token. - */ - private void setupTransferProcess() { - String assetId = this.edcService.getAssetIdFromCatalogForAssetName(this.myExposedUri.toString(), - this.remoteKerUri.toString(), EdcConnectorService.ASSET_NAME); - String contractAgreementJson = this.edcService.negotiateContract(this.myExposedUri.toString(), - this.remoteKerUri.toString(), assetId); - - this.contractAgreementId = findByJsonPointerExpression(contractAgreementJson, "/contractAgreementId"); - - String transferJson = this.edcService.transferProcess(this.myExposedUri.toString(), - this.remoteKerUri.toString(), this.contractAgreementId, assetId); - this.transferId = findByJsonPointerExpression(transferJson, "/@id"); - - LOG.info("EDC Data Transfer with Remote KER {} started with Contract Agreement Id: {} and Transfer Id: {}", - this.remoteKerUri.toString(), this.contractAgreementId, this.transferId); } private int getHttpTimeout() { @@ -183,15 +135,11 @@ private int errorOccurred() { * {@link KnowledgeEngineRuntimeDetails} */ private void updateRemoteKerDataFromPeer() { - if (this.edcService != null && !tokenAvailable()) { - LOG.warn("No token available yet!"); - return; - } try { - HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(new URI(this.remoteKerUri + "/runtimedetails")) - .headers("Content-Type", "application/json"); - if (this.edcService != null) - requestBuilder = requestBuilder.setHeader("Authorization", authToken); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(new URI(this.remoteKerUri + "/runtimedetails")); + //.headers("Content-Type", "application/json"); + if (this.transferProcess != null) + requestBuilder = requestBuilder.setHeader("Authorization", this.transferProcess.authToken()); HttpRequest request = requestBuilder.GET().build(); HttpResponse response = this.httpClient.send(request, BodyHandlers.ofString()); @@ -221,10 +169,6 @@ private void updateRemoteKerDataFromPeer() { dispatcher.notifySmartConnectorsChanged(); } - private boolean tokenAvailable() { - return this.authToken != null; - } - public boolean isAvailable() { if (tryAgainAfter != null) { boolean after = LocalDateTime.now().isAfter(tryAgainAfter); @@ -300,17 +244,14 @@ public void start() { public void stop() { if (this.isAvailable()) { - if (this.edcService != null && !tokenAvailable()) { - LOG.warn("No token available yet!"); - return; - } try { String ker_id = URLEncoder.encode(dispatcher.getMyKnowledgeEngineRuntimeDetails().getRuntimeId(), StandardCharsets.UTF_8); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(new URI(this.remoteKerUri + "/runtimedetails/" + ker_id)) .headers("Content-Type", "application/json"); - if (this.edcService != null) - requestBuilder = requestBuilder.headers("Authorization", authToken); + if (this.transferProcess != null) + requestBuilder = requestBuilder.headers("Authorization", this.transferProcess.authToken()); HttpRequest request = requestBuilder.DELETE().build(); HttpResponse response = this.httpClient.send(request, BodyHandlers.ofString()); @@ -356,22 +297,19 @@ public void sendToRemoteSmartConnector(KnowledgeMessage message) throws IOExcept throw new IOException("KER " + this.remoteKerUri + " is currently unavailable. Trying again later."); } - if (this.edcService != null && !tokenAvailable()) { - LOG.warn("No token available yet!"); - return; - } - try { String jsonMessage = objectMapper.writeValueAsString(MessageConverter.toJson(message)); + HttpRequest.Builder requestBuilder = HttpRequest .newBuilder(new URI(this.remoteKerUri + getPathForMessageType(message))) .headers("Content-Type", "application/json"); - if (this.edcService != null) - requestBuilder = requestBuilder.setHeader("Authorization", authToken); + if (this.transferProcess != null) + requestBuilder = requestBuilder.setHeader("Authorization", this.transferProcess.authToken()); HttpRequest request = requestBuilder.POST(BodyPublishers.ofString(jsonMessage)).build(); HttpResponse response = this.httpClient.send(request, BodyHandlers.ofString()); - if (response.statusCode() == 202) { + // TODO -> Change 200 back to 202! + if (response.statusCode() == 200 || response.statusCode() == 202) { this.noError(); LOG.trace("Successfully sent message {} to {}", message.getMessageId(), this.remoteKerUri); } else { @@ -400,18 +338,14 @@ public void sendMyKerDetailsToPeer(KnowledgeEngineRuntimeDetails details) { return; } - if (this.edcService != null && !tokenAvailable()) { - LOG.warn("No token available yet!"); - return; - } - try { String jsonMessage = objectMapper.writeValueAsString(details); + HttpRequest.Builder requestBuilder = HttpRequest.newBuilder(new URI(this.remoteKerUri + "/runtimedetails")) .headers("Content-Type", "application/json"); - if (this.edcService != null) - requestBuilder = requestBuilder.headers("Authorization", authToken); + if (this.transferProcess != null) + requestBuilder = requestBuilder.headers("Authorization", this.transferProcess.authToken()); HttpRequest request = requestBuilder.POST(BodyPublishers.ofString(jsonMessage)).build(); HttpResponse response = this.httpClient.send(request, BodyHandlers.ofString()); @@ -467,44 +401,4 @@ public String getConfigProperty(String key, String defaultValue) { public boolean hasConfigProperty(String key) { return System.getenv(key) != null; } - - public boolean checkAuthorizationToken(String authorizationToken) { - if (validationEndpoint != null) { - LOG.info("Contacting validation endpoint {}", validationEndpoint); - HttpRequest request = null; - try { - request = HttpRequest.newBuilder(new URI(validationEndpoint)) - .headers("Content-Type", "application/json", "Authorization", authorizationToken).GET().build(); - } catch (URISyntaxException e) { - LOG.warn("Invalid URI for the validationEndpoint: " + validationEndpoint); - } - - try { - HttpResponse response = this.httpClient.send(request, BodyHandlers.ofString()); - if (response.statusCode() == 200) { - return true; - } else { - LOG.warn("Validating failed with status code {} and message '{}'", response.statusCode(), - response.body()); - } - } catch (IOException | InterruptedException e) { - LOG.error("Encountered a problem during authenticating the EDC token.", e); - } - - } - return false; - } - - public String getTransferId() { - return this.transferId; - } - - public String getContractAgreementId() { - return this.contractAgreementId; - } - - public void setToken(String aToken) { - this.authToken = aToken; - this.updateRemoteKerDataFromPeer(); - } } diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnectionManager.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnectionManager.java index 0c89dd18..f4cb2c0c 100644 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnectionManager.java +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteKerConnectionManager.java @@ -1,7 +1,6 @@ package eu.knowledge.engine.smartconnector.runtime.messaging; import java.net.URI; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; @@ -13,18 +12,13 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import org.eclipse.microprofile.config.Config; -import org.eclipse.microprofile.config.ConfigProvider; -import org.eclipse.microprofile.config.ConfigValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.knowledge.engine.smartconnector.api.SmartConnector; -import eu.knowledge.engine.smartconnector.api.SmartConnectorConfig; -import eu.knowledge.engine.smartconnector.edc.EdcConnectorProperties; import eu.knowledge.engine.smartconnector.edc.EdcConnectorService; -import eu.knowledge.engine.smartconnector.edc.InMemoryTokenManager; -import eu.knowledge.engine.smartconnector.edc.Token; +import eu.knowledge.engine.smartconnector.edc.ParticipantProperties; +import eu.knowledge.engine.smartconnector.edc.TransferProcess; import eu.knowledge.engine.smartconnector.runtime.KeRuntime; import eu.knowledge.engine.smartconnector.runtime.messaging.inter_ker.api.NotFoundException; import eu.knowledge.engine.smartconnector.runtime.messaging.inter_ker.api.SmartConnectorManagementApiService; @@ -54,63 +48,16 @@ public class RemoteKerConnectionManager extends SmartConnectorManagementApiServi private final MessageDispatcher messageDispatcher; private Date knowledgeDirectoryUpdateCooldownEnds = null; private EdcConnectorService edcService = null; - private InMemoryTokenManager tokenManager = null; - private URI myExposedUrl; - private URI myEdcConnectorUrl = null; private boolean useEdc; public RemoteKerConnectionManager(MessageDispatcher messageDispatcher, URI myExposedUrl, boolean useEdc) { this.messageDispatcher = messageDispatcher; - this.myExposedUrl = myExposedUrl; messageReceiver = new RemoteMessageReceiver(messageDispatcher); this.useEdc = useEdc; if (this.useEdc) { - List config = loadConfig(); - - this.edcService = new EdcConnectorService(config); - this.tokenManager = new InMemoryTokenManager(); - } - } - - /** - * TODO We do not want to load these manually, is there a better way? - * - * @return A configuration object with properties for the two connectors. - */ - private List loadConfig() { - - Config config = ConfigProvider.getConfig(); - - ConfigValue protocolUrl = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_PROTOCOL_URL); - ConfigValue managementUrl = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_MANAGEMENT_URL); - ConfigValue dataPlaneControlUrl = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_DATAPLANE_CONTROL_URL); - ConfigValue dataPlanePublicUrl = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_DATAPLANE_PUBLIC_URL); - ConfigValue tokenValidationEndpoint = config.getConfigValue(SmartConnectorConfig.CONF_KEY_KE_EDC_TOKEN_VALIDATION_ENDPOINT); - - EdcConnectorProperties props = new EdcConnectorProperties( - this.myExposedUrl.toString(), - protocolUrl.getValue(), - managementUrl.getValue(), - "tke-dataplane", - dataPlaneControlUrl.getValue(), - dataPlanePublicUrl.getValue(), - tokenValidationEndpoint.getValue(), - "TNO Knowledge Engine Runtime", - "https://www.knowledge-engine.eu/" - ); - - LOG.info("Setting management url to: {}", managementUrl); - - try { - this.myEdcConnectorUrl = new URI(props.protocolUrl()); - } catch (URISyntaxException e) { - LOG.error("Invalid syntax for EDC Connector URL"); + this.edcService = new EdcConnectorService(myExposedUrl); } - - List connectors = List.of(props); - - return connectors; } public void start() { @@ -125,7 +72,7 @@ public void start() { // configure our EDC Connector with the TKE asset if (useEdc) { - edcService.configureConnector(this.myExposedUrl.toString()); + edcService.configureConnector(); } } @@ -183,17 +130,18 @@ private synchronized void queryKnowledgeDirectory() { RemoteKerConnection messageSender; if (useEdc) { - EdcConnectorProperties prop = new EdcConnectorProperties( - knowledgeEngineRuntime.getExposedUrl().toString(), - knowledgeEngineRuntime.getEdcConnectorUrl().toString() + URI counterPartyParticipantId = knowledgeEngineRuntime.getEdcParticipantId(); + ParticipantProperties participant = new ParticipantProperties( + counterPartyParticipantId, + knowledgeEngineRuntime.getEdcConnectorUrl(), + knowledgeEngineRuntime.getEdcDataPlaneUrl() ); - this.edcService.addConnector(prop); + this.edcService.registerParticipant(participant); + TransferProcess transferProcess = this.edcService.createTransferProcess(counterPartyParticipantId); - messageSender = new RemoteKerConnection(messageDispatcher, this.myExposedUrl, - this.edcService, this.tokenManager, knowledgeEngineRuntime); + messageSender = new RemoteKerConnection(messageDispatcher, knowledgeEngineRuntime, transferProcess); } else { - messageSender = new RemoteKerConnection(messageDispatcher, this.myExposedUrl, null, null, - knowledgeEngineRuntime); + messageSender = new RemoteKerConnection(messageDispatcher, knowledgeEngineRuntime, null); } remoteKerConnections.put(knowledgeEngineRuntime.getId(), messageSender); messageSender.start(); @@ -311,25 +259,6 @@ public Response runtimedetailsKerIdDelete(String authorizationToken, String kerI } } - @Override - public Response tokenPost(String body, SecurityContext securityContext) throws NotFoundException { - - LOG.info("Token JSON received: {}", body); - // TODO Change runtimeexception from new Token to something we can use? - if (tokenManager != null) { - tokenManager.tokenReceived(new Token(body)); - Token t = new Token(body); - - for (RemoteKerConnection ker : this.remoteKerConnections.values()) { - if (ker.getTransferId().equals(t.id()) && ker.getContractAgreementId().equals(t.contractId())) { - ker.setToken(t.authCode()); - } - } - } - - return Response.status(200).build(); - } - /** * Notify other KnowledgeEngineRuntimes that something changed locally. Called * directly by the {@link LocalSmartConnectorConnectionManager} after it made @@ -357,14 +286,7 @@ public List getRemoteSmartConnectorIds() { return list; } - public boolean isTokenValid(String authorizationToken, URI fromKnowledgeBase) { - if (getRemoteKerConnection(fromKnowledgeBase) != null) { - return getRemoteKerConnection(fromKnowledgeBase).checkAuthorizationToken(authorizationToken); - } - return false; - } - - URI getEdcConnectorUrl() { - return this.myEdcConnectorUrl; + public ParticipantProperties getMyEdcProperties() { + return this.edcService.getMyProperties(); } } diff --git a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteMessageReceiver.java b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteMessageReceiver.java index 3a6115b2..9a63b03c 100644 --- a/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteMessageReceiver.java +++ b/smart-connector/src/main/java/eu/knowledge/engine/smartconnector/runtime/messaging/RemoteMessageReceiver.java @@ -38,23 +38,13 @@ private Response handleMessage(String authorizationToken, KnowledgeMessage messa LOG.trace("Received {} {} from KnowledgeDirectory for KnowledgeBase {} from remote SmartConnector", message.getClass().getSimpleName(), message.getMessageId(), message.getToKnowledgeBase()); //TODO: Hacky way to determine meta-ness of KI is not great, replace by more robust solution + //NOTE: If and else clause are both the same -> remove or change? if (message.getToKnowledgeInteraction().toURL().toString().contains("meta")) { messageDispatcher.deliverToLocalSmartConnector(message); return Response.status(202).build(); } else { - if (this.messageDispatcher.usesEdc()) { - if (messageDispatcher.getRemoteSmartConnectorConnectionsManager().isTokenValid(authorizationToken, message.getFromKnowledgeBase())) { - LOG.info("Authorization token has been validated"); - messageDispatcher.deliverToLocalSmartConnector(message); - return Response.status(202).build(); - } else { - LOG.warn("Could not validate the authorization token"); - return Response.status(403).entity("Invalid authorization token").build(); - } - } else { - messageDispatcher.deliverToLocalSmartConnector(message); - return Response.status(202).build(); - } + messageDispatcher.deliverToLocalSmartConnector(message); + return Response.status(202).build(); } } catch (IOException e) { // Was not able to deliver message to the SmartConnector diff --git a/smart-connector/src/main/resources/META-INF/microprofile-config.properties b/smart-connector/src/main/resources/META-INF/microprofile-config.properties index bbf90fa7..5aafeadf 100644 --- a/smart-connector/src/main/resources/META-INF/microprofile-config.properties +++ b/smart-connector/src/main/resources/META-INF/microprofile-config.properties @@ -9,8 +9,7 @@ ke.runtime.hostname = localhost ke.reasoner.level = 2 ke.runtime.use.edc = false +ke.edc.participant.id = ke.edc.protocol.url = ke.edc.management.url = -ke.edc.dataplane.control.url = ke.edc.dataplane.public.url = -ke.edc.token.validation.endpoint = diff --git a/smart-connector/src/main/resources/openapi-inter-ker.yaml b/smart-connector/src/main/resources/openapi-inter-ker.yaml index 8a0b8d12..8d179770 100644 --- a/smart-connector/src/main/resources/openapi-inter-ker.yaml +++ b/smart-connector/src/main/resources/openapi-inter-ker.yaml @@ -95,25 +95,6 @@ paths: text/plain; charset=UTF-8: schema: type: string - /token: - post: - summary: Token to use when communicating with that particular KE Runtime (for usage with Eclipse Dataspace Components (EDC)) - tags: - - "smart connector management" - requestBody: - required: true - content: - application/json; charset=UTF-8: - schema: - $ref: '#/components/schemas/Token' - responses: - '200': - description: Successfully received token. - '400': - description: Incorrect token. - '500': - description: Error while processing token. - /messaging/askmessage: post: summary: Handle an AskMessage @@ -359,6 +340,4 @@ components: errorMessage: type: string required: - - replyToMessage - Token: - type: string \ No newline at end of file + - replyToMessage \ No newline at end of file diff --git a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/misc/WireMockFirstConfigurationTest.java b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/misc/WireMockFirstConfigurationTest.java index 9909a5c9..4fd02dcc 100644 --- a/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/misc/WireMockFirstConfigurationTest.java +++ b/smart-connector/src/test/java/eu/knowledge/engine/smartconnector/misc/WireMockFirstConfigurationTest.java @@ -62,8 +62,8 @@ public void testConfigHttpConnectTimeout() throws Exception { MessageDispatcher messageDispatcher = mock(MessageDispatcher.class); - var ker = new RemoteKerConnection(messageDispatcher, new URI(SmartConnectorConfig.CONF_KEY_KE_RUNTIME_EXPOSED_URL), null, null, - new KnowledgeEngineRuntimeConnectionDetails().exposedUrl(URI.create("http://10.255.255.1/"))); + var ker = new RemoteKerConnection(messageDispatcher, + new KnowledgeEngineRuntimeConnectionDetails().exposedUrl(URI.create("http://10.255.255.1/")), null); ker.start(); assertFalse(ker.isAvailable());