diff --git a/.github/workflows/deployment-test.yaml b/.github/workflows/deployment-test.yaml index 7a7e63c8a..83bc15d08 100644 --- a/.github/workflows/deployment-test.yaml +++ b/.github/workflows/deployment-test.yaml @@ -79,11 +79,11 @@ jobs: with: imagename: edc-runtime-memory rootDir: edc-controlplane/edc-runtime-memory - values_file: charts/tractusx-connector-memory/example.yaml + values_file: edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml helm_command: |- helm install tx-inmem charts/tractusx-connector-memory \ - -f charts/tractusx-connector-memory/example.yaml \ - --set vault.secrets="daps-crt:$(cat daps.cert);daps-key:$(cat daps.key)" \ + -f edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml \ + --set vault.secrets="client-secret:$(cat client.secret)" \ --wait-for-jobs --timeout=120s --dependency-update # wait for the pod to become ready @@ -108,7 +108,7 @@ jobs: helm install tx-prod charts/tractusx-connector \ -f edc-tests/deployment/src/main/resources/helm/tractusx-connector-test.yaml \ --dependency-update \ - --wait-for-jobs --timeout=120s + --wait-for-jobs --timeout=120s # wait for the pod to become ready kubectl rollout status deployment tx-prod-controlplane @@ -135,9 +135,8 @@ jobs: rootDir: "." values_file: edc-tests/deployment/src/main/resources/helm/tractusx-connector-azure-vault-test.yaml helm_command: |- - az keyvault secret set --vault-name ${{ secrets.AZURE_VAULT_NAME }} --name daps-crt --value "$(cat daps.cert)" > /dev/null - az keyvault secret set --vault-name ${{ secrets.AZURE_VAULT_NAME }} --name daps-key --value "$(cat daps.key)" > /dev/null az keyvault secret set --vault-name ${{ secrets.AZURE_VAULT_NAME }} --name aes-keys --value "$(cat aes.key)" > /dev/null + az keyvault secret set --vault-name ${{ secrets.AZURE_VAULT_NAME }} --name client-secret --value "$(cat client.secret)" > /dev/null helm install tx-prod charts/tractusx-connector-azure-vault \ -f edc-tests/deployment/src/main/resources/helm/tractusx-connector-azure-vault-test.yaml \ diff --git a/.github/workflows/draft-new-release.yaml b/.github/workflows/draft-new-release.yaml index ef04b6746..f25929394 100644 --- a/.github/workflows/draft-new-release.yaml +++ b/.github/workflows/draft-new-release.yaml @@ -66,7 +66,7 @@ jobs: uses: mikefarah/yq@v4.34.1 with: cmd: |- - find charts -name Chart.yaml | xargs -n1 yq -i '.appVersion = "${{ github.event.inputs.version }}" | .version = "${{ github.event.inputs.version }}"' + find charts -name Chart.yaml -maxdepth 3 | xargs -n1 yq -i '.appVersion = "${{ github.event.inputs.version }}" | .version = "${{ github.event.inputs.version }}"' - name: Update Chart READMEs uses: addnab/docker-run-action@v3 diff --git a/.github/workflows/publish-new-release.yml b/.github/workflows/publish-new-release.yml index 089ec3ed8..f55e600bc 100644 --- a/.github/workflows/publish-new-release.yml +++ b/.github/workflows/publish-new-release.yml @@ -233,9 +233,18 @@ jobs: git checkout main && git merge -X theirs releases --no-commit --no-ff # Extract release version - IFS=. read -r RELEASE_VERSION_MAJOR RELEASE_VERSION_MINOR RELEASE_VERSION_PATCH<<<"${{ env.RELEASE_VERSION }}" - # Compute new snapshot version - VERSION="$RELEASE_VERSION_MAJOR.$RELEASE_VERSION_MINOR.$((RELEASE_VERSION_PATCH+1))-SNAPSHOT" + IFS=.- read -r RELEASE_VERSION_MAJOR RELEASE_VERSION_MINOR RELEASE_VERSION_PATCH SNAPSHOT<<<"${{ env.RELEASE_VERSION }}" + INC=0 + # Compute new snapshot version, do not increment snapshot on non-final releases, e.g. -rc1 + if [ -z $SNAPSHOT ]; then + # snapshot + echo "${{ env.RELEASE_VERSION }} is a final release version, increase patch for next snapshot" + INC=1 + else + echo "${{ env.RELEASE_VERSION }} is not a final release version (contains \"$SNAPSHOT\"), will not increase patch" + fi + + VERSION="$RELEASE_VERSION_MAJOR.$RELEASE_VERSION_MINOR.$((RELEASE_VERSION_PATCH+$INC))-SNAPSHOT" SNAPSHOT_VERSION=$VERSION # Persist the "version" in the gradle.properties diff --git a/.github/workflows/verify.yaml b/.github/workflows/verify.yaml index c2e276362..9961015b7 100644 --- a/.github/workflows/verify.yaml +++ b/.github/workflows/verify.yaml @@ -26,6 +26,7 @@ on: branches: - main - releases + - previews/* tags: - '[0-9]+.[0-9]+.[0-9]+' release: @@ -129,7 +130,7 @@ jobs: postgres-tests: runs-on: ubuntu-latest - needs: [ verify-formatting ] + needs: [ verify-formatting, verify-license-headers ] services: postgres: @@ -143,5 +144,14 @@ jobs: - uses: actions/checkout@v3 - uses: ./.github/actions/setup-java + # create non-default schema name to test usage of non-default schema + - name: setup postgres schema + run: | + sudo apt update + sudo apt install --yes postgresql-client + psql -h localhost -d postgres -U postgres -c 'CREATE SCHEMA testschema;' + env: + PGPASSWORD: password + - name: Run Postgresql E2E tests run: ./gradlew test -DincludeTags="PostgresqlIntegrationTest" diff --git a/CHANGELOG.md b/CHANGELOG.md index c57281d2f..1de1fc596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.4.1] - 2023-05-31 +## [0.5.0-rc1] - 2023-06-21 + +## [0.5.0-rc1] - 2023-06-21 + +## Fixed + +Various fixes and improvements to our helm charts + +### Added + +Support for SSI (centralized MiW) (#459, #510) +Support for the JsonWebSignature2020 Crypto Suite (#483) + +## Changed + +All Helm charts now use SSI instead of DAPS (#511) + +## Removed + +Support for DAPS as identity provider (#511) ## [0.4.1] - 2023-05-31 @@ -323,7 +342,9 @@ corresponding [documentation](/docs/migration/Version_0.0.x_0.1.x.md). ## [0.0.1] - 2022-05-13 -[Unreleased]: https://github.com/eclipse-tractusx/tractusx-edc/compare/0.4.1...HEAD +[Unreleased]: https://github.com/eclipse-tractusx/tractusx-edc/compare/0.5.0-rc1...HEAD + +[0.5.0-rc1]: https://github.com/eclipse-tractusx/tractusx-edc/compare/0.4.1...0.5.0-rc1 [0.4.1]: https://github.com/eclipse-tractusx/tractusx-edc/compare/0.3.3...0.4.1 diff --git a/build.gradle.kts b/build.gradle.kts index 50213a16b..936e686e5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -113,7 +113,7 @@ allprojects { configDirectory.set(rootProject.file("resources")) //checkstyle violations are reported at the WARN level - this.isShowViolations = System.getProperty("checkstyle.verbose", "false").toBoolean() + this.isShowViolations = System.getProperty("checkstyle.verbose", "true").toBoolean() } @@ -175,4 +175,4 @@ nexusPublishing { maxRetries.set(120) delayBetween.set(Duration.ofSeconds(10)) } -} \ No newline at end of file +} diff --git a/charts/tractusx-connector-azure-vault/Chart.yaml b/charts/tractusx-connector-azure-vault/Chart.yaml index 7b2802934..78c8f0823 100644 --- a/charts/tractusx-connector-azure-vault/Chart.yaml +++ b/charts/tractusx-connector-azure-vault/Chart.yaml @@ -40,22 +40,16 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.1 +version: 0.5.0-rc1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.4.1" +appVersion: "0.5.0-rc1" home: https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector sources: - https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector dependencies: - # IDS Dynamic Attribute Provisioning Service (IAM) - - name: daps - version: 0.0.1 - repository: "file://./subcharts/omejdn" - alias: daps - condition: install.daps # PostgreSQL - name: postgresql alias: postgresql diff --git a/charts/tractusx-connector-azure-vault/README.md b/charts/tractusx-connector-azure-vault/README.md index d13d18514..cc0d46135 100644 --- a/charts/tractusx-connector-azure-vault/README.md +++ b/charts/tractusx-connector-azure-vault/README.md @@ -1,6 +1,6 @@ # tractusx-connector-azure-vault -![Version: 0.4.1](https://img.shields.io/badge/Version-0.4.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.4.1](https://img.shields.io/badge/AppVersion-0.4.1-informational?style=flat-square) +![Version: 0.5.0-rc1](https://img.shields.io/badge/Version-0.5.0--rc1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.0-rc1](https://img.shields.io/badge/AppVersion-0.5.0--rc1-informational?style=flat-square) A Helm chart for Tractus-X Eclipse Data Space Connector. The connector deployment consists of two runtime consists of a Control Plane and a Data Plane. Note that _no_ external dependencies such as a PostgreSQL database and Azure KeyVault are included. @@ -38,7 +38,7 @@ Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev -helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0.4.1 \ +helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0.5.0-rc1 \ -f /tractusx-connector-azure-vault-test.yaml \ --set vault.azure.name=$AZURE_VAULT_NAME \ --set vault.azure.client=$AZURE_CLIENT_ID \ @@ -56,7 +56,6 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri | Repository | Name | Version | |------------|------|---------| -| file://./subcharts/omejdn | daps(daps) | 0.0.1 | | https://charts.bitnami.com/bitnami | postgresql(postgresql) | 12.1.6 | ## Values @@ -161,20 +160,17 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri | controlplane.securityContext.runAsUser | int | `10001` | The container's process will run with the specified uid | | controlplane.service.annotations | object | `{}` | | | controlplane.service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | +| controlplane.ssi.endpoint.audience | string | `"http://this.audience"` | | +| controlplane.ssi.miw.authorityId | string | `""` | | +| controlplane.ssi.miw.url | string | `""` | | +| controlplane.ssi.oauth.client.id | string | `""` | | +| controlplane.ssi.oauth.client.secretAlias | string | `"client-secret"` | | +| controlplane.ssi.oauth.tokenurl | string | `""` | | | controlplane.tolerations | list | `[]` | | | controlplane.url.ids | string | `""` | Explicitly declared url for reaching the ids api (e.g. if ingresses not used) | | controlplane.volumeMounts | list | `[]` | declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container | | controlplane.volumes | list | `[]` | [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories | | customLabels | object | `{}` | | -| daps.clientId | string | `""` | | -| daps.connectors[0].attributes.referringConnector | string | `"http://sokrates-controlplane/BPNSOKRATES"` | | -| daps.connectors[0].certificate | string | `""` | | -| daps.connectors[0].id | string | `"E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65"` | | -| daps.connectors[0].name | string | `"sokrates"` | | -| daps.fullnameOverride | string | `"daps"` | | -| daps.paths.jwks | string | `"/jwks.json"` | | -| daps.paths.token | string | `"/token"` | | -| daps.url | string | `""` | | | dataplane.affinity | object | `{}` | | | dataplane.autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | | dataplane.autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | @@ -255,9 +251,7 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri | dataplane.volumeMounts | list | `[]` | declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container | | dataplane.volumes | list | `[]` | [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories | | fullnameOverride | string | `""` | | -| idsdaps.connectors[0].certificate | string | `""` | | | imagePullSecrets | list | `[]` | Existing image pull secret to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | -| install.daps | bool | `true` | | | install.postgresql | bool | `true` | | | nameOverride | string | `""` | | | participant.id | string | `""` | | @@ -265,24 +259,23 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri | postgresql.auth.password | string | `"password"` | | | postgresql.auth.username | string | `"user"` | | | postgresql.enabled | bool | `false` | | -| postgresql.fullnameOverride | string | `"postgresql"` | | -| postgresql.jdbcUrl | string | `""` | | +| postgresql.jdbcUrl | string | `"jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc"` | | | postgresql.primary.persistence | string | `nil` | | | postgresql.readReplicas.persistence.enabled | bool | `false` | | | serviceAccount.annotations | object | `{}` | | | serviceAccount.create | bool | `true` | | | serviceAccount.imagePullSecrets | list | `[]` | Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | | serviceAccount.name | string | `""` | | +| tests | object | `{"hookDeletePolicy":"before-hook-creation,hook-succeeded"}` | Configurations for Helm tests | +| tests.hookDeletePolicy | string | `"before-hook-creation,hook-succeeded"` | Configure the hook-delete-policy for Helm tests | | vault.azure.certificate | string | `nil` | | | vault.azure.client | string | `""` | | | vault.azure.name | string | `""` | | | vault.azure.secret | string | `nil` | | | vault.azure.tenant | string | `""` | | -| vault.secretNames.dapsPrivateKey | string | `"daps-private-key"` | | -| vault.secretNames.dapsPublicKey | string | `"daps-public-key"` | | | vault.secretNames.transferProxyTokenEncryptionAesKey | string | `"transfer-proxy-token-encryption-aes-key"` | | -| vault.secretNames.transferProxyTokenSignerPrivateKey | string | `"transfer-proxy-token-signer-private-key"` | | -| vault.secretNames.transferProxyTokenSignerPublicKey | string | `"transfer-proxy-token-signer-public-key"` | | +| vault.secretNames.transferProxyTokenSignerPrivateKey | string | `nil` | | +| vault.secretNames.transferProxyTokenSignerPublicKey | string | `nil` | | ---------------------------------------------- Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/README.md b/charts/tractusx-connector-azure-vault/subcharts/omejdn/README.md deleted file mode 100644 index d23a9f9fa..000000000 --- a/charts/tractusx-connector-azure-vault/subcharts/omejdn/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# daps - -![Version: 0.4.1](https://img.shields.io/badge/Version-0.4.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.4.1](https://img.shields.io/badge/AppVersion-0.4.1-informational?style=flat-square) - -A Helm chart for Kubernetes - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. | -| automountServiceAccountToken | bool | `false` | Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod | -| autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | -| autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | -| autoscaling.minReplicas | int | `1` | Minimal replicas if resource consumption falls below resource threshholds | -| autoscaling.targetCPUUtilizationPercentage | int | `80` | targetAverageUtilization of cpu provided to a pod | -| autoscaling.targetMemoryUtilizationPercentage | int | `80` | targetAverageUtilization of memory provided to a pod | -| connectors | list | `[]` | | -| fullnameOverride | string | `""` | Overrides the releases full name | -| image.pullPolicy | string | `"IfNotPresent"` | [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use | -| image.repository | string | `"ghcr.io/fraunhofer-aisec/omejdn-server"` | Which omjedn container image to use | -| image.tag | string | `"1.7.1"` | Overrides the image tag whose default is the chart appVersion | -| imagePullSecret.dockerconfigjson | string | `""` | Image pull secret to create to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) Note: This value needs to adhere to the [(base64 encoded) .dockerconfigjson format](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials). Furthermore, if 'imagePullSecret.dockerconfigjson' is defined, it takes precedence over 'imagePullSecrets'. | -| nameOverride | string | `""` | Overrides the charts name | -| nodeSelector | object | `{}` | [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. | -| podAnnotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) | -| podSecurityContext | object | `{}` | | -| replicaCount | int | `1` | Specifies how many replicas of a deployed pod shall be created during the deployment Note: If horizontal pod autoscaling is enabled this setting has no effect | -| resources | object | `{}` | [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod | -| securityContext | object | `{}` | | -| service.port | int | `4567` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) to expose the running application on a set of Pods as a network service. | -| service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | -| serviceAccount.annotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account | -| serviceAccount.create | bool | `true` | Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release | -| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template | -| tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. | - ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/configmap.yaml b/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/configmap.yaml deleted file mode 100644 index 5ad21648d..000000000 --- a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/configmap.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -data: - scope_mapping.yml: |- - --- - idsc:IDS_CONNECTOR_ATTRIBUTES_ALL: - - referringConnector - - omejdn.yml: |- - --- - host: http://daps:4567/ - path_prefix: '' - bind_to: 0.0.0.0 - allow_origin: "*" - app_env: debug - openid: false - user_backend: - - yaml - user_backend_default: yaml - accept_audience: idsc:IDS_CONNECTORS_ALL - issuer: http://daps:4567/ - environment: development - default_audience: - - idsc:IDS_CONNECTORS_ALL - access_token: - expiration: 3600 - algorithm: RS256 - id_token: - expiration: 3600 - algorithm: RS256 - - plugins.yml: |- - --- - plugins: - token_user_attributes: - - clients.yml: |- - --- - - client_id: data-plane-oauth2 - client_secret: supersecret - name: provision oauth2 - grant_types: - - client_credentials - token_endpoint_auth_method: client_secret_post - scope: openid -{{- range $i, $val := .Values.connectors }} - - client_id: {{ quote $val.id }} - name: {{ quote $val.name }} - token_endpoint_auth_method: private_key_jwt - grant_types: - - client_credentials - scope: - - idsc:IDS_CONNECTOR_ATTRIBUTES_ALL - attributes: - - key: idsc - value: IDS_CONNECTOR_ATTRIBUTES_ALL - - key: securityProfile - value: idsc:BASE_SECURITY_PROFILE - {{- range $key, $value := $val.attributes }} - - key: {{ $key }} - value: {{ $value }} - {{- end }} - redirect_uri: http://localhost:4200 -{{ end -}} - - -{{- range $i, $val := .Values.connectors }} - {{ $val.name }}: {{ quote $val.certificate | toString }} -{{ end -}} diff --git a/charts/tractusx-connector-azure-vault/templates/deployment-controlplane.yaml b/charts/tractusx-connector-azure-vault/templates/deployment-controlplane.yaml index 3a8ed5fd7..362594114 100644 --- a/charts/tractusx-connector-azure-vault/templates/deployment-controlplane.yaml +++ b/charts/tractusx-connector-azure-vault/templates/deployment-controlplane.yaml @@ -1,24 +1,24 @@ # -# Copyright (c) 2023 ZF Friedrichshafen AG -# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH -# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) -# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# + # Copyright (c) 2023 ZF Friedrichshafen AG + # Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH + # Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + # Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # 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 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + # License for the specific language governing permissions and limitations + # under the License. + # + # SPDX-License-Identifier: Apache-2.0 + # --- apiVersion: apps/v1 @@ -115,21 +115,21 @@ spec: - name: EDC_PARTICIPANT_ID value: {{ .Values.participant.id | required ".Values.participant.id is required" | quote }} - ######################## - ## DAPS CONFIGURATION ## - ######################## - - # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/iam/oauth2/oauth2-core - - name: EDC_OAUTH_CLIENT_ID - value: {{ .Values.daps.clientId | required ".Values.daps.clientId is required" | quote }} - - name: EDC_OAUTH_PROVIDER_JWKS_URL - value: {{ printf "%s%s" .Values.daps.url .Values.daps.paths.jwks }} - - name: EDC_OAUTH_TOKEN_URL - value: {{ printf "%s%s" .Values.daps.url .Values.daps.paths.token }} - - name: EDC_OAUTH_PRIVATE_KEY_ALIAS - value: {{ .Values.vault.secretNames.dapsPrivateKey | required ".Values.vault.secretNames.dapsPrivateKey is required" | quote }} - - name: EDC_OAUTH_CERTIFICATE_ALIAS - value: {{ .Values.vault.secretNames.dapsPublicKey | required ".Values.vault.secretNames.dapsPublicKey is required" | quote }} + ########################## + # SSI / MIW CONFIGURATION + ########################## + - name: "TX_SSI_MIW_URL" + value: {{ .Values.controlplane.ssi.miw.url }} + - name: "TX_SSI_MIW_AUTHORITY_ID" + value: {{ .Values.controlplane.ssi.miw.authorityId }} + - name: "TX_SSI_OAUTH_TOKEN_URL" + value: {{ .Values.controlplane.ssi.oauth.tokenurl }} + - name: "TX_SSI_OAUTH_CLIENT_ID" + value: {{ .Values.controlplane.ssi.oauth.client.id }} + - name: "TX_SSI_OAUTH_CLIENT_SECRET_ALIAS" + value: {{ .Values.controlplane.ssi.oauth.client.secretAlias }} + - name: "TX_SSI_ENDPOINT_AUDIENCE" + value: {{ printf "%s%s" (include "txdc.controlplane.url.protocol" .) .Values.controlplane.endpoints.protocol.path | quote }} ####### # API # @@ -178,61 +178,61 @@ spec: - name: "EDC_DATASOURCE_ASSET_NAME" value: "asset" - name: "EDC_DATASOURCE_ASSET_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_ASSET_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_ASSET_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/contract-definition-store-sql - name: "EDC_DATASOURCE_CONTRACTDEFINITION_NAME" value: "contractdefinition" - name: "EDC_DATASOURCE_CONTRACTDEFINITION_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_CONTRACTDEFINITION_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_CONTRACTDEFINITION_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/contract-negotiation-store-sql - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_NAME" value: "contractnegotiation" - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/policy-store-sql - name: "EDC_DATASOURCE_POLICY_NAME" value: "policy" - name: "EDC_DATASOURCE_POLICY_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_POLICY_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_POLICY_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/transfer-process-store-sql - name: "EDC_DATASOURCE_TRANSFERPROCESS_NAME" value: "transferprocess" - name: "EDC_DATASOURCE_TRANSFERPROCESS_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_TRANSFERPROCESS_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_TRANSFERPROCESS_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/edr-cache-sql - name: "EDC_DATASOURCE_EDR_NAME" value: "edr" - name: "EDC_DATASOURCE_EDR_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_EDR_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_EDR_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} ################ ## DATA PLANE ## @@ -252,10 +252,14 @@ spec: # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/data-plane-transfer - name: "EDC_TRANSFER_PROXY_ENDPOINT" value: {{ include "txdc.dataplane.url.public" . }} + {{- if .Values.vault.secretNames.transferProxyTokenSignerPrivateKey }} - name: "EDC_TRANSFER_PROXY_TOKEN_SIGNER_PRIVATEKEY_ALIAS" value: {{ .Values.vault.secretNames.transferProxyTokenSignerPrivateKey | quote }} + {{- end }} + {{- if .Values.vault.secretNames.transferProxyTokenSignerPublicKey }} - name: "EDC_TRANSFER_PROXY_TOKEN_VERIFIER_PUBLICKEY_ALIAS" value: {{ .Values.vault.secretNames.transferProxyTokenSignerPublicKey | quote }} + {{- end }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/transfer/transfer-pull-http-dynamic-receiver diff --git a/charts/tractusx-connector-azure-vault/templates/deployment-dataplane.yaml b/charts/tractusx-connector-azure-vault/templates/deployment-dataplane.yaml index 468c1c2d9..8626dc512 100644 --- a/charts/tractusx-connector-azure-vault/templates/deployment-dataplane.yaml +++ b/charts/tractusx-connector-azure-vault/templates/deployment-dataplane.yaml @@ -155,9 +155,9 @@ spec: - name: "EDC_DATASOURCE_EDR_NAME" value: "edr" - name: "EDC_DATASOURCE_EDR_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_EDR_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_EDR_URL" value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} diff --git a/charts/tractusx-connector-azure-vault/templates/ingress-controlplane.yaml b/charts/tractusx-connector-azure-vault/templates/ingress-controlplane.yaml index d70d00413..0be9a53a8 100644 --- a/charts/tractusx-connector-azure-vault/templates/ingress-controlplane.yaml +++ b/charts/tractusx-connector-azure-vault/templates/ingress-controlplane.yaml @@ -18,7 +18,7 @@ # {{- $fullName := include "txdc.fullname" . }} -{{- $controlLabels := include "txdc.controlplane.labels" . | nindent 4 }} +{{- $controlLabels := include "txdc.controlplane.labels" . }} {{- $controlEdcEndpoints := .Values.controlplane.endpoints }} {{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} {{- $namespace := .Release.Namespace }} @@ -26,6 +26,7 @@ {{- range .Values.controlplane.ingresses }} {{- if and .enabled .endpoints }} {{- $controlIngressName := printf "%s-controlplane-%s" $fullName .hostname }} +{{- $annotations := .annotations | default dict }} --- {{- if semverCompare ">=1.19-0" $gitVersion }} apiVersion: networking.k8s.io/v1 @@ -39,22 +40,22 @@ metadata: name: {{ $controlIngressName }} namespace: {{ $namespace | default "default" | quote }} labels: - {{- $controlLabels | nindent 2 }} + {{- $controlLabels | nindent 4 }} annotations: {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} - {{- if not (hasKey .annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .annotations "kubernetes.io/ingress.class" .className}} + {{- if not (hasKey $annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $annotations "kubernetes.io/ingress.class" .className}} {{- end }} {{- end }} {{- if .certManager }} {{- if .certManager.issuer }} - {{- $_ := set .annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- $_ := set $annotations "cert-manager.io/issuer" .certManager.issuer}} {{- end }} {{- if .certManager.clusterIssuer }} - {{- $_ := set .annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- $_ := set $annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} {{- end }} {{- end }} - {{- with .annotations }} + {{- with $annotations }} {{- toYaml . | nindent 4 }} {{- end }} spec: diff --git a/charts/tractusx-connector-azure-vault/templates/ingress-dataplane.yaml b/charts/tractusx-connector-azure-vault/templates/ingress-dataplane.yaml index 20788d85f..c59084455 100644 --- a/charts/tractusx-connector-azure-vault/templates/ingress-dataplane.yaml +++ b/charts/tractusx-connector-azure-vault/templates/ingress-dataplane.yaml @@ -18,7 +18,7 @@ # {{- $fullName := include "txdc.fullname" . }} -{{- $dataLabels := include "txdc.dataplane.labels" . | nindent 4 }} +{{- $dataLabels := include "txdc.dataplane.labels" . }} {{- $dataEdcEndpoints := .Values.dataplane.endpoints }} {{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} {{- $namespace := .Release.Namespace }} @@ -26,6 +26,7 @@ {{- range .Values.dataplane.ingresses }} {{- if and .enabled .endpoints }} {{- $dataIngressName := printf "%s-dataplane-%s" $fullName .hostname }} +{{- $annotations := .annotations | default dict }} --- {{- if semverCompare ">=1.19-0" $gitVersion }} apiVersion: networking.k8s.io/v1 @@ -39,22 +40,22 @@ metadata: name: {{ $dataIngressName }} namespace: {{ $namespace | default "default" | quote }} labels: - {{- $dataLabels | nindent 2 }} + {{- $dataLabels | nindent 4 }} annotations: {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} - {{- if not (hasKey .annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .annotations "kubernetes.io/ingress.class" .className}} + {{- if not (hasKey $annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $annotations "kubernetes.io/ingress.class" .className}} {{- end }} {{- end }} {{- if .certManager }} {{- if .certManager.issuer }} - {{- $_ := set .annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- $_ := set $annotations "cert-manager.io/issuer" .certManager.issuer}} {{- end }} {{- if .certManager.clusterIssuer }} - {{- $_ := set .annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- $_ := set $annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} {{- end }} {{- end }} - {{- with .annotations }} + {{- with $annotations }} {{- toYaml . | nindent 4 }} {{- end }} spec: diff --git a/charts/tractusx-connector-azure-vault/templates/tests/test-controlplane-readiness.yaml b/charts/tractusx-connector-azure-vault/templates/tests/test-controlplane-readiness.yaml index db4765c0c..ed8514ad0 100644 --- a/charts/tractusx-connector-azure-vault/templates/tests/test-controlplane-readiness.yaml +++ b/charts/tractusx-connector-azure-vault/templates/tests/test-controlplane-readiness.yaml @@ -26,6 +26,7 @@ metadata: {{- include "txdc.controlplane.labels" . | nindent 4 }} annotations: "helm.sh/hook": test + "helm.sh/hook-delete-policy": {{ .Values.tests.hookDeletePolicy }} spec: containers: - name: wget diff --git a/charts/tractusx-connector-azure-vault/templates/tests/test-dataplane-readiness.yaml b/charts/tractusx-connector-azure-vault/templates/tests/test-dataplane-readiness.yaml index 0aed7c112..e21865bc8 100644 --- a/charts/tractusx-connector-azure-vault/templates/tests/test-dataplane-readiness.yaml +++ b/charts/tractusx-connector-azure-vault/templates/tests/test-dataplane-readiness.yaml @@ -26,6 +26,7 @@ metadata: {{- include "txdc.dataplane.labels" . | nindent 4 }} annotations: "helm.sh/hook": test + "helm.sh/hook-delete-policy": {{ .Values.tests.hookDeletePolicy }} spec: containers: - name: wget diff --git a/charts/tractusx-connector-azure-vault/values.yaml b/charts/tractusx-connector-azure-vault/values.yaml index 3a124ad81..f9758ecaf 100644 --- a/charts/tractusx-connector-azure-vault/values.yaml +++ b/charts/tractusx-connector-azure-vault/values.yaml @@ -27,14 +27,12 @@ # Declare variables to be passed into your templates. install: - daps: true postgresql: true fullnameOverride: "" nameOverride: "" # -- Existing image pull secret to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) imagePullSecrets: [] - customLabels: {} participant: @@ -131,6 +129,18 @@ controlplane: businessPartnerValidation: log: agreementValidation: true + # SSI configuration + ssi: + miw: + url: "" + authorityId: "" + oauth: + tokenurl: "" + client: + id: "" + secretAlias: "client-secret" + endpoint: + audience: "http://this.audience" service: # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. type: ClusterIP @@ -495,8 +505,7 @@ dataplane: public: "" postgresql: - jdbcUrl: "" - fullnameOverride: "postgresql" + jdbcUrl: "jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc" primary: persistence: enabled: false @@ -516,26 +525,10 @@ vault: certificate: secretNames: - transferProxyTokenSignerPrivateKey: transfer-proxy-token-signer-private-key - transferProxyTokenSignerPublicKey: transfer-proxy-token-signer-public-key + transferProxyTokenSignerPrivateKey: + transferProxyTokenSignerPublicKey: transferProxyTokenEncryptionAesKey: transfer-proxy-token-encryption-aes-key - dapsPrivateKey: daps-private-key - dapsPublicKey: daps-public-key -daps: - fullnameOverride: "daps" - url: "" - clientId: "" - paths: - jwks: /jwks.json - token: /token - connectors: - - id: E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65 - name: sokrates - attributes: - referringConnector: http://sokrates-controlplane/BPNSOKRATES - # Must be the same certificate that is stores in section 'sokrates-vault' - certificate: "" # must be set externally! backendService: httpProxyTokenReceiverUrl: "" serviceAccount: @@ -548,6 +541,7 @@ serviceAccount: name: "" # -- Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) imagePullSecrets: [] -idsdaps: - connectors: - - certificate: |- +# -- Configurations for Helm tests +tests: + # -- Configure the hook-delete-policy for Helm tests + hookDeletePolicy: before-hook-creation,hook-succeeded diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/Chart.yaml b/charts/tractusx-connector-legacy/Chart.yaml similarity index 50% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/Chart.yaml rename to charts/tractusx-connector-legacy/Chart.yaml index 3e10aa1fc..3355373bb 100644 --- a/charts/tractusx-connector-azure-vault/subcharts/omejdn/Chart.yaml +++ b/charts/tractusx-connector-legacy/Chart.yaml @@ -1,4 +1,8 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -18,8 +22,16 @@ --- apiVersion: v2 -name: daps -description: A Helm chart for Kubernetes +name: tractusx-connector-legacy +deprecated: true +description: | + A Helm chart for Tractus-X Eclipse Data Space Connector. The connector deployment consists of two runtime consists of a + Control Plane and a Data Plane. Note that _no_ external dependencies such as a PostgreSQL database and HashiCorp Vault are included. + + This chart is intended for use with an _existing_ PostgreSQL database and an _existing_ HashiCorp Vault. + + Deprecation notice: this chart uses DAPS, which was replaced with an SSI solution in v0.5.0 of Tractus-X EDC and is thus deprecated. + It will not be maintained, supported or tested anymore and it will be removed in future versions. # A chart can be either an 'application' or a 'library' chart. # # Application charts are a collection of templates that can be packaged into versioned archives @@ -32,9 +44,31 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.1 +version: 0.5.0-rc1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.4.1" +appVersion: "0.5.0-rc1" +home: https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector-legacy +sources: + - https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector-legacy +dependencies: + # IDS Dynamic Attribute Provisioning Service (IAM) + - name: daps + version: 0.0.1 + repository: "file://./subcharts/omejdn" + alias: daps + condition: install.daps + # HashiCorp Vault + - name: vault + alias: vault + version: 0.20.0 + repository: https://helm.releases.hashicorp.com + condition: install.vault + # PostgreSQL + - name: postgresql + alias: postgresql + version: 12.1.6 + repository: https://charts.bitnami.com/bitnami + condition: install.postgresql diff --git a/charts/tractusx-connector-legacy/README.md b/charts/tractusx-connector-legacy/README.md new file mode 100644 index 000000000..65abb2723 --- /dev/null +++ b/charts/tractusx-connector-legacy/README.md @@ -0,0 +1,298 @@ +# tractusx-connector-legacy + +> **:exclamation: This Helm Chart is deprecated!** + +![Version: 0.5.0-rc1](https://img.shields.io/badge/Version-0.5.0--rc1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.0-rc1](https://img.shields.io/badge/AppVersion-0.5.0--rc1-informational?style=flat-square) + +A Helm chart for Tractus-X Eclipse Data Space Connector. The connector deployment consists of two runtime consists of a +Control Plane and a Data Plane. Note that _no_ external dependencies such as a PostgreSQL database and HashiCorp Vault are included. + +This chart is intended for use with an _existing_ PostgreSQL database and an _existing_ HashiCorp Vault. + +Deprecation notice: this chart uses DAPS, which was replaced with an SSI solution in v0.5.0 of Tractus-X EDC and is thus deprecated. +It will not be maintained, supported or tested anymore and it will be removed in future versions. + +**Homepage:** + +This chart uses Hashicorp Vault, which is expected to contain the following secrets on application start: + +- `daps-cert`: contains the x509 certificate of the connector. +- `daps-key`: the private key of the x509 certificate +- `aes-keys`: a 128bit, 256bit or 512bit string used to encrypt data. Must be stored in base64 format. + +These must be obtained from a DAPS instance, the process of which is out of the scope of this document. Alternatively, +self-signed certificates can be used for testing: + +```shell +openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout daps.key -out daps.cert -subj "/CN=test" +export DAPS_KEY="$(cat daps.key)" +export DAPS_CERT="$(cat daps.cert)" +``` + +## Launching the application + +The following requirements must be met before launching the application: + +- Write access to a HashiCorp Vault instance is required to run this chart +- Secrets are seeded in advance + +Please also consider using [this example configuration](https://github.com/eclipse-tractusx/tractusx-edc/blob/main/edc-tests/deployment/src/main/resources/helm/tractusx-connector-test.yaml) +to launch the application. +Combined, run this shell command to start the in-memory Tractus-X EDC runtime: + +```shell +helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev +helm install my-release tractusx-edc/tractusx-connector --version 0.5.0-rc1 \ + -f /tractusx-connector-test.yaml +``` + +## Source Code + +* + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| file://./subcharts/omejdn | daps(daps) | 0.0.1 | +| https://charts.bitnami.com/bitnami | postgresql(postgresql) | 12.1.6 | +| https://helm.releases.hashicorp.com | vault(vault) | 0.20.0 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| backendService.httpProxyTokenReceiverUrl | string | `""` | | +| controlplane.affinity | object | `{}` | | +| controlplane.autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | +| controlplane.autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | +| controlplane.autoscaling.minReplicas | int | `1` | Minimal replicas if resource consumption falls below resource threshholds | +| controlplane.autoscaling.targetCPUUtilizationPercentage | int | `80` | targetAverageUtilization of cpu provided to a pod | +| controlplane.autoscaling.targetMemoryUtilizationPercentage | int | `80` | targetAverageUtilization of memory provided to a pod | +| controlplane.businessPartnerValidation.log.agreementValidation | bool | `true` | | +| controlplane.debug.enabled | bool | `false` | | +| controlplane.debug.port | int | `1044` | | +| controlplane.debug.suspendOnStart | bool | `false` | | +| controlplane.endpoints | object | `{"control":{"path":"/control","port":8083},"default":{"path":"/api","port":8080},"management":{"authKey":"","path":"/management","port":8081},"metrics":{"path":"/metrics","port":9090},"observability":{"insecure":true,"path":"/observability","port":8085},"protocol":{"path":"/api/v1/dsp","port":8084}}` | endpoints of the control plane | +| controlplane.endpoints.control | object | `{"path":"/control","port":8083}` | control api, used for internal control calls. can be added to the internal ingress, but should probably not | +| controlplane.endpoints.control.path | string | `"/control"` | path for incoming api calls | +| controlplane.endpoints.control.port | int | `8083` | port for incoming api calls | +| controlplane.endpoints.default | object | `{"path":"/api","port":8080}` | default api for health checks, should not be added to any ingress | +| controlplane.endpoints.default.path | string | `"/api"` | path for incoming api calls | +| controlplane.endpoints.default.port | int | `8080` | port for incoming api calls | +| controlplane.endpoints.management | object | `{"authKey":"","path":"/management","port":8081}` | data management api, used by internal users, can be added to an ingress and must not be internet facing | +| controlplane.endpoints.management.authKey | string | `""` | authentication key, must be attached to each 'X-Api-Key' request header | +| controlplane.endpoints.management.path | string | `"/management"` | path for incoming api calls | +| controlplane.endpoints.management.port | int | `8081` | port for incoming api calls | +| controlplane.endpoints.metrics | object | `{"path":"/metrics","port":9090}` | metrics api, used for application metrics, must not be internet facing | +| controlplane.endpoints.metrics.path | string | `"/metrics"` | path for incoming api calls | +| controlplane.endpoints.metrics.port | int | `9090` | port for incoming api calls | +| controlplane.endpoints.observability | object | `{"insecure":true,"path":"/observability","port":8085}` | observability api with unsecured access, must not be internet facing | +| controlplane.endpoints.observability.insecure | bool | `true` | allow or disallow insecure access, i.e. access without authentication | +| controlplane.endpoints.observability.path | string | `"/observability"` | observability api, provides /health /readiness and /liveness endpoints | +| controlplane.endpoints.observability.port | int | `8085` | port for incoming API calls | +| controlplane.endpoints.protocol | object | `{"path":"/api/v1/dsp","port":8084}` | ids api, used for inter connector communication and must be internet facing | +| controlplane.endpoints.protocol.path | string | `"/api/v1/dsp"` | path for incoming api calls | +| controlplane.endpoints.protocol.port | int | `8084` | port for incoming api calls | +| controlplane.env | object | `{}` | | +| controlplane.envConfigMapNames | list | `[]` | | +| controlplane.envSecretNames | list | `[]` | | +| controlplane.envValueFrom | object | `{}` | | +| controlplane.image.pullPolicy | string | `"IfNotPresent"` | [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use | +| controlplane.image.repository | string | `""` | Which derivate of the control plane to use. when left empty the deployment will select the correct image automatically | +| controlplane.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion | +| controlplane.ingresses[0].annotations | object | `{}` | Additional ingress annotations to add | +| controlplane.ingresses[0].certManager.clusterIssuer | string | `""` | If preset enables certificate generation via cert-manager cluster-wide issuer | +| controlplane.ingresses[0].certManager.issuer | string | `""` | If preset enables certificate generation via cert-manager namespace scoped issuer | +| controlplane.ingresses[0].className | string | `""` | Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use | +| controlplane.ingresses[0].enabled | bool | `false` | | +| controlplane.ingresses[0].endpoints | list | `["protocol"]` | EDC endpoints exposed by this ingress resource | +| controlplane.ingresses[0].hostname | string | `"edc-control.local"` | The hostname to be used to precisely map incoming traffic onto the underlying network service | +| controlplane.ingresses[0].tls | object | `{"enabled":false,"secretName":""}` | TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource | +| controlplane.ingresses[0].tls.enabled | bool | `false` | Enables TLS on the ingress resource | +| controlplane.ingresses[0].tls.secretName | string | `""` | If present overwrites the default secret name | +| controlplane.ingresses[1].annotations | object | `{}` | Additional ingress annotations to add | +| controlplane.ingresses[1].certManager.clusterIssuer | string | `""` | If preset enables certificate generation via cert-manager cluster-wide issuer | +| controlplane.ingresses[1].certManager.issuer | string | `""` | If preset enables certificate generation via cert-manager namespace scoped issuer | +| controlplane.ingresses[1].className | string | `""` | Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use | +| controlplane.ingresses[1].enabled | bool | `false` | | +| controlplane.ingresses[1].endpoints | list | `["management","control"]` | EDC endpoints exposed by this ingress resource | +| controlplane.ingresses[1].hostname | string | `"edc-control.intranet"` | The hostname to be used to precisely map incoming traffic onto the underlying network service | +| controlplane.ingresses[1].tls | object | `{"enabled":false,"secretName":""}` | TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource | +| controlplane.ingresses[1].tls.enabled | bool | `false` | Enables TLS on the ingress resource | +| controlplane.ingresses[1].tls.secretName | string | `""` | If present overwrites the default secret name | +| controlplane.initContainers | list | `[]` | | +| controlplane.internationalDataSpaces.catalogId | string | `"TXDC-Catalog"` | | +| controlplane.internationalDataSpaces.curator | string | `""` | | +| controlplane.internationalDataSpaces.description | string | `"Tractus-X Eclipse IDS Data Space Connector"` | | +| controlplane.internationalDataSpaces.id | string | `"TXDC"` | | +| controlplane.internationalDataSpaces.maintainer | string | `""` | | +| controlplane.internationalDataSpaces.title | string | `""` | | +| controlplane.livenessProbe.enabled | bool | `true` | Whether to enable kubernetes [liveness-probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | +| controlplane.livenessProbe.failureThreshold | int | `6` | when a probe fails kubernetes will try 6 times before giving up | +| controlplane.livenessProbe.initialDelaySeconds | int | `30` | seconds to wait before performing the first liveness check | +| controlplane.livenessProbe.periodSeconds | int | `10` | this fields specifies that kubernetes should perform a liveness check every 10 seconds | +| controlplane.livenessProbe.successThreshold | int | `1` | number of consecutive successes for the probe to be considered successful after having failed | +| controlplane.livenessProbe.timeoutSeconds | int | `5` | number of seconds after which the probe times out | +| controlplane.logging | string | `".level=INFO\norg.eclipse.edc.level=ALL\nhandlers=java.util.logging.ConsoleHandler\njava.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter\njava.util.logging.ConsoleHandler.level=ALL\njava.util.logging.SimpleFormatter.format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS] [%4$-7s] %5$s%6$s%n"` | configuration of the [Java Util Logging Facade](https://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview.html) | +| controlplane.nodeSelector | object | `{}` | | +| controlplane.opentelemetry | string | `"otel.javaagent.enabled=false\notel.javaagent.debug=false"` | configuration of the [Open Telemetry Agent](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/) to collect and expose metrics | +| controlplane.podAnnotations | object | `{}` | additional annotations for the pod | +| controlplane.podLabels | object | `{}` | additional labels for the pod | +| controlplane.podSecurityContext | object | `{"fsGroup":10001,"runAsGroup":10001,"runAsUser":10001,"seccompProfile":{"type":"RuntimeDefault"}}` | The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment | +| controlplane.podSecurityContext.fsGroup | int | `10001` | The owner for volumes and any files created within volumes will belong to this guid | +| controlplane.podSecurityContext.runAsGroup | int | `10001` | Processes within a pod will belong to this guid | +| controlplane.podSecurityContext.runAsUser | int | `10001` | Runs all processes within a pod with a special uid | +| controlplane.podSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` | Restrict a Container's Syscalls with seccomp | +| controlplane.readinessProbe.enabled | bool | `true` | Whether to enable kubernetes [readiness-probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | +| controlplane.readinessProbe.failureThreshold | int | `6` | when a probe fails kubernetes will try 6 times before giving up | +| controlplane.readinessProbe.initialDelaySeconds | int | `30` | seconds to wait before performing the first readiness check | +| controlplane.readinessProbe.periodSeconds | int | `10` | this fields specifies that kubernetes should perform a readiness check every 10 seconds | +| controlplane.readinessProbe.successThreshold | int | `1` | number of consecutive successes for the probe to be considered successful after having failed | +| controlplane.readinessProbe.timeoutSeconds | int | `5` | number of seconds after which the probe times out | +| controlplane.replicaCount | int | `1` | | +| controlplane.resources | object | `{}` | [resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) for the container | +| controlplane.securityContext.allowPrivilegeEscalation | bool | `false` | Controls [Privilege Escalation](https://kubernetes.io/docs/concepts/security/pod-security-policy/#privilege-escalation) enabling setuid binaries changing the effective user ID | +| controlplane.securityContext.capabilities.add | list | `[]` | Specifies which capabilities to add to issue specialized syscalls | +| controlplane.securityContext.capabilities.drop | list | `["ALL"]` | Specifies which capabilities to drop to reduce syscall attack surface | +| controlplane.securityContext.readOnlyRootFilesystem | bool | `true` | Whether the root filesystem is mounted in read-only mode | +| controlplane.securityContext.runAsNonRoot | bool | `true` | Requires the container to run without root privileges | +| controlplane.securityContext.runAsUser | int | `10001` | The container's process will run with the specified uid | +| controlplane.service.annotations | object | `{}` | | +| controlplane.service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | +| controlplane.tolerations | list | `[]` | | +| controlplane.url.ids | string | `""` | Explicitly declared url for reaching the ids api (e.g. if ingresses not used) | +| controlplane.volumeMounts | list | `[]` | declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container | +| controlplane.volumes | list | `[]` | [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories | +| customLabels | object | `{}` | | +| daps.clientId | string | `""` | | +| daps.connectors[0].attributes.referringConnector | string | `"http://sokrates-controlplane/BPNSOKRATES"` | | +| daps.connectors[0].certificate | string | `""` | | +| daps.connectors[0].id | string | `"E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65"` | | +| daps.connectors[0].name | string | `"sokrates"` | | +| daps.paths.jwks | string | `"/jwks.json"` | | +| daps.paths.token | string | `"/token"` | | +| daps.url | string | `"http://{{ .Release.Name }}-daps:4567"` | | +| dataplane.affinity | object | `{}` | | +| dataplane.autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | +| dataplane.autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | +| dataplane.autoscaling.minReplicas | int | `1` | Minimal replicas if resource consumption falls below resource threshholds | +| dataplane.autoscaling.targetCPUUtilizationPercentage | int | `80` | targetAverageUtilization of cpu provided to a pod | +| dataplane.autoscaling.targetMemoryUtilizationPercentage | int | `80` | targetAverageUtilization of memory provided to a pod | +| dataplane.aws.accessKeyId | string | `""` | | +| dataplane.aws.endpointOverride | string | `""` | | +| dataplane.aws.secretAccessKey | string | `""` | | +| dataplane.debug.enabled | bool | `false` | | +| dataplane.debug.port | int | `1044` | | +| dataplane.debug.suspendOnStart | bool | `false` | | +| dataplane.endpoints.control.path | string | `"/api/dataplane/control"` | | +| dataplane.endpoints.control.port | int | `8083` | | +| dataplane.endpoints.default.path | string | `"/api"` | | +| dataplane.endpoints.default.port | int | `8080` | | +| dataplane.endpoints.metrics.path | string | `"/metrics"` | | +| dataplane.endpoints.metrics.port | int | `9090` | | +| dataplane.endpoints.observability.insecure | bool | `true` | allow or disallow insecure access, i.e. access without authentication | +| dataplane.endpoints.observability.path | string | `"/observability"` | observability api, provides /health /readiness and /liveness endpoints | +| dataplane.endpoints.observability.port | int | `8085` | port for incoming API calls | +| dataplane.endpoints.proxy.path | string | `"/proxy"` | | +| dataplane.endpoints.proxy.port | int | `8186` | | +| dataplane.endpoints.public.path | string | `"/api/public"` | | +| dataplane.endpoints.public.port | int | `8081` | | +| dataplane.env | object | `{}` | | +| dataplane.envConfigMapNames | list | `[]` | | +| dataplane.envSecretNames | list | `[]` | | +| dataplane.envValueFrom | object | `{}` | | +| dataplane.image.pullPolicy | string | `"IfNotPresent"` | [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use | +| dataplane.image.repository | string | `""` | Which derivate of the data plane to use. when left empty the deployment will select the correct image automatically | +| dataplane.image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion | +| dataplane.ingresses[0].annotations | object | `{}` | Additional ingress annotations to add | +| dataplane.ingresses[0].certManager.clusterIssuer | string | `""` | If preset enables certificate generation via cert-manager cluster-wide issuer | +| dataplane.ingresses[0].certManager.issuer | string | `""` | If preset enables certificate generation via cert-manager namespace scoped issuer | +| dataplane.ingresses[0].className | string | `""` | Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use | +| dataplane.ingresses[0].enabled | bool | `false` | | +| dataplane.ingresses[0].endpoints | list | `["public"]` | EDC endpoints exposed by this ingress resource | +| dataplane.ingresses[0].hostname | string | `"edc-data.local"` | The hostname to be used to precisely map incoming traffic onto the underlying network service | +| dataplane.ingresses[0].tls | object | `{"enabled":false,"secretName":""}` | TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource | +| dataplane.ingresses[0].tls.enabled | bool | `false` | Enables TLS on the ingress resource | +| dataplane.ingresses[0].tls.secretName | string | `""` | If present overwrites the default secret name | +| dataplane.initContainers | list | `[]` | | +| dataplane.livenessProbe.enabled | bool | `true` | Whether to enable kubernetes [liveness-probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | +| dataplane.livenessProbe.failureThreshold | int | `6` | when a probe fails kubernetes will try 6 times before giving up | +| dataplane.livenessProbe.initialDelaySeconds | int | `30` | seconds to wait before performing the first liveness check | +| dataplane.livenessProbe.periodSeconds | int | `10` | this fields specifies that kubernetes should perform a liveness check every 10 seconds | +| dataplane.livenessProbe.successThreshold | int | `1` | number of consecutive successes for the probe to be considered successful after having failed | +| dataplane.livenessProbe.timeoutSeconds | int | `5` | number of seconds after which the probe times out | +| dataplane.logging | string | `".level=INFO\norg.eclipse.edc.level=ALL\nhandlers=java.util.logging.ConsoleHandler\njava.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter\njava.util.logging.ConsoleHandler.level=ALL\njava.util.logging.SimpleFormatter.format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS] [%4$-7s] %5$s%6$s%n"` | configuration of the [Java Util Logging Facade](https://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview.html) | +| dataplane.nodeSelector | object | `{}` | | +| dataplane.opentelemetry | string | `"otel.javaagent.enabled=false\notel.javaagent.debug=false"` | configuration of the [Open Telemetry Agent](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/) to collect and expose metrics | +| dataplane.podAnnotations | object | `{}` | additional annotations for the pod | +| dataplane.podLabels | object | `{}` | additional labels for the pod | +| dataplane.podSecurityContext | object | `{"fsGroup":10001,"runAsGroup":10001,"runAsUser":10001,"seccompProfile":{"type":"RuntimeDefault"}}` | The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment | +| dataplane.podSecurityContext.fsGroup | int | `10001` | The owner for volumes and any files created within volumes will belong to this guid | +| dataplane.podSecurityContext.runAsGroup | int | `10001` | Processes within a pod will belong to this guid | +| dataplane.podSecurityContext.runAsUser | int | `10001` | Runs all processes within a pod with a special uid | +| dataplane.podSecurityContext.seccompProfile.type | string | `"RuntimeDefault"` | Restrict a Container's Syscalls with seccomp | +| dataplane.readinessProbe.enabled | bool | `true` | Whether to enable kubernetes [readiness-probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) | +| dataplane.readinessProbe.failureThreshold | int | `6` | when a probe fails kubernetes will try 6 times before giving up | +| dataplane.readinessProbe.initialDelaySeconds | int | `30` | seconds to wait before performing the first readiness check | +| dataplane.readinessProbe.periodSeconds | int | `10` | this fields specifies that kubernetes should perform a liveness check every 10 seconds | +| dataplane.readinessProbe.successThreshold | int | `1` | number of consecutive successes for the probe to be considered successful after having failed | +| dataplane.readinessProbe.timeoutSeconds | int | `5` | number of seconds after which the probe times out | +| dataplane.replicaCount | int | `1` | | +| dataplane.resources | object | `{}` | [resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) for the container | +| dataplane.securityContext.allowPrivilegeEscalation | bool | `false` | Controls [Privilege Escalation](https://kubernetes.io/docs/concepts/security/pod-security-policy/#privilege-escalation) enabling setuid binaries changing the effective user ID | +| dataplane.securityContext.capabilities.add | list | `[]` | Specifies which capabilities to add to issue specialized syscalls | +| dataplane.securityContext.capabilities.drop | list | `["ALL"]` | Specifies which capabilities to drop to reduce syscall attack surface | +| dataplane.securityContext.readOnlyRootFilesystem | bool | `true` | Whether the root filesystem is mounted in read-only mode | +| dataplane.securityContext.runAsNonRoot | bool | `true` | Requires the container to run without root privileges | +| dataplane.securityContext.runAsUser | int | `10001` | The container's process will run with the specified uid | +| dataplane.service.port | int | `80` | | +| dataplane.service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | +| dataplane.tolerations | list | `[]` | | +| dataplane.url.public | string | `""` | Explicitly declared url for reaching the public api (e.g. if ingresses not used) | +| dataplane.volumeMounts | list | `[]` | declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container | +| dataplane.volumes | list | `[]` | [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories | +| fullnameOverride | string | `""` | | +| idsdaps.connectors[0].certificate | string | `""` | | +| imagePullSecrets | list | `[]` | Existing image pull secret to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | +| install.daps | bool | `true` | | +| install.postgresql | bool | `true` | | +| install.vault | bool | `true` | | +| nameOverride | string | `""` | | +| networkPolicy.controlplane | object | `{"from":[{"namespaceSelector":{}}]}` | Configuration of the controlplane component | +| networkPolicy.controlplane.from | list | `[{"namespaceSelector":{}}]` | Specify from rule network policy for cp (defaults to all namespaces) | +| networkPolicy.dataplane | object | `{"from":[{"namespaceSelector":{}}]}` | Configuration of the dataplane component | +| networkPolicy.dataplane.from | list | `[{"namespaceSelector":{}}]` | Specify from rule network policy for dp (defaults to all namespaces) | +| networkPolicy.enabled | bool | `false` | If `true` network policy will be created to restrict access to control- and dataplane | +| participant.id | string | `""` | | +| postgresql.auth.database | string | `"edc"` | | +| postgresql.auth.password | string | `"password"` | | +| postgresql.auth.username | string | `"user"` | | +| postgresql.jdbcUrl | string | `"jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc"` | | +| postgresql.primary.persistence.enabled | bool | `false` | | +| postgresql.readReplicas.persistence.enabled | bool | `false` | | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.create | bool | `true` | | +| serviceAccount.imagePullSecrets | list | `[]` | Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | +| serviceAccount.name | string | `""` | | +| tests | object | `{"hookDeletePolicy":"before-hook-creation,hook-succeeded"}` | Configurations for Helm tests | +| tests.hookDeletePolicy | string | `"before-hook-creation,hook-succeeded"` | Configure the hook-delete-policy for Helm tests | +| vault.hashicorp.healthCheck.enabled | bool | `true` | | +| vault.hashicorp.healthCheck.standbyOk | bool | `true` | | +| vault.hashicorp.paths.health | string | `"/v1/sys/health"` | | +| vault.hashicorp.paths.secret | string | `"/v1/secret"` | | +| vault.hashicorp.timeout | int | `30` | | +| vault.hashicorp.token | string | `""` | | +| vault.hashicorp.url | string | `"http://{{ .Release.Name }}-vault:8200"` | | +| vault.injector.enabled | bool | `false` | | +| vault.secretNames.dapsPrivateKey | string | `"daps-private-key"` | | +| vault.secretNames.dapsPublicKey | string | `"daps-public-key"` | | +| vault.secretNames.transferProxyTokenEncryptionAesKey | string | `"transfer-proxy-token-encryption-aes-key"` | | +| vault.secretNames.transferProxyTokenSignerPrivateKey | string | `"transfer-proxy-token-signer-private-key"` | | +| vault.secretNames.transferProxyTokenSignerPublicKey | string | `"transfer-proxy-token-signer-public-key"` | | +| vault.server.dev.devRootToken | string | `"root"` | | +| vault.server.dev.enabled | bool | `true` | | +| vault.server.postStart | string | `nil` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/charts/tractusx-connector-legacy/README.md.gotmpl b/charts/tractusx-connector-legacy/README.md.gotmpl new file mode 100644 index 000000000..210216e6c --- /dev/null +++ b/charts/tractusx-connector-legacy/README.md.gotmpl @@ -0,0 +1,51 @@ +{{ template "chart.header" . }} + +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.badgesSection" . }} + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +This chart uses Hashicorp Vault, which is expected to contain the following secrets on application start: + +- `daps-cert`: contains the x509 certificate of the connector. +- `daps-key`: the private key of the x509 certificate +- `aes-keys`: a 128bit, 256bit or 512bit string used to encrypt data. Must be stored in base64 format. + +These must be obtained from a DAPS instance, the process of which is out of the scope of this document. Alternatively, +self-signed certificates can be used for testing: + +```shell +openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout daps.key -out daps.cert -subj "/CN=test" +export DAPS_KEY="$(cat daps.key)" +export DAPS_CERT="$(cat daps.cert)" +``` + +## Launching the application + +The following requirements must be met before launching the application: + +- Write access to a HashiCorp Vault instance is required to run this chart +- Secrets are seeded in advance + +Please also consider using [this example configuration](https://github.com/eclipse-tractusx/tractusx-edc/blob/main/edc-tests/deployment/src/main/resources/helm/tractusx-connector-test.yaml) +to launch the application. +Combined, run this shell command to start the in-memory Tractus-X EDC runtime: + +```shell +helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev +helm install my-release tractusx-edc/tractusx-connector --version {{ .Version }} \ + -f /tractusx-connector-test.yaml +``` + +{{ template "chart.maintainersSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.valuesSection" . }} + +{{ template "helm-docs.versionFooter" . }} diff --git a/charts/tractusx-connector-legacy/example.values.yaml b/charts/tractusx-connector-legacy/example.values.yaml new file mode 100644 index 000000000..d2b082afa --- /dev/null +++ b/charts/tractusx-connector-legacy/example.values.yaml @@ -0,0 +1,97 @@ +# +# Copyright (c) 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +fullnameOverride: tx-prod +################################ +# EDC ControlPlane + DataPlane # +################################ +participant: + id: "test-participant" +controlplane: + service: + type: NodePort + endpoints: + management: + authKey: password + image: + pullPolicy: Never + tag: "latest" + repository: "edc-controlplane-postgresql-hashicorp-vault-legacy" + securityContext: + # avoids some errors in the log: cannot write temp files of large multipart requests when R/O + readOnlyRootFilesystem: false +dataplane: + image: + pullPolicy: Never + tag: "latest" + repository: "edc-dataplane-hashicorp-vault" + securityContext: + # avoids some errors in the log: cannot write temp files of large multipart requests when R/O + readOnlyRootFilesystem: false + aws: + endpointOverride: http://minio:9000 + secretAccessKey: qwerty123 + accessKeyId: qwerty123 +postgresql: + jdbcUrl: jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc + auth: + username: user + password: password +vault: + hashicorp: + url: http://{{ .Release.Name }}-vault:8200 + token: root + secretNames: + transferProxyTokenSignerPublicKey: daps-crt + transferProxyTokenSignerPrivateKey: daps-key + transferProxyTokenEncryptionAesKey: aes-keys + dapsPrivateKey: daps-key + dapsPublicKey: daps-crt + server: + postStart: + - sh + - -c + - |- + { + sleep 5 + + cat << EOF | /bin/vault kv put secret/daps-crt content=- + <<< ENTER CERTIFICATE CONTENT HERE!!! >>> + EOF + + + cat << EOF | /bin/vault kv put secret/daps-key content=- + <<< ENTER PRIVATE KEY CONTENT HERE !!! >>> + EOF + + + /bin/vault kv put secret/aes-keys content=YWVzX2VuY2tleV90ZXN0Cg== + + } +daps: + url: "http://{{ .Release.Name }}-daps:4567" + clientId: "E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65" +backendService: + httpProxyTokenReceiverUrl: "http://backend:8080" +tests: + hookDeletePolicy: before-hook-creation +idsdaps: + connectors: + - certificate: |- + <<< ENTER CERTIFICATE CONTENT HERE!!! >>> diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/.helmignore b/charts/tractusx-connector-legacy/subcharts/omejdn/.helmignore similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/.helmignore rename to charts/tractusx-connector-legacy/subcharts/omejdn/.helmignore diff --git a/docs/samples/example-dataspace/daps/Chart.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/Chart.yaml similarity index 99% rename from docs/samples/example-dataspace/daps/Chart.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/Chart.yaml index f0a4e6e4e..a41ff8bd4 100644 --- a/docs/samples/example-dataspace/daps/Chart.yaml +++ b/charts/tractusx-connector-legacy/subcharts/omejdn/Chart.yaml @@ -20,7 +20,6 @@ apiVersion: v2 name: daps description: A Helm chart for Kubernetes - # A chart can be either an 'application' or a 'library' chart. # # Application charts are a collection of templates that can be packaged into versioned archives @@ -30,12 +29,10 @@ description: A Helm chart for Kubernetes # a dependency of application charts to inject those utilities and functions into the rendering # pipeline. Library charts do not define any templates and therefore cannot be deployed. type: application - # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) version: 0.0.1 - # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. diff --git a/docs/samples/example-dataspace/daps/README.md b/charts/tractusx-connector-legacy/subcharts/omejdn/README.md similarity index 100% rename from docs/samples/example-dataspace/daps/README.md rename to charts/tractusx-connector-legacy/subcharts/omejdn/README.md diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/_helpers.tpl b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/_helpers.tpl similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/_helpers.tpl rename to charts/tractusx-connector-legacy/subcharts/omejdn/templates/_helpers.tpl diff --git a/charts/tractusx-connector/subcharts/omejdn/templates/configmap.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/configmap.yaml similarity index 96% rename from charts/tractusx-connector/subcharts/omejdn/templates/configmap.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/templates/configmap.yaml index 5ad21648d..0f007ed8d 100644 --- a/charts/tractusx-connector/subcharts/omejdn/templates/configmap.yaml +++ b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/configmap.yaml @@ -31,7 +31,7 @@ data: omejdn.yml: |- --- - host: http://daps:4567/ + host: http://{{ .Release.Name }}-daps:4567/ path_prefix: '' bind_to: 0.0.0.0 allow_origin: "*" @@ -41,7 +41,7 @@ data: - yaml user_backend_default: yaml accept_audience: idsc:IDS_CONNECTORS_ALL - issuer: http://daps:4567/ + issuer: http://{{ .Release.Name }}-daps:4567/ environment: development default_audience: - idsc:IDS_CONNECTORS_ALL diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/deployment.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/deployment.yaml similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/deployment.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/templates/deployment.yaml diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/hpa.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/hpa.yaml similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/hpa.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/templates/hpa.yaml diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/imagepullsecret.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/imagepullsecret.yaml similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/imagepullsecret.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/templates/imagepullsecret.yaml diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/service.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/service.yaml similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/service.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/templates/service.yaml diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/serviceaccount.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/templates/serviceaccount.yaml similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/templates/serviceaccount.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/templates/serviceaccount.yaml diff --git a/charts/tractusx-connector-azure-vault/subcharts/omejdn/values.yaml b/charts/tractusx-connector-legacy/subcharts/omejdn/values.yaml similarity index 100% rename from charts/tractusx-connector-azure-vault/subcharts/omejdn/values.yaml rename to charts/tractusx-connector-legacy/subcharts/omejdn/values.yaml diff --git a/charts/tractusx-connector-legacy/templates/NOTES.txt b/charts/tractusx-connector-legacy/templates/NOTES.txt new file mode 100644 index 000000000..254cf9c67 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/NOTES.txt @@ -0,0 +1,45 @@ +1. Get the control plane URL by running these commands: +{{ with index .Values.controlplane.ingresses 0}} +{{- if .enabled }} +{{- range .paths }} + http{{ if .tls }}s{{ end }}://{{ .hostname }}{{ .path }} +{{- end }} +{{- else if contains "NodePort" $.Values.controlplane.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ $.Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "txdc.fullname" $ }}) + export NODE_IP=$(kubectl get nodes --namespace {{ $.Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" $.Values.controlplane.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "txdc.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "txdc.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ $.Values.controlplane.service.port }} +{{- else if contains "ClusterIP" $.Values.controlplane.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ $.Release.Namespace }} -l "app.kubernetes.io/name={{ include "txdc.name" $ }},app.kubernetes.io/instance={{ $.Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ $.Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ $.Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} +{{- end }} + +2. Get the data plane URL by running these commands: +{{ with index .Values.controlplane.ingresses 0}} +{{- if .enabled }} +{{- range .paths }} + http{{ if .tls }}s{{ end }}://{{ .hostname }}{{ .path }} +{{- end }} +{{- else if contains "NodePort" $.Values.dataplane.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ $.Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "txdc.fullname" $ }}) + export NODE_IP=$(kubectl get nodes --namespace {{ $.Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" $.Values.dataplane.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ $.Release.Namespace }} svc -w {{ include "txdc.fullname" $ }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "txdc.fullname" $ }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" $.Values.dataplane.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ $.Release.Namespace }} -l "app.kubernetes.io/name={{ include "txdc.name" $ }},app.kubernetes.io/instance={{ $.Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ $.Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ $.Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} +{{- end }} diff --git a/charts/tractusx-connector-legacy/templates/_helpers.tpl b/charts/tractusx-connector-legacy/templates/_helpers.tpl new file mode 100644 index 000000000..701e6fc75 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/_helpers.tpl @@ -0,0 +1,175 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "txdc.name" -}} +{{- default .Chart.Name .Values.nameOverride | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "txdc.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "txdc.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Control Common labels +*/}} +{{- define "txdc.labels" -}} +helm.sh/chart: {{ include "txdc.chart" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Control Common labels +*/}} +{{- define "txdc.controlplane.labels" -}} +helm.sh/chart: {{ include "txdc.chart" . }} +{{ include "txdc.controlplane.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: edc-controlplane +app.kubernetes.io/part-of: edc +{{- end }} + +{{/* +Data Common labels +*/}} +{{- define "txdc.dataplane.labels" -}} +helm.sh/chart: {{ include "txdc.chart" . }} +{{ include "txdc.dataplane.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +app.kubernetes.io/component: edc-dataplane +app.kubernetes.io/part-of: edc +{{- end }} + +{{/* +Control Selector labels +*/}} +{{- define "txdc.controlplane.selectorLabels" -}} +app.kubernetes.io/name: {{ include "txdc.name" . }}-controlplane +app.kubernetes.io/instance: {{ .Release.Name }}-controlplane +{{- end }} + +{{/* +Data Selector labels +*/}} +{{- define "txdc.dataplane.selectorLabels" -}} +app.kubernetes.io/name: {{ include "txdc.name" . }}-dataplane +app.kubernetes.io/instance: {{ .Release.Name }}-dataplane +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "txdc.controlplane.serviceaccount.name" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "txdc.fullname" . ) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "txdc.dataplane.serviceaccount.name" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "txdc.fullname" . ) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Control IDS URL +*/}} +{{- define "txdc.controlplane.url.protocol" -}} +{{- if .Values.controlplane.url.protocol }}{{/* if ids api url has been specified explicitly */}} +{{- .Values.controlplane.url.protocol }} +{{- else }}{{/* else when ids api url has not been specified explicitly */}} +{{- with (index .Values.controlplane.ingresses 0) }} +{{- if .enabled }}{{/* if ingress enabled */}} +{{- if .tls.enabled }}{{/* if TLS enabled */}} +{{- printf "https://%s" .hostname -}} +{{- else }}{{/* else when TLS not enabled */}} +{{- printf "http://%s" .hostname -}} +{{- end }}{{/* end if tls */}} +{{- else }}{{/* else when ingress not enabled */}} +{{- printf "http://%s-controlplane:%v" ( include "txdc.fullname" $ ) $.Values.controlplane.endpoints.protocol.port -}} +{{- end }}{{/* end if ingress */}} +{{- end }}{{/* end with ingress */}} +{{- end }}{{/* end if .Values.controlplane.url.protocol */}} +{{- end }} + +{{/* +Validation URL +*/}} +{{- define "txdc.controlplane.url.validation" -}} +{{- printf "http://%s-controlplane:%v%s/token" ( include "txdc.fullname" $ ) $.Values.controlplane.endpoints.control.port $.Values.controlplane.endpoints.control.path -}} +{{- end }} + +{{/* +Data Control URL +*/}} +{{- define "txdc.dataplane.url.control" -}} +{{- printf "http://%s-dataplane:%v%s" (include "txdc.fullname" . ) .Values.dataplane.endpoints.control.port .Values.dataplane.endpoints.control.path -}} +{{- end }} + +{{/* +Data Public URL +*/}} +{{- define "txdc.dataplane.url.public" -}} +{{- if .Values.dataplane.url.public }}{{/* if public api url has been specified explicitly */}} +{{- .Values.dataplane.url.public }} +{{- else }}{{/* else when public api url has not been specified explicitly */}} +{{- with (index .Values.dataplane.ingresses 0) }} +{{- if .enabled }}{{/* if ingress enabled */}} +{{- if .tls.enabled }}{{/* if TLS enabled */}} +{{- printf "https://%s%s" .hostname $.Values.dataplane.endpoints.public.path -}} +{{- else }}{{/* else when TLS not enabled */}} +{{- printf "http://%s%s" .hostname $.Values.dataplane.endpoints.public.path -}} +{{- end }}{{/* end if tls */}} +{{- else }}{{/* else when ingress not enabled */}} +{{- printf "http://%s-dataplane:%v%s" (include "txdc.fullname" $ ) $.Values.dataplane.endpoints.public.port $.Values.dataplane.endpoints.public.path -}} +{{- end }}{{/* end if ingress */}} +{{- end }}{{/* end with ingress */}} +{{- end }}{{/* end if .Values.dataplane.url.public */}} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "txdc.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "txdc.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/templates/service.yaml b/charts/tractusx-connector-legacy/templates/configmap-controlplane.yaml similarity index 53% rename from charts/tractusx-connector-memory/subcharts/omejdn/templates/service.yaml rename to charts/tractusx-connector-legacy/templates/configmap-controlplane.yaml index 947e69742..42f2a493f 100644 --- a/charts/tractusx-connector-memory/subcharts/omejdn/templates/service.yaml +++ b/charts/tractusx-connector-legacy/templates/configmap-controlplane.yaml @@ -1,4 +1,8 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -15,20 +19,18 @@ # # SPDX-License-Identifier: Apache-2.0 # - + --- apiVersion: v1 -kind: Service +kind: ConfigMap metadata: - name: {{ include "omejdn.fullname" . }} + name: {{ include "txdc.fullname" . }}-controlplane + namespace: {{ .Release.Namespace | default "default" | quote }} labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "omejdn.selectorLabels" . | nindent 4 }} + {{- include "txdc.controlplane.labels" . | nindent 4 }} +data: + opentelemetry.properties: |- + {{- .Values.controlplane.opentelemetry | nindent 4 }} + + logging.properties: |- + {{- .Values.controlplane.logging | nindent 4 }} diff --git a/charts/tractusx-connector/subcharts/omejdn/templates/service.yaml b/charts/tractusx-connector-legacy/templates/configmap-dataplane.yaml similarity index 54% rename from charts/tractusx-connector/subcharts/omejdn/templates/service.yaml rename to charts/tractusx-connector-legacy/templates/configmap-dataplane.yaml index 947e69742..87fd401c3 100644 --- a/charts/tractusx-connector/subcharts/omejdn/templates/service.yaml +++ b/charts/tractusx-connector-legacy/templates/configmap-dataplane.yaml @@ -1,4 +1,8 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -18,17 +22,15 @@ --- apiVersion: v1 -kind: Service +kind: ConfigMap metadata: - name: {{ include "omejdn.fullname" . }} + name: {{ include "txdc.fullname" . }}-dataplane + namespace: {{ .Release.Namespace | default "default" | quote }} labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "omejdn.selectorLabels" . | nindent 4 }} + {{- include "txdc.dataplane.labels" . | nindent 4 }} +data: + opentelemetry.properties: |- + {{- .Values.dataplane.opentelemetry | nindent 4 }} + + logging.properties: |- + {{- .Values.dataplane.logging | nindent 4 }} diff --git a/charts/tractusx-connector-legacy/templates/deployment-controlplane.yaml b/charts/tractusx-connector-legacy/templates/deployment-controlplane.yaml new file mode 100644 index 000000000..35f84ea15 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/deployment-controlplane.yaml @@ -0,0 +1,361 @@ +# + # Copyright (c) 2023 ZF Friedrichshafen AG + # Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH + # Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + # Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # 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 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + # License for the specific language governing permissions and limitations + # under the License. + # + # SPDX-License-Identifier: Apache-2.0 + # + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "txdc.fullname" . }}-controlplane + labels: + {{- include "txdc.controlplane.labels" . | nindent 4 }} +spec: + {{- if not .Values.controlplane.autoscaling.enabled }} + replicas: {{ .Values.controlplane.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "txdc.controlplane.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.controlplane.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "txdc.controlplane.selectorLabels" . | nindent 8 }} + {{- with .Values.controlplane.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "txdc.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.controlplane.podSecurityContext | nindent 8 }} + initContainers: + {{- toYaml .Values.controlplane.initContainers | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.controlplane.securityContext | nindent 12 }} + + # either use the specified image, or use the default one + {{- if .Values.controlplane.image.repository }} + image: "{{ .Values.controlplane.image.repository }}:{{ .Values.controlplane.image.tag | default .Chart.AppVersion }}" + {{- else }} + image: "tractusx/edc-controlplane-postgresql-hashicorp-vault-legacy:{{ .Values.controlplane.image.tag | default .Chart.AppVersion }}" + {{- end }} + imagePullPolicy: {{ .Values.controlplane.image.pullPolicy }} + ports: + {{- range $key,$value := .Values.controlplane.endpoints }} + - name: {{ $key }} + containerPort: {{ $value.port }} + protocol: TCP + {{- end }} + {{- if .Values.controlplane.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.controlplane.endpoints.observability.path }}/check/liveness + port: {{ .Values.controlplane.endpoints.observability.port }} + initialDelaySeconds: {{ .Values.controlplane.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.controlplane.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.controlplane.livenessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.controlplane.livenessProbe.failureThreshold }} + successThreshold: {{ .Values.controlplane.livenessProbe.successThreshold }} + {{- end }} + {{- if .Values.controlplane.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: {{ .Values.controlplane.endpoints.observability.path }}/check/readiness + port: {{ .Values.controlplane.endpoints.observability.port }} + initialDelaySeconds: {{ .Values.controlplane.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.controlplane.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.controlplane.readinessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.controlplane.readinessProbe.failureThreshold }} + successThreshold: {{ .Values.controlplane.readinessProbe.successThreshold }} + {{- end }} + resources: + {{- toYaml .Values.controlplane.resources | nindent 12 }} + env: + {{- if .Values.controlplane.debug.enabled }} + - name: "JAVA_TOOL_OPTIONS" + {{- if .Values.controlplane.debug.suspendOnStart }} + value: >- + {{ printf "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=%v" .Values.controlplane.debug.port }} + {{- else }} + value: >- + {{ printf "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=%v" .Values.controlplane.debug.port }} + {{- end }} + {{- end }} + + ######################## + ## ID CONFIGURATION ## + ######################## + - name: EDC_PARTICIPANT_ID + value: {{ .Values.participant.id | required ".Values.participant.id is required" | quote }} + + ######################## + ## DAPS CONFIGURATION ## + ######################## + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/iam/oauth2/oauth2-core + - name: EDC_OAUTH_CLIENT_ID + value: {{ .Values.daps.clientId | required ".Values.daps.clientId is required" | quote }} + - name: EDC_OAUTH_PROVIDER_JWKS_URL + value: {{ printf "%s%s" (tpl .Values.daps.url .) .Values.daps.paths.jwks }} + - name: EDC_OAUTH_TOKEN_URL + value: {{ printf "%s%s" (tpl .Values.daps.url .) .Values.daps.paths.token }} + - name: EDC_OAUTH_PRIVATE_KEY_ALIAS + value: {{ .Values.vault.secretNames.dapsPrivateKey | required ".Values.vault.secretNames.dapsPrivateKey is required" | quote }} + - name: EDC_OAUTH_CERTIFICATE_ALIAS + value: {{ .Values.vault.secretNames.dapsPublicKey | required ".Values.vault.secretNames.dapsPublicKey is required" | quote }} + + ####### + # API # + ####### + - name: "EDC_API_AUTH_KEY" + value: {{ .Values.controlplane.endpoints.management.authKey | required ".Values.controlplane.endpoints.management.authKey is required" | quote }} + - name: "WEB_HTTP_DEFAULT_PORT" + value: {{ .Values.controlplane.endpoints.default.port | quote }} + - name: "WEB_HTTP_DEFAULT_PATH" + value: {{ .Values.controlplane.endpoints.default.path | quote }} + - name: "WEB_HTTP_MANAGEMENT_PORT" + value: {{ .Values.controlplane.endpoints.management.port | quote }} + - name: "WEB_HTTP_MANAGEMENT_PATH" + value: {{ .Values.controlplane.endpoints.management.path | quote }} + - name: "WEB_HTTP_CONTROL_PORT" + value: {{ .Values.controlplane.endpoints.control.port | quote }} + - name: "WEB_HTTP_CONTROL_PATH" + value: {{ .Values.controlplane.endpoints.control.path | quote }} + - name: "WEB_HTTP_PROTOCOL_PORT" + value: {{ .Values.controlplane.endpoints.protocol.port | quote }} + - name: "WEB_HTTP_PROTOCOL_PATH" + value: {{ .Values.controlplane.endpoints.protocol.path | quote }} + - name: "WEB_HTTP_OBSERVABILITY_PORT" + value: {{ .Values.controlplane.endpoints.observability.port | quote}} + - name: "WEB_HTTP_OBSERVABILITY_PATH" + value: {{ .Values.controlplane.endpoints.observability.path | quote}} + - name: "TRACTUSX_API_OBSERVABILITY_ALLOW-INSECURE" + value: {{ .Values.controlplane.endpoints.observability.insecure | quote }} + + ######### + ## DSP ## + ######### + + - name: "EDC_DSP_CALLBACK_ADDRESS" + value: {{ printf "%s%s" (include "txdc.controlplane.url.protocol" .) .Values.controlplane.endpoints.protocol.path | quote }} + - name: "EDC_OAUTH_PROVIDER_AUDIENCE" + value: "idsc:IDS_CONNECTORS_ALL" + - name: "EDC_OAUTH_ENDPOINT_AUDIENCE" + value: {{ printf "%s%s" (include "txdc.controlplane.url.protocol" . ) .Values.controlplane.endpoints.protocol.path | quote }} + + ################ + ## POSTGRESQL ## + ################ + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/asset-index-sql + - name: "EDC_DATASOURCE_ASSET_NAME" + value: "asset" + - name: "EDC_DATASOURCE_ASSET_USER" + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} + - name: "EDC_DATASOURCE_ASSET_PASSWORD" + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} + - name: "EDC_DATASOURCE_ASSET_URL" + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/contract-definition-store-sql + - name: "EDC_DATASOURCE_CONTRACTDEFINITION_NAME" + value: "contractdefinition" + - name: "EDC_DATASOURCE_CONTRACTDEFINITION_USER" + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} + - name: "EDC_DATASOURCE_CONTRACTDEFINITION_PASSWORD" + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} + - name: "EDC_DATASOURCE_CONTRACTDEFINITION_URL" + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/contract-negotiation-store-sql + - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_NAME" + value: "contractnegotiation" + - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_USER" + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} + - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_PASSWORD" + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} + - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_URL" + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/policy-store-sql + - name: "EDC_DATASOURCE_POLICY_NAME" + value: "policy" + - name: "EDC_DATASOURCE_POLICY_USER" + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} + - name: "EDC_DATASOURCE_POLICY_PASSWORD" + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} + - name: "EDC_DATASOURCE_POLICY_URL" + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/transfer-process-store-sql + - name: "EDC_DATASOURCE_TRANSFERPROCESS_NAME" + value: "transferprocess" + - name: "EDC_DATASOURCE_TRANSFERPROCESS_USER" + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} + - name: "EDC_DATASOURCE_TRANSFERPROCESS_PASSWORD" + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} + - name: "EDC_DATASOURCE_TRANSFERPROCESS_URL" + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} + + # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/edr-cache-sql + - name: "EDC_DATASOURCE_EDR_NAME" + value: "edr" + - name: "EDC_DATASOURCE_EDR_USER" + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} + - name: "EDC_DATASOURCE_EDR_PASSWORD" + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} + - name: "EDC_DATASOURCE_EDR_URL" + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} + + ################ + ## DATA PLANE ## + ################ + + # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/dataplane-selector-configuration + - name: "EDC_DATAPLANE_SELECTOR_DEFAULTPLANE_URL" + value: {{ include "txdc.dataplane.url.control" . }}/transfer + - name: "EDC_DATAPLANE_SELECTOR_DEFAULTPLANE_SOURCETYPES" + value: "HttpData,AmazonS3" + - name: "EDC_DATAPLANE_SELECTOR_DEFAULTPLANE_DESTINATIONTYPES" + value: "HttpProxy,AmazonS3" + - name: "EDC_DATAPLANE_SELECTOR_DEFAULTPLANE_PROPERTIES" + value: |- + {{ printf "{ \"publicApiUrl\": \"%s\" }" (include "txdc.dataplane.url.public" . ) }} + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/data-plane-transfer + - name: "EDC_TRANSFER_PROXY_ENDPOINT" + value: {{ include "txdc.dataplane.url.public" . }} + - name: "EDC_TRANSFER_PROXY_TOKEN_SIGNER_PRIVATEKEY_ALIAS" + value: {{ .Values.vault.secretNames.transferProxyTokenSignerPrivateKey | quote }} + - name: "EDC_TRANSFER_PROXY_TOKEN_VERIFIER_PUBLICKEY_ALIAS" + value: {{ .Values.vault.secretNames.transferProxyTokenSignerPublicKey | quote }} + + # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/transfer/transfer-pull-http-dynamic-receiver + + - name: "EDC_RECEIVER_HTTP_DYNAMIC_ENDPOINT" + value: {{ .Values.backendService.httpProxyTokenReceiverUrl | required ".Values.backendService.httpProxyTokenReceiverUrl is required" | quote }} + + ########### + ## VAULT ## + ########### + + # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/hashicorp-vault + - name: "EDC_VAULT_HASHICORP_URL" + value: {{ tpl .Values.vault.hashicorp.url . | quote }} + - name: "EDC_VAULT_HASHICORP_TOKEN" + value: {{ .Values.vault.hashicorp.token | required ".Values.vault.hashicorp.token is required" | quote }} + - name: "EDC_VAULT_HASHICORP_TIMEOUT_SECONDS" + value: {{ .Values.vault.hashicorp.timeout | quote }} + - name: "EDC_VAULT_HASHICORP_HEALTH_CHECK_ENABLED" + value: {{ .Values.vault.hashicorp.healthCheck.enabled | quote }} + - name: "EDC_VAULT_HASHICORP_HEALTH_CHECK_STANDBY_OK" + value: {{ .Values.vault.hashicorp.healthCheck.standbyOk | quote }} + - name: "EDC_VAULT_HASHICORP_API_SECRET_PATH" + value: {{ .Values.vault.hashicorp.paths.secret | quote }} + - name: "EDC_VAULT_HASHICORP_API_HEALTH_CHECK_PATH" + value: {{ .Values.vault.hashicorp.paths.health | quote }} + + ##################### + ## DATA ENCRYPTION ## + ##################### + + # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/data-encryption + - name: "EDC_DATA_ENCRYPTION_KEYS_ALIAS" + value: {{ .Values.vault.secretNames.transferProxyTokenEncryptionAesKey | quote }} + - name: "EDC_DATA_ENCRYPTION_ALGORITHM" + value: "AES" + + ########################### + ## AAS WRAPPER EXTENSION ## + ########################### + - name: "EDC_CP_ADAPTER_CACHE_CATALOG_EXPIRE_AFTER" + value: "0" + - name: "EDC_CP_ADAPTER_REUSE_CONTRACT_AGREEMENT" + value: "0" + + ########################### + ## BUSINESS PARTNER NUMBER VALIDATION EXTENSION ## + ########################### + - name: "TRACTUSX_BUSINESSPARTNERVALIDATION_LOG_AGREEMENT_VALIDATION" + value: {{ .Values.controlplane.businessPartnerValidation.log.agreementValidation | quote }} + + ###################################### + ## Additional environment variables ## + ###################################### + - name: "EDC_CONNECTOR_NAME" + value: {{ include "txdc.fullname" .}}-controlplane + {{- range $key, $value := .Values.controlplane.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 16 }} + {{- end }} + {{- range $key, $value := .Values.controlplane.env }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + {{- if and (or .Values.controlplane.envSecretNames .Values.controlplane.envConfigMapNames) (or (gt (len .Values.controlplane.envSecretNames) 0) (gt (len .Values.controlplane.envConfigMapNames) 0)) }} + envFrom: + {{- range $value := .Values.controlplane.envSecretNames }} + - secretRef: + name: {{ $value | quote }} + {{- end }} + {{- range $value := .Values.controlplane.envConfigMapNames }} + - configMapRef: + name: {{ $value | quote }} + {{- end }} + {{- end }} + volumeMounts: + - name: "configuration" + mountPath: "/app/opentelemetry.properties" + subPath: "opentelemetry.properties" + - name: "configuration" + mountPath: "/app/logging.properties" + subPath: "logging.properties" + volumes: + - name: "configuration" + configMap: + name: {{ include "txdc.fullname" . }}-controlplane + items: + - key: "opentelemetry.properties" + path: "opentelemetry.properties" + - key: "logging.properties" + path: "logging.properties" + {{- with .Values.controlplane.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controlplane.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.controlplane.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/tractusx-connector-legacy/templates/deployment-dataplane.yaml b/charts/tractusx-connector-legacy/templates/deployment-dataplane.yaml new file mode 100644 index 000000000..01ef5ca33 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/deployment-dataplane.yaml @@ -0,0 +1,236 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "txdc.fullname" . }}-dataplane + labels: + {{- include "txdc.dataplane.labels" . | nindent 4 }} +spec: + {{- if not .Values.dataplane.autoscaling.enabled }} + replicas: {{ .Values.dataplane.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "txdc.dataplane.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.dataplane.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "txdc.dataplane.selectorLabels" . | nindent 8 }} + {{- with .Values.dataplane.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "txdc.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.dataplane.podSecurityContext | nindent 8 }} + initContainers: + {{- toYaml .Values.dataplane.initContainers | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.dataplane.securityContext | nindent 12 }} + {{- if .Values.dataplane.image.repository }} + image: "{{ .Values.dataplane.image.repository }}:{{ .Values.dataplane.image.tag | default .Chart.AppVersion }}" + {{- else }} + image: "tractusx/edc-dataplane-hashicorp-vault:{{ .Values.dataplane.image.tag | default .Chart.AppVersion }}" + {{- end }} + imagePullPolicy: {{ .Values.dataplane.image.pullPolicy }} + ports: + {{- range $key,$value := .Values.dataplane.endpoints }} + - name: {{ $key }} + containerPort: {{ $value.port }} + protocol: TCP + {{- end }} + {{- if .Values.dataplane.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: {{ .Values.dataplane.endpoints.observability.path }}/check/liveness + port: {{ .Values.dataplane.endpoints.observability.port }} + initialDelaySeconds: {{ .Values.dataplane.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.dataplane.livenessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.dataplane.livenessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.dataplane.livenessProbe.failureThreshold }} + successThreshold: {{ .Values.dataplane.livenessProbe.successThreshold }} + {{- end }} + {{- if .Values.dataplane.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: {{ .Values.dataplane.endpoints.observability.path }}/check/readiness + port: {{ .Values.dataplane.endpoints.observability.port }} + initialDelaySeconds: {{ .Values.dataplane.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.dataplane.readinessProbe.periodSeconds }} + timeoutSeconds: {{ .Values.dataplane.readinessProbe.timeoutSeconds }} + failureThreshold: {{ .Values.dataplane.readinessProbe.failureThreshold }} + successThreshold: {{ .Values.dataplane.readinessProbe.successThreshold }} + {{- end }} + resources: + {{- toYaml .Values.dataplane.resources | nindent 12 }} + env: + {{- if .Values.dataplane.debug.enabled }} + - name: "JAVA_TOOL_OPTIONS" + {{- if .Values.dataplane.debug.suspendOnStart }} + value: >- + {{ printf "-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=%v" .Values.dataplane.debug.port }} + {{- else }} + value: >- + {{ printf "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=%v" .Values.dataplane.debug.port }} + {{- end }} + {{- end }} + + ####### + # API # + ####### + - name: "WEB_HTTP_DEFAULT_PORT" + value: {{ .Values.dataplane.endpoints.default.port | quote }} + - name: "WEB_HTTP_DEFAULT_PATH" + value: {{ .Values.dataplane.endpoints.default.path | quote }} + - name: "WEB_HTTP_CONTROL_PORT" + value: {{ .Values.dataplane.endpoints.control.port | quote }} + - name: "WEB_HTTP_CONTROL_PATH" + value: {{ .Values.dataplane.endpoints.control.path | quote }} + - name: "WEB_HTTP_PUBLIC_PORT" + value: {{ .Values.dataplane.endpoints.public.port | quote }} + - name: "WEB_HTTP_PUBLIC_PATH" + value: {{ .Values.dataplane.endpoints.public.path | quote }} + - name: "EDC_DATAPLANE_TOKEN_VALIDATION_ENDPOINT" + value: {{ include "txdc.controlplane.url.validation" .}} + - name: "WEB_HTTP_OBSERVABILITY_PORT" + value: {{ .Values.dataplane.endpoints.observability.port | quote }} + - name: "WEB_HTTP_OBSERVABILITY_PATH" + value: {{ .Values.dataplane.endpoints.observability.path | quote }} + - name: "TRACTUSX_API_OBSERVABILITY_ALLOW-INSECURE" + value: {{ .Values.dataplane.endpoints.observability.insecure | quote }} + + ####### + # AWS # + ####### + {{- if .Values.dataplane.aws.endpointOverride }} + - name: "EDC_AWS_ENDPOINT_OVERRIDE" + value: {{ .Values.dataplane.aws.endpointOverride | quote }} + {{- end }} + {{- if .Values.dataplane.aws.secretAccessKey }} + - name: "AWS_SECRET_ACCESS_KEY" + value: {{ .Values.dataplane.aws.secretAccessKey | quote }} + {{- end }} + {{- if .Values.dataplane.aws.accessKeyId }} + - name: "AWS_ACCESS_KEY_ID" + value: {{ .Values.dataplane.aws.accessKeyId | quote }} + {{- end }} + + ############### + ## EDR CACHE ## + ############### + + # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/edr-cache-sql + - name: "EDC_DATASOURCE_EDR_NAME" + value: "edr" + - name: "EDC_DATASOURCE_EDR_USER" + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} + - name: "EDC_DATASOURCE_EDR_PASSWORD" + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} + - name: "EDC_DATASOURCE_EDR_URL" + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} + + ########### + ## VAULT ## + ########### + + # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/hashicorp-vault + - name: "EDC_VAULT_HASHICORP_URL" + value: {{ tpl .Values.vault.hashicorp.url . | quote }} + - name: "EDC_VAULT_HASHICORP_TOKEN" + value: {{ .Values.vault.hashicorp.token | required ".Values.vault.hashicorp.token is required" | quote }} + - name: "EDC_VAULT_HASHICORP_TIMEOUT_SECONDS" + value: {{ .Values.vault.hashicorp.timeout | quote }} + - name: "EDC_VAULT_HASHICORP_HEALTH_CHECK_ENABLED" + value: {{ .Values.vault.hashicorp.healthCheck.enabled | quote }} + - name: "EDC_VAULT_HASHICORP_HEALTH_CHECK_STANDBY_OK" + value: {{ .Values.vault.hashicorp.healthCheck.standbyOk | quote }} + - name: "EDC_VAULT_HASHICORP_API_SECRET_PATH" + value: {{ .Values.vault.hashicorp.paths.secret | quote }} + - name: "EDC_VAULT_HASHICORP_API_HEALTH_CHECK_PATH" + value: {{ .Values.vault.hashicorp.paths.health | quote }} + + ###################################### + ## Additional environment variables ## + ###################################### + - name: "EDC_CONNECTOR_NAME" + value: {{ include "txdc.fullname" .}}-dataplane + {{- range $key, $value := .Values.dataplane.envValueFrom }} + - name: {{ $key | quote }} + valueFrom: + {{- tpl (toYaml $value) $ | nindent 16 }} + {{- end }} + {{- range $key, $value := .Values.dataplane.env }} + - name: {{ $key | quote }} + value: {{ $value | quote }} + {{- end }} + {{- if and (or .Values.dataplane.envSecretNames .Values.dataplane.envConfigMapNames) (or (gt (len .Values.dataplane.envSecretNames) 0) (gt (len .Values.dataplane.envConfigMapNames) 0)) }} + envFrom: + {{- range $value := .Values.dataplane.envSecretNames }} + - secretRef: + name: {{ $value | quote }} + {{- end }} + {{- range $value := .Values.dataplane.envConfigMapNames }} + - configMapRef: + name: {{ $value | quote }} + {{- end }} + {{- end }} + volumeMounts: + - name: "configuration" + mountPath: "/app/opentelemetry.properties" + subPath: "opentelemetry.properties" + - name: "configuration" + mountPath: "/app/logging.properties" + subPath: "logging.properties" + volumes: + - name: "configuration" + configMap: + name: {{ include "txdc.fullname" . }}-dataplane + items: + - key: "opentelemetry.properties" + path: "opentelemetry.properties" + - key: "logging.properties" + path: "logging.properties" + {{- with .Values.dataplane.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.dataplane.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.dataplane.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/tractusx-connector-legacy/templates/hpa-controlplane.yaml b/charts/tractusx-connector-legacy/templates/hpa-controlplane.yaml new file mode 100644 index 000000000..c52ed9152 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/hpa-controlplane.yaml @@ -0,0 +1,51 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +{{- if .Values.controlplane.autoscaling.enabled }} +--- +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "txdc.fullname" . }}-controlplane + labels: + {{- include "txdc.controlplane.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "txdc.fullname" . }}-controlplane + minReplicas: {{ .Values.controlplane.autoscaling.minReplicas }} + maxReplicas: {{ .Values.controlplane.autoscaling.maxReplicas }} + metrics: + {{- if .Values.controlplane.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.controlplane.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.controlplane.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.controlplane.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/tractusx-connector-legacy/templates/hpa-dataplane.yaml b/charts/tractusx-connector-legacy/templates/hpa-dataplane.yaml new file mode 100644 index 000000000..519c0e526 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/hpa-dataplane.yaml @@ -0,0 +1,51 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +{{- if .Values.controlplane.autoscaling.enabled }} +--- +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "txdc.fullname" . }}-dataplane + labels: + {{- include "txdc.dataplane.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "txdc.fullname" . }}-dataplane + minReplicas: {{ .Values.dataplane.autoscaling.minReplicas }} + maxReplicas: {{ .Values.dataplane.autoscaling.maxReplicas }} + metrics: + {{- if .Values.dataplane.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.dataplane.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.dataplane.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.dataplane.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/charts/tractusx-connector-legacy/templates/ingress-controlplane.yaml b/charts/tractusx-connector-legacy/templates/ingress-controlplane.yaml new file mode 100644 index 000000000..abc90106e --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/ingress-controlplane.yaml @@ -0,0 +1,100 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +{{- $fullName := include "txdc.fullname" . }} +{{- $controlLabels := include "txdc.controlplane.labels" . }} +{{- $controlEdcEndpoints := .Values.controlplane.endpoints }} +{{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} +{{- $namespace := .Release.Namespace }} + +{{- range .Values.controlplane.ingresses }} +{{- if and .enabled .endpoints }} +{{- $controlIngressName := printf "%s-controlplane-%s" $fullName .hostname }} +{{- $annotations := .annotations | default dict }} +--- +{{- if semverCompare ">=1.19-0" $gitVersion }} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" $gitVersion }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $controlIngressName }} + namespace: {{ $namespace | default "default" | quote }} + labels: + {{- $controlLabels | nindent 4 }} + annotations: + {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} + {{- if not (hasKey $annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $annotations "kubernetes.io/ingress.class" .className}} + {{- end }} + {{- end }} + {{- if .certManager }} + {{- if .certManager.issuer }} + {{- $_ := set $annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- end }} + {{- if .certManager.clusterIssuer }} + {{- $_ := set $annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- end }} + {{- end }} + {{- with $annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .className (semverCompare ">=1.18-0" $gitVersion) }} + ingressClassName: {{ .className }} + {{- end }} + {{- if .hostname }} + {{- if .tls.enabled }} + tls: + - hosts: + - {{ .hostname }} + {{- if .tls.secretName }} + secretName: {{ .tls.secretName }} + {{- else }} + secretName: {{ $controlIngressName }}-tls + {{- end }} + {{- end }} + rules: + - host: {{ .hostname }} + http: + paths: + {{- $ingressEdcEndpoints := .endpoints }} + {{- range $name, $mapping := $controlEdcEndpoints }} + {{- if (has $name $ingressEdcEndpoints) }} + - path: {{ $mapping.path }} + pathType: Prefix + backend: + {{- if semverCompare ">=1.19-0" $gitVersion }} + service: + name: {{ $fullName }}-controlplane + port: + number: {{ $mapping.port }} + {{- else }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }}{{- /* end: if .enabled */}} +{{- end }}{{- /* end: range .Values.ingresses */}} diff --git a/charts/tractusx-connector-legacy/templates/ingress-dataplane.yaml b/charts/tractusx-connector-legacy/templates/ingress-dataplane.yaml new file mode 100644 index 000000000..4777a55d4 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/ingress-dataplane.yaml @@ -0,0 +1,100 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +{{- $fullName := include "txdc.fullname" . }} +{{- $dataLabels := include "txdc.dataplane.labels" . }} +{{- $dataEdcEndpoints := .Values.dataplane.endpoints }} +{{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} +{{- $namespace := .Release.Namespace }} + +{{- range .Values.dataplane.ingresses }} +{{- if and .enabled .endpoints }} +{{- $dataIngressName := printf "%s-dataplane-%s" $fullName .hostname }} +{{- $annotations := .annotations | default dict }} +--- +{{- if semverCompare ">=1.19-0" $gitVersion }} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" $gitVersion }} +apiVersion: networking.k8s.io/v1beta1 +{{- else }} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $dataIngressName }} + namespace: {{ $namespace | default "default" | quote }} + labels: + {{- $dataLabels | nindent 4 }} + annotations: + {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} + {{- if not (hasKey $annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $annotations "kubernetes.io/ingress.class" .className}} + {{- end }} + {{- end }} + {{- if .certManager }} + {{- if .certManager.issuer }} + {{- $_ := set $annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- end }} + {{- if .certManager.clusterIssuer }} + {{- $_ := set $annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- end }} + {{- end }} + {{- with $annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .className (semverCompare ">=1.18-0" $gitVersion) }} + ingressClassName: {{ .className }} + {{- end }} + {{- if .hostname }} + {{- if .tls.enabled }} + tls: + - hosts: + - {{ .hostname }} + {{- if .tls.secretName }} + secretName: {{ .tls.secretName }} + {{- else }} + secretName: {{ $dataIngressName }}-tls + {{- end }} + {{- end }} + rules: + - host: {{ .hostname }} + http: + paths: + {{- $ingressEdcEndpoints := .endpoints }} + {{- range $name, $mapping := $dataEdcEndpoints }} + {{- if (has $name $ingressEdcEndpoints) }} + - path: {{ $mapping.path }} + pathType: Prefix + backend: + {{- if semverCompare ">=1.19-0" $gitVersion }} + service: + name: {{ $fullName }}-dataplane + port: + number: {{ $mapping.port }} + {{- else }} + {{- end }} + {{- end }} + {{- end }} + {{- end }} +{{- end }}{{- /* end: if .enabled */}} +{{- end }}{{- /* end: range .Values.ingresses */}} diff --git a/charts/tractusx-connector-legacy/templates/networkpolicy.yaml b/charts/tractusx-connector-legacy/templates/networkpolicy.yaml new file mode 100644 index 000000000..7a40cb6a3 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/networkpolicy.yaml @@ -0,0 +1,45 @@ +# +# Copyright (c) 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +{{- if eq (.Values.networkPolicy.enabled | toString) "true" }} +{{- range tuple "controlplane" "dataplane" }} +{{- $name := . }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "txdc.fullname" $ }}-{{ $name }} + labels: + {{- include (printf "txdc.%s.labels" $name) $ | nindent 4 }} +spec: + podSelector: + matchLabels: + {{- include (printf "txdc.%s.selectorLabels" $name) $ | nindent 6 }} + ingress: + - from: + {{- toYaml (index $.Values.networkPolicy $name "from") | nindent 6 }} + ports: + {{- range $key,$value := (index $.Values $name "endpoints") }} + - port: {{ $value.port }} + protocol: TCP + {{- end }} + policyTypes: + - Ingress +--- +{{- end }} +{{- end }} diff --git a/charts/tractusx-connector-legacy/templates/service-controlplane.yaml b/charts/tractusx-connector-legacy/templates/service-controlplane.yaml new file mode 100644 index 000000000..acab58343 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/service-controlplane.yaml @@ -0,0 +1,59 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "txdc.fullname" . }}-controlplane + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "txdc.controlplane.labels" . | nindent 4 }} +spec: + type: {{ .Values.controlplane.service.type }} + ports: + - port: {{ .Values.controlplane.endpoints.default.port }} + targetPort: default + protocol: TCP + name: default + - port: {{ .Values.controlplane.endpoints.control.port }} + targetPort: control + protocol: TCP + name: control + - port: {{ .Values.controlplane.endpoints.management.port }} + targetPort: management + protocol: TCP + name: management + - port: {{ .Values.controlplane.endpoints.protocol.port }} + targetPort: protocol + protocol: TCP + name: protocol + - port: {{ .Values.controlplane.endpoints.metrics.port }} + targetPort: metrics + protocol: TCP + name: metrics + - port: {{ .Values.controlplane.endpoints.observability.port}} + targetPort: observability + protocol: TCP + name: observability + selector: + {{- include "txdc.controlplane.selectorLabels" . | nindent 4 }} diff --git a/charts/tractusx-connector-legacy/templates/service-dataplane.yaml b/charts/tractusx-connector-legacy/templates/service-dataplane.yaml new file mode 100644 index 000000000..14c2181b7 --- /dev/null +++ b/charts/tractusx-connector-legacy/templates/service-dataplane.yaml @@ -0,0 +1,60 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "txdc.fullname" . }}-dataplane + namespace: {{ .Release.Namespace | default "default" | quote }} + labels: + {{- include "txdc.dataplane.labels" . | nindent 4 }} +spec: + type: {{ .Values.dataplane.service.type }} + ports: + - port: {{ .Values.dataplane.endpoints.default.port }} + targetPort: default + protocol: TCP + name: default + - port: {{ .Values.dataplane.endpoints.control.port }} + targetPort: control + protocol: TCP + name: control + - port: {{ .Values.dataplane.endpoints.public.port }} + targetPort: public + protocol: TCP + name: public + - port: {{ .Values.dataplane.endpoints.observability.port }} + targetPort: observability + protocol: TCP + name: observability + - port: {{ .Values.dataplane.endpoints.metrics.port }} + targetPort: metrics + protocol: TCP + name: metrics + - port: {{ .Values.dataplane.endpoints.proxy.port }} + targetPort: proxy + protocol: TCP + name: proxy + + selector: + {{- include "txdc.dataplane.selectorLabels" . | nindent 4 }} diff --git a/docs/samples/example-dataspace/daps/templates/serviceaccount.yaml b/charts/tractusx-connector-legacy/templates/serviceaccount.yaml similarity index 66% rename from docs/samples/example-dataspace/daps/templates/serviceaccount.yaml rename to charts/tractusx-connector-legacy/templates/serviceaccount.yaml index 536f31871..4a6e1ac07 100644 --- a/docs/samples/example-dataspace/daps/templates/serviceaccount.yaml +++ b/charts/tractusx-connector-legacy/templates/serviceaccount.yaml @@ -1,4 +1,8 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional # information regarding copyright ownership. @@ -21,11 +25,15 @@ apiVersion: v1 kind: ServiceAccount metadata: - name: {{ include "omejdn.serviceAccountName" . }} + name: {{ include "txdc.serviceAccountName" . }} labels: - {{- include "omejdn.labels" . | nindent 4 }} + {{- include "txdc.labels" . | nindent 4 }} {{- with .Values.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} {{- end }} +{{- with .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: + {{- toYaml . | nindent 2 }} +{{- end }} {{- end }} diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/templates/serviceaccount.yaml b/charts/tractusx-connector-legacy/templates/tests/test-controlplane-readiness.yaml similarity index 58% rename from charts/tractusx-connector-memory/subcharts/omejdn/templates/serviceaccount.yaml rename to charts/tractusx-connector-legacy/templates/tests/test-controlplane-readiness.yaml index 536f31871..694084ded 100644 --- a/charts/tractusx-connector-memory/subcharts/omejdn/templates/serviceaccount.yaml +++ b/charts/tractusx-connector-legacy/templates/tests/test-controlplane-readiness.yaml @@ -1,3 +1,4 @@ +# # Copyright (c) 2023 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional @@ -16,16 +17,20 @@ # SPDX-License-Identifier: Apache-2.0 # -{{- if .Values.serviceAccount.create -}} --- apiVersion: v1 -kind: ServiceAccount +kind: Pod metadata: - name: {{ include "omejdn.serviceAccountName" . }} + name: "{{include "txdc.fullname" .}}test-controlplane-readiness" labels: - {{- include "omejdn.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} + {{- include "txdc.controlplane.labels" . | nindent 4 }} annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} + "helm.sh/hook": test + "helm.sh/hook-delete-policy": {{ .Values.tests.hookDeletePolicy }} +spec: + containers: + - name: wget + image: curlimages/curl + command: [ 'curl' ] + args: [ '{{- printf "http://%s-controlplane:%v%s/check/readiness" (include "txdc.fullname" $ ) $.Values.controlplane.endpoints.observability.port $.Values.controlplane.endpoints.observability.path -}}' ] + restartPolicy: Never diff --git a/charts/tractusx-connector/subcharts/omejdn/templates/serviceaccount.yaml b/charts/tractusx-connector-legacy/templates/tests/test-dataplane-readiness.yaml similarity index 59% rename from charts/tractusx-connector/subcharts/omejdn/templates/serviceaccount.yaml rename to charts/tractusx-connector-legacy/templates/tests/test-dataplane-readiness.yaml index 536f31871..0ecc0ce32 100644 --- a/charts/tractusx-connector/subcharts/omejdn/templates/serviceaccount.yaml +++ b/charts/tractusx-connector-legacy/templates/tests/test-dataplane-readiness.yaml @@ -1,3 +1,4 @@ +# # Copyright (c) 2023 Contributors to the Eclipse Foundation # # See the NOTICE file(s) distributed with this work for additional @@ -16,16 +17,20 @@ # SPDX-License-Identifier: Apache-2.0 # -{{- if .Values.serviceAccount.create -}} --- apiVersion: v1 -kind: ServiceAccount +kind: Pod metadata: - name: {{ include "omejdn.serviceAccountName" . }} + name: "{{include "txdc.fullname" .}}test-dataplane-readiness" labels: - {{- include "omejdn.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} + {{- include "txdc.dataplane.labels" . | nindent 4 }} annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} + "helm.sh/hook": test + "helm.sh/hook-delete-policy": {{ .Values.tests.hookDeletePolicy }} +spec: + containers: + - name: wget + image: curlimages/curl + command: [ 'curl' ] + args: [ '{{- printf "http://%s-dataplane:%v%s/check/readiness" (include "txdc.fullname" $ ) $.Values.dataplane.endpoints.observability.port $.Values.dataplane.endpoints.observability.path -}}' ] + restartPolicy: Never diff --git a/charts/tractusx-connector-legacy/values.yaml b/charts/tractusx-connector-legacy/values.yaml new file mode 100644 index 000000000..f19493f45 --- /dev/null +++ b/charts/tractusx-connector-legacy/values.yaml @@ -0,0 +1,575 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +--- +# Default values for eclipse-dataspace-connector. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +install: + daps: true + postgresql: true + vault: true +fullnameOverride: "" +nameOverride: "" +# -- Existing image pull secret to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) +imagePullSecrets: [] +customLabels: {} + +participant: + id: "" + +controlplane: + image: + # -- Which derivate of the control plane to use. when left empty the deployment will select the correct image automatically + repository: "" + # -- [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use + pullPolicy: IfNotPresent + # -- Overrides the image tag whose default is the chart appVersion + tag: "" + initContainers: [] + debug: + enabled: false + port: 1044 + suspendOnStart: false + internationalDataSpaces: + id: TXDC + description: Tractus-X Eclipse IDS Data Space Connector + title: "" + maintainer: "" + curator: "" + catalogId: TXDC-Catalog + livenessProbe: + # -- Whether to enable kubernetes [liveness-probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) + enabled: true + # -- seconds to wait before performing the first liveness check + initialDelaySeconds: 30 + # -- this fields specifies that kubernetes should perform a liveness check every 10 seconds + periodSeconds: 10 + # -- number of seconds after which the probe times out + timeoutSeconds: 5 + # -- when a probe fails kubernetes will try 6 times before giving up + failureThreshold: 6 + # -- number of consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + readinessProbe: + # -- Whether to enable kubernetes [readiness-probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) + enabled: true + # -- seconds to wait before performing the first readiness check + initialDelaySeconds: 30 + # -- this fields specifies that kubernetes should perform a readiness check every 10 seconds + periodSeconds: 10 + # -- number of seconds after which the probe times out + timeoutSeconds: 5 + # -- when a probe fails kubernetes will try 6 times before giving up + failureThreshold: 6 + # -- number of consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + # -- endpoints of the control plane + endpoints: + # -- default api for health checks, should not be added to any ingress + default: + # -- port for incoming api calls + port: 8080 + # -- path for incoming api calls + path: /api + # -- data management api, used by internal users, can be added to an ingress and must not be internet facing + management: + # -- port for incoming api calls + port: 8081 + # -- path for incoming api calls + path: /management + # -- authentication key, must be attached to each 'X-Api-Key' request header + authKey: "" + # -- control api, used for internal control calls. can be added to the internal ingress, but should probably not + control: + # -- port for incoming api calls + port: 8083 + # -- path for incoming api calls + path: /control + # -- ids api, used for inter connector communication and must be internet facing + protocol: + # -- port for incoming api calls + port: 8084 + # -- path for incoming api calls + path: /api/v1/dsp + # -- metrics api, used for application metrics, must not be internet facing + metrics: + # -- port for incoming api calls + port: 9090 + # -- path for incoming api calls + path: /metrics + # -- observability api with unsecured access, must not be internet facing + observability: + # -- port for incoming API calls + port: 8085 + # -- observability api, provides /health /readiness and /liveness endpoints + path: /observability + # -- allow or disallow insecure access, i.e. access without authentication + insecure: true + businessPartnerValidation: + log: + agreementValidation: true + service: + # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. + type: ClusterIP + annotations: {} + # -- additional labels for the pod + podLabels: {} + # -- additional annotations for the pod + podAnnotations: {} + # -- The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment + podSecurityContext: + seccompProfile: + # -- Restrict a Container's Syscalls with seccomp + type: RuntimeDefault + # -- Runs all processes within a pod with a special uid + runAsUser: 10001 + # -- Processes within a pod will belong to this guid + runAsGroup: 10001 + # -- The owner for volumes and any files created within volumes will belong to this guid + fsGroup: 10001 + # The [container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) defines privilege and access control settings for a Container within a pod + securityContext: + capabilities: + # -- Specifies which capabilities to drop to reduce syscall attack surface + drop: + - ALL + # -- Specifies which capabilities to add to issue specialized syscalls + add: [] + # -- Whether the root filesystem is mounted in read-only mode + readOnlyRootFilesystem: true + # -- Controls [Privilege Escalation](https://kubernetes.io/docs/concepts/security/pod-security-policy/#privilege-escalation) enabling setuid binaries changing the effective user ID + allowPrivilegeEscalation: false + # -- Requires the container to run without root privileges + runAsNonRoot: true + # -- The container's process will run with the specified uid + runAsUser: 10001 + # Extra environment variables that will be pass onto deployment pods + env: {} + # ENV_NAME: value + + # "valueFrom" environment variable references that will be added to deployment pods. Name is templated. + # ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core + envValueFrom: {} + # ENV_NAME: + # configMapKeyRef: + # name: configmap-name + # key: value_key + # secretKeyRef: + # name: secret-name + # key: value_key + + # [Kubernetes Secret Resource](https://kubernetes.io/docs/concepts/configuration/secret/) names to load environment variables from + envSecretNames: [] + # - first-secret + # - second-secret + + # [Kubernetes ConfigMap Resource](https://kubernetes.io/docs/concepts/configuration/configmap/) names to load environment variables from + envConfigMapNames: [] + # - first-config-map + # - second-config-map + + ## Ingress declaration to expose the network service. + ingresses: + ## Public / Internet facing Ingress + - enabled: false + # -- The hostname to be used to precisely map incoming traffic onto the underlying network service + hostname: "edc-control.local" + # -- Additional ingress annotations to add + annotations: {} + # -- EDC endpoints exposed by this ingress resource + endpoints: + - protocol + # -- Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use + className: "" + # -- TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource + tls: + # -- Enables TLS on the ingress resource + enabled: false + # -- If present overwrites the default secret name + secretName: "" + ## Adds [cert-manager](https://cert-manager.io/docs/) annotations to the ingress resource + certManager: + # -- If preset enables certificate generation via cert-manager namespace scoped issuer + issuer: "" + # -- If preset enables certificate generation via cert-manager cluster-wide issuer + clusterIssuer: "" + ## Private / Intranet facing Ingress + - enabled: false + # -- The hostname to be used to precisely map incoming traffic onto the underlying network service + hostname: "edc-control.intranet" + # -- Additional ingress annotations to add + annotations: {} + # -- EDC endpoints exposed by this ingress resource + endpoints: + - management + - control + # -- Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use + className: "" + # -- TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource + tls: + # -- Enables TLS on the ingress resource + enabled: false + # -- If present overwrites the default secret name + secretName: "" + ## Adds [cert-manager](https://cert-manager.io/docs/) annotations to the ingress resource + certManager: + # -- If preset enables certificate generation via cert-manager namespace scoped issuer + issuer: "" + # -- If preset enables certificate generation via cert-manager cluster-wide issuer + clusterIssuer: "" + # -- declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container + volumeMounts: [] + # -- [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories + volumes: [] + # -- [resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) for the container + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + replicaCount: 1 + autoscaling: + # -- Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) + enabled: false + # -- Minimal replicas if resource consumption falls below resource threshholds + minReplicas: 1 + # -- Maximum replicas if resource consumption exceeds resource threshholds + maxReplicas: 100 + # -- targetAverageUtilization of cpu provided to a pod + targetCPUUtilizationPercentage: 80 + # -- targetAverageUtilization of memory provided to a pod + targetMemoryUtilizationPercentage: 80 + # -- configuration of the [Open Telemetry Agent](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/) to collect and expose metrics + opentelemetry: |- + otel.javaagent.enabled=false + otel.javaagent.debug=false + # -- configuration of the [Java Util Logging Facade](https://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview.html) + logging: |- + .level=INFO + org.eclipse.edc.level=ALL + handlers=java.util.logging.ConsoleHandler + java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter + java.util.logging.ConsoleHandler.level=ALL + java.util.logging.SimpleFormatter.format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS] [%4$-7s] %5$s%6$s%n + # [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain pods to nodes + nodeSelector: {} + # [tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) to configure preferred nodes + tolerations: [] + # [affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) to configure which nodes the pods can be scheduled on + affinity: {} + url: + # -- Explicitly declared url for reaching the ids api (e.g. if ingresses not used) + ids: "" +dataplane: + image: + # -- Which derivate of the data plane to use. when left empty the deployment will select the correct image automatically + repository: "" + # -- [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use + pullPolicy: IfNotPresent + # -- Overrides the image tag whose default is the chart appVersion + tag: "" + initContainers: [] + debug: + enabled: false + port: 1044 + suspendOnStart: false + livenessProbe: + # -- Whether to enable kubernetes [liveness-probe](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) + enabled: true + # -- seconds to wait before performing the first liveness check + initialDelaySeconds: 30 + # -- this fields specifies that kubernetes should perform a liveness check every 10 seconds + periodSeconds: 10 + # -- number of seconds after which the probe times out + timeoutSeconds: 5 + # -- when a probe fails kubernetes will try 6 times before giving up + failureThreshold: 6 + # -- number of consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + readinessProbe: + # -- Whether to enable kubernetes [readiness-probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) + enabled: true + # -- seconds to wait before performing the first readiness check + initialDelaySeconds: 30 + # -- this fields specifies that kubernetes should perform a liveness check every 10 seconds + periodSeconds: 10 + # -- number of seconds after which the probe times out + timeoutSeconds: 5 + # -- when a probe fails kubernetes will try 6 times before giving up + failureThreshold: 6 + # -- number of consecutive successes for the probe to be considered successful after having failed + successThreshold: 1 + service: + # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. + type: ClusterIP + port: 80 + endpoints: + default: + port: 8080 + path: /api + public: + port: 8081 + path: /api/public + control: + port: 8083 + path: /api/dataplane/control + proxy: + port: 8186 + path: /proxy + observability: + # -- port for incoming API calls + port: 8085 + # -- observability api, provides /health /readiness and /liveness endpoints + path: /observability + # -- allow or disallow insecure access, i.e. access without authentication + insecure: true + metrics: + port: 9090 + path: /metrics + aws: + endpointOverride: "" + accessKeyId: "" + secretAccessKey: "" + # -- additional labels for the pod + podLabels: {} + # -- additional annotations for the pod + podAnnotations: {} + # -- The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment + podSecurityContext: + seccompProfile: + # -- Restrict a Container's Syscalls with seccomp + type: RuntimeDefault + # -- Runs all processes within a pod with a special uid + runAsUser: 10001 + # -- Processes within a pod will belong to this guid + runAsGroup: 10001 + # -- The owner for volumes and any files created within volumes will belong to this guid + fsGroup: 10001 + # The [container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) defines privilege and access control settings for a Container within a pod + securityContext: + capabilities: + # -- Specifies which capabilities to drop to reduce syscall attack surface + drop: + - ALL + # -- Specifies which capabilities to add to issue specialized syscalls + add: [] + # -- Whether the root filesystem is mounted in read-only mode + readOnlyRootFilesystem: true + # -- Controls [Privilege Escalation](https://kubernetes.io/docs/concepts/security/pod-security-policy/#privilege-escalation) enabling setuid binaries changing the effective user ID + allowPrivilegeEscalation: false + # -- Requires the container to run without root privileges + runAsNonRoot: true + # -- The container's process will run with the specified uid + runAsUser: 10001 + # Extra environment variables that will be pass onto deployment pods + env: {} + # ENV_NAME: value + + # "valueFrom" environment variable references that will be added to deployment pods. Name is templated. + # ref: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.19/#envvarsource-v1-core + envValueFrom: {} + # ENV_NAME: + # configMapKeyRef: + # name: configmap-name + # key: value_key + # secretKeyRef: + # name: secret-name + # key: value_key + + # [Kubernetes Secret Resource](https://kubernetes.io/docs/concepts/configuration/secret/) names to load environment variables from + envSecretNames: [] + # - first-secret + # - second-secret + + # [Kubernetes ConfigMap Resource](https://kubernetes.io/docs/concepts/configuration/configmap/) names to load environment variables from + envConfigMapNames: [] + # - first-config-map + # - second-config-map + + ## Ingress declaration to expose the network service. + ingresses: + ## Public / Internet facing Ingress + - enabled: false + # -- The hostname to be used to precisely map incoming traffic onto the underlying network service + hostname: "edc-data.local" + # -- Additional ingress annotations to add + annotations: {} + # -- EDC endpoints exposed by this ingress resource + endpoints: + - public + # -- Defines the [ingress class](https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-class) to use + className: "" + # -- TLS [tls class](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls) applied to the ingress resource + tls: + # -- Enables TLS on the ingress resource + enabled: false + # -- If present overwrites the default secret name + secretName: "" + ## Adds [cert-manager](https://cert-manager.io/docs/) annotations to the ingress resource + certManager: + # -- If preset enables certificate generation via cert-manager namespace scoped issuer + issuer: "" + # -- If preset enables certificate generation via cert-manager cluster-wide issuer + clusterIssuer: "" + # -- declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container + volumeMounts: [] + # -- [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories + volumes: [] + # -- [resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) for the container + resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + replicaCount: 1 + autoscaling: + # -- Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) + enabled: false + # -- Minimal replicas if resource consumption falls below resource threshholds + minReplicas: 1 + # -- Maximum replicas if resource consumption exceeds resource threshholds + maxReplicas: 100 + # -- targetAverageUtilization of cpu provided to a pod + targetCPUUtilizationPercentage: 80 + # -- targetAverageUtilization of memory provided to a pod + targetMemoryUtilizationPercentage: 80 + # -- configuration of the [Open Telemetry Agent](https://opentelemetry.io/docs/instrumentation/java/automatic/agent-config/) to collect and expose metrics + opentelemetry: |- + otel.javaagent.enabled=false + otel.javaagent.debug=false + # -- configuration of the [Java Util Logging Facade](https://docs.oracle.com/javase/7/docs/technotes/guides/logging/overview.html) + logging: |- + .level=INFO + org.eclipse.edc.level=ALL + handlers=java.util.logging.ConsoleHandler + java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter + java.util.logging.ConsoleHandler.level=ALL + java.util.logging.SimpleFormatter.format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS] [%4$-7s] %5$s%6$s%n + # [node selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain pods to nodes + nodeSelector: {} + # [tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) to configure preferred nodes + tolerations: [] + # [affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) to configure which nodes the pods can be scheduled on + affinity: {} + url: + # -- Explicitly declared url for reaching the public api (e.g. if ingresses not used) + public: "" +postgresql: + jdbcUrl: "jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc" + primary: + persistence: + enabled: false + readReplicas: + persistence: + enabled: false + auth: + database: "edc" + username: "user" + password: "password" +vault: + injector: + enabled: false + server: + dev: + enabled: true + devRootToken: "root" + # Must be the same certificate that is configured in section 'daps' + postStart: # must be set externally! + hashicorp: + url: "http://{{ .Release.Name }}-vault:8200" + token: "" + timeout: 30 + healthCheck: + enabled: true + standbyOk: true + paths: + secret: /v1/secret + health: /v1/sys/health + secretNames: + transferProxyTokenSignerPrivateKey: transfer-proxy-token-signer-private-key + transferProxyTokenSignerPublicKey: transfer-proxy-token-signer-public-key + transferProxyTokenEncryptionAesKey: transfer-proxy-token-encryption-aes-key + dapsPrivateKey: daps-private-key + dapsPublicKey: daps-public-key +daps: + url: "http://{{ .Release.Name }}-daps:4567" + clientId: "" + paths: + jwks: /jwks.json + token: /token + connectors: + - id: E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65 + name: sokrates + attributes: + referringConnector: http://sokrates-controlplane/BPNSOKRATES + # Must be the same certificate that is stores in section 'sokrates-vault' + certificate: "" # must be set externally! +backendService: + httpProxyTokenReceiverUrl: "" + +networkPolicy: + # -- If `true` network policy will be created to restrict access to control- and dataplane + enabled: false + # -- Configuration of the controlplane component + controlplane: + # -- Specify from rule network policy for cp (defaults to all namespaces) + from: + - namespaceSelector: {} + # -- Configuration of the dataplane component + dataplane: + # -- Specify from rule network policy for dp (defaults to all namespaces) + from: + - namespaceSelector: {} + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + # -- Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) + imagePullSecrets: [] +idsdaps: + connectors: + - certificate: |- + +# -- Configurations for Helm tests +tests: + # -- Configure the hook-delete-policy for Helm tests + hookDeletePolicy: before-hook-creation,hook-succeeded diff --git a/charts/tractusx-connector-memory/Chart.yaml b/charts/tractusx-connector-memory/Chart.yaml index 5612b3523..22384dd79 100644 --- a/charts/tractusx-connector-memory/Chart.yaml +++ b/charts/tractusx-connector-memory/Chart.yaml @@ -34,19 +34,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.1 +version: 0.5.0-rc1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.4.1" +appVersion: "0.5.0-rc1" home: https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector-memory sources: - https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector-memory -dependencies: - # IDS Dynamic Attribute Provisioning Service (IAM) - - name: daps - version: 0.0.1 - repository: "file://./subcharts/omejdn" - alias: daps - condition: install.daps diff --git a/charts/tractusx-connector-memory/README.md b/charts/tractusx-connector-memory/README.md index 532c7539a..f49f98b6f 100644 --- a/charts/tractusx-connector-memory/README.md +++ b/charts/tractusx-connector-memory/README.md @@ -1,6 +1,6 @@ # tractusx-connector-memory -![Version: 0.4.1](https://img.shields.io/badge/Version-0.4.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.4.1](https://img.shields.io/badge/AppVersion-0.4.1-informational?style=flat-square) +![Version: 0.5.0-rc1](https://img.shields.io/badge/Version-0.5.0--rc1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.0-rc1](https://img.shields.io/badge/AppVersion-0.5.0--rc1-informational?style=flat-square) A Helm chart for Tractus-X Eclipse Data Space Connector based on memory. Please only use this for development or testing purposes, never in production workloads! @@ -25,15 +25,15 @@ export DAPS_CERT="$(cat daps.cert)" The in-memory vault can be seeded directly with secrets that are passed in `:;:;...` format. This config value can be passed to the runtime using the `vault.secrets` parameter. In addition, the runtime requires a couple of configuration parameters, all of which can be found in the section below. Please also consider using -[this example configuration](https://github.com/eclipse-tractusx/tractusx-edc/blob/main/charts/tractusx-connector-memory/example.yaml) +[this example configuration](https://github.com/eclipse-tractusx/tractusx-edc/blob/main/edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml) to launch the application. Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev -helm install my-release tractusx-edc/tractusx-connector-memory --version 0.4.1 \ - -f /example.yaml \ +helm install my-release tractusx-edc/tractusx-connector-memory --version 0.5.0-rc1 \ + -f /tractusx-connector-memory-test.yaml \ --set vault.secrets="daps-cert:$DAPS_CERT;daps-key:$DAPS_KEY" \ ``` @@ -43,12 +43,6 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri * -## Requirements - -| Repository | Name | Version | -|------------|------|---------| -| file://./subcharts/omejdn | daps(daps) | 0.0.1 | - ## Values | Key | Type | Default | Description | @@ -60,14 +54,11 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri | daps.connectors[0].certificate | string | `""` | | | daps.connectors[0].id | string | `"E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65"` | | | daps.connectors[0].name | string | `"sokrates"` | | -| daps.fullnameOverride | string | `"daps"` | | | daps.paths.jwks | string | `"/jwks.json"` | | | daps.paths.token | string | `"/token"` | | -| daps.url | string | `""` | | +| daps.url | string | `"http://{{ .Release.Name }}-daps:4567"` | | | fullnameOverride | string | `""` | | -| idsdaps.connectors[0].certificate | string | `""` | | | imagePullSecrets | list | `[]` | Existing image pull secret to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | -| install.daps | bool | `true` | | | nameOverride | string | `""` | | | participant.id | string | `""` | | | runtime.affinity | object | `{}` | | @@ -166,6 +157,12 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri | runtime.securityContext.runAsUser | int | `10001` | The container's process will run with the specified uid | | runtime.service.annotations | object | `{}` | | | runtime.service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | +| runtime.ssi.endpoint.audience | string | `"http://this.audience"` | | +| runtime.ssi.miw.authorityId | string | `""` | | +| runtime.ssi.miw.url | string | `""` | | +| runtime.ssi.oauth.client.id | string | `""` | | +| runtime.ssi.oauth.client.secretAlias | string | `"client-secret"` | | +| runtime.ssi.oauth.tokenurl | string | `""` | | | runtime.tolerations | list | `[]` | | | runtime.url.ids | string | `""` | Explicitly declared url for reaching the ids api (e.g. if ingresses not used) | | runtime.url.public | string | `""` | | @@ -176,11 +173,9 @@ Note that `DAPS_CERT` contains the x509 certificate, `DAPS_KEY` contains the pri | serviceAccount.create | bool | `true` | | | serviceAccount.imagePullSecrets | list | `[]` | Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | | serviceAccount.name | string | `""` | | -| vault.secretNames.dapsPrivateKey | string | `"daps-private-key"` | | -| vault.secretNames.dapsPublicKey | string | `"daps-public-key"` | | +| tests | object | `{"hookDeletePolicy":"before-hook-creation,hook-succeeded"}` | Configurations for Helm tests | +| tests.hookDeletePolicy | string | `"before-hook-creation,hook-succeeded"` | Configure the hook-delete-policy for Helm tests | | vault.secretNames.transferProxyTokenEncryptionAesKey | string | `"transfer-proxy-token-encryption-aes-key"` | | -| vault.secretNames.transferProxyTokenSignerPrivateKey | string | `"transfer-proxy-token-signer-private-key"` | | -| vault.secretNames.transferProxyTokenSignerPublicKey | string | `"transfer-proxy-token-signer-public-key"` | | | vault.secrets | string | `""` | | | vault.server.postStart | string | `""` | | diff --git a/charts/tractusx-connector-memory/README.md.gotmpl b/charts/tractusx-connector-memory/README.md.gotmpl index 630e63377..f67920699 100644 --- a/charts/tractusx-connector-memory/README.md.gotmpl +++ b/charts/tractusx-connector-memory/README.md.gotmpl @@ -27,7 +27,7 @@ export DAPS_CERT="$(cat daps.cert)" The in-memory vault can be seeded directly with secrets that are passed in `:;:;...` format. This config value can be passed to the runtime using the `vault.secrets` parameter. In addition, the runtime requires a couple of configuration parameters, all of which can be found in the section below. Please also consider using -[this example configuration](https://github.com/eclipse-tractusx/tractusx-edc/blob/main/charts/tractusx-connector-memory/example.yaml) +[this example configuration](https://github.com/eclipse-tractusx/tractusx-edc/blob/main/edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml) to launch the application. Combined, run this shell command to start the in-memory Tractus-X EDC runtime: @@ -35,7 +35,7 @@ Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev helm install my-release tractusx-edc/tractusx-connector-memory --version {{ .Version }} \ - -f /example.yaml \ + -f /tractusx-connector-memory-test.yaml \ --set vault.secrets="daps-cert:$DAPS_CERT;daps-key:$DAPS_KEY" \ ``` diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/.helmignore b/charts/tractusx-connector-memory/subcharts/omejdn/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/Chart.yaml b/charts/tractusx-connector-memory/subcharts/omejdn/Chart.yaml deleted file mode 100644 index 3e10aa1fc..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/Chart.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: v2 -name: daps -description: A Helm chart for Kubernetes -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.1 -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "0.4.1" diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/README.md b/charts/tractusx-connector-memory/subcharts/omejdn/README.md deleted file mode 100644 index d23a9f9fa..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# daps - -![Version: 0.4.1](https://img.shields.io/badge/Version-0.4.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.4.1](https://img.shields.io/badge/AppVersion-0.4.1-informational?style=flat-square) - -A Helm chart for Kubernetes - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. | -| automountServiceAccountToken | bool | `false` | Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod | -| autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | -| autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | -| autoscaling.minReplicas | int | `1` | Minimal replicas if resource consumption falls below resource threshholds | -| autoscaling.targetCPUUtilizationPercentage | int | `80` | targetAverageUtilization of cpu provided to a pod | -| autoscaling.targetMemoryUtilizationPercentage | int | `80` | targetAverageUtilization of memory provided to a pod | -| connectors | list | `[]` | | -| fullnameOverride | string | `""` | Overrides the releases full name | -| image.pullPolicy | string | `"IfNotPresent"` | [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use | -| image.repository | string | `"ghcr.io/fraunhofer-aisec/omejdn-server"` | Which omjedn container image to use | -| image.tag | string | `"1.7.1"` | Overrides the image tag whose default is the chart appVersion | -| imagePullSecret.dockerconfigjson | string | `""` | Image pull secret to create to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) Note: This value needs to adhere to the [(base64 encoded) .dockerconfigjson format](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials). Furthermore, if 'imagePullSecret.dockerconfigjson' is defined, it takes precedence over 'imagePullSecrets'. | -| nameOverride | string | `""` | Overrides the charts name | -| nodeSelector | object | `{}` | [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. | -| podAnnotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) | -| podSecurityContext | object | `{}` | | -| replicaCount | int | `1` | Specifies how many replicas of a deployed pod shall be created during the deployment Note: If horizontal pod autoscaling is enabled this setting has no effect | -| resources | object | `{}` | [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod | -| securityContext | object | `{}` | | -| service.port | int | `4567` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) to expose the running application on a set of Pods as a network service. | -| service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | -| serviceAccount.annotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account | -| serviceAccount.create | bool | `true` | Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release | -| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template | -| tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. | - ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/templates/_helpers.tpl b/charts/tractusx-connector-memory/subcharts/omejdn/templates/_helpers.tpl deleted file mode 100644 index 95b115eee..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "omejdn.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "omejdn.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "omejdn.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "omejdn.labels" -}} -helm.sh/chart: {{ include "omejdn.chart" . }} -{{ include "omejdn.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "omejdn.selectorLabels" -}} -app.kubernetes.io/name: {{ include "omejdn.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "omejdn.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "omejdn.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/templates/configmap.yaml b/charts/tractusx-connector-memory/subcharts/omejdn/templates/configmap.yaml deleted file mode 100644 index 5ad21648d..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/templates/configmap.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -data: - scope_mapping.yml: |- - --- - idsc:IDS_CONNECTOR_ATTRIBUTES_ALL: - - referringConnector - - omejdn.yml: |- - --- - host: http://daps:4567/ - path_prefix: '' - bind_to: 0.0.0.0 - allow_origin: "*" - app_env: debug - openid: false - user_backend: - - yaml - user_backend_default: yaml - accept_audience: idsc:IDS_CONNECTORS_ALL - issuer: http://daps:4567/ - environment: development - default_audience: - - idsc:IDS_CONNECTORS_ALL - access_token: - expiration: 3600 - algorithm: RS256 - id_token: - expiration: 3600 - algorithm: RS256 - - plugins.yml: |- - --- - plugins: - token_user_attributes: - - clients.yml: |- - --- - - client_id: data-plane-oauth2 - client_secret: supersecret - name: provision oauth2 - grant_types: - - client_credentials - token_endpoint_auth_method: client_secret_post - scope: openid -{{- range $i, $val := .Values.connectors }} - - client_id: {{ quote $val.id }} - name: {{ quote $val.name }} - token_endpoint_auth_method: private_key_jwt - grant_types: - - client_credentials - scope: - - idsc:IDS_CONNECTOR_ATTRIBUTES_ALL - attributes: - - key: idsc - value: IDS_CONNECTOR_ATTRIBUTES_ALL - - key: securityProfile - value: idsc:BASE_SECURITY_PROFILE - {{- range $key, $value := $val.attributes }} - - key: {{ $key }} - value: {{ $value }} - {{- end }} - redirect_uri: http://localhost:4200 -{{ end -}} - - -{{- range $i, $val := .Values.connectors }} - {{ $val.name }}: {{ quote $val.certificate | toString }} -{{ end -}} diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/templates/deployment.yaml b/charts/tractusx-connector-memory/subcharts/omejdn/templates/deployment.yaml deleted file mode 100644 index 58bfff105..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/templates/deployment.yaml +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "omejdn.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "omejdn.selectorLabels" . | nindent 8 }} - spec: - {{- if .Values.imagePullSecret.dockerconfigjson }} - imagePullSecrets: - - name: {{ include "omejdn.fullname" . }}-imagepullsecret - {{- else }} - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- end }} - serviceAccountName: {{ include "omejdn.serviceAccountName" . }} - automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - initContainers: - - name: init-daps-pvc - image: alpine - command: - - "sh" - - "-c" - args: - - | - cp /opt/config/omejdn.yml /etc/daps/omejdn.yml - cp /opt/config/clients.yml /etc/daps/clients.yml - cp /opt/config/plugins.yml /etc/daps/plugins.yml - cp /opt/config/scope_mapping.yml /etc/daps/scope_mapping.yml - apk add --update openssl - openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout /etc/keys/omejdn/omejdn.key \ - -subj "/C=DE/ST=Berlin/L=Berlin/O=Tractus-X-EDC-Test, Inc./OU=DE" - volumeMounts: - - mountPath: /etc/daps - name: config-dir - - mountPath: /etc/keys/omejdn - name: omejdn-key-dir - - mountPath: /opt/config/omejdn.yml - name: omejdn-config - subPath: omejdn.yml - - mountPath: /opt/config/scope_mapping.yml - name: scope-mapping - subPath: scope_mapping.yml - - mountPath: /opt/config/clients.yml - name: clients-config - subPath: clients.yml - - mountPath: /opt/config/plugins.yml - name: plugins-config - subPath: plugins.yml - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - volumeMounts: - - mountPath: /opt/config/ - name: config-dir - - mountPath: /opt/keys/omejdn/omejdn.key - name: omejdn-key-dir - subPath: omejdn.key - - mountPath: /opt/keys/clients/ - name: client-certificates - ports: - - name: http - containerPort: 4567 - protocol: TCP - livenessProbe: - httpGet: - path: /jwks.json - port: http - readinessProbe: - httpGet: - path: /jwks.json - port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - env: - - name: OMEJDN_JWT_AUD_OVERRIDE - value: "idsc:IDS_CONNECTORS_ALL" - - name: OMEJDN_PLUGINS - value: "config/plugins.yml" - volumes: - - name: config-dir - emptyDir: { } - - name: omejdn-key-dir - emptyDir: { } - - name: omejdn-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: omejdn.yml - path: omejdn.yml - - name: scope-mapping - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: scope_mapping.yml - path: scope_mapping.yml - - name: clients-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: clients.yml - path: clients.yml - - name: plugins-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: plugins.yml - path: plugins.yml - - name: client-certificates - configMap: - name: {{ include "omejdn.fullname" . }} - items: - {{- range $i, $val := .Values.connectors }} - - key: {{ $val.name }} - path: {{ $val.id }}.cert - {{- end }} diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/templates/hpa.yaml b/charts/tractusx-connector-memory/subcharts/omejdn/templates/hpa.yaml deleted file mode 100644 index f1f072f6c..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/templates/hpa.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation - # - # See the NOTICE file(s) distributed with this work for additional - # information regarding copyright ownership. - # - # 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 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - # License for the specific language governing permissions and limitations - # under the License. - # - # SPDX-License-Identifier: Apache-2.0 - # - -{{- if .Values.autoscaling.enabled }} ---- -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "omejdn.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/templates/imagepullsecret.yaml b/charts/tractusx-connector-memory/subcharts/omejdn/templates/imagepullsecret.yaml deleted file mode 100644 index 44f573e0f..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/templates/imagepullsecret.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation - # - # See the NOTICE file(s) distributed with this work for additional - # information regarding copyright ownership. - # - # 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 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - # License for the specific language governing permissions and limitations - # under the License. - # - # SPDX-License-Identifier: Apache-2.0 - # - -{{- if .Values.imagePullSecret.dockerconfigjson }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "edc-dataplane.fullname" . }}-imagepullsecret - namespace: {{ .Release.Namespace | default "default" | quote }} - labels: - {{- include "edc-dataplane.labels" . | nindent 4 }} -data: - .dockerconfigjson: {{ .Values.imagePullSecret.dockerconfigjson }} -type: kubernetes.io/dockerconfigjson -{{- end }} diff --git a/charts/tractusx-connector-memory/subcharts/omejdn/values.yaml b/charts/tractusx-connector-memory/subcharts/omejdn/values.yaml deleted file mode 100644 index f411b8774..000000000 --- a/charts/tractusx-connector-memory/subcharts/omejdn/values.yaml +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -# Default values for omejdn. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -# -- Specifies how many replicas of a deployed pod shall be created during the deployment -# Note: If horizontal pod autoscaling is enabled this setting has no effect -replicaCount: 1 - -image: - # -- Which omjedn container image to use - repository: ghcr.io/fraunhofer-aisec/omejdn-server - # -- [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use - pullPolicy: IfNotPresent - # -- Overrides the image tag whose default is the chart appVersion - tag: "1.7.1" - -imagePullSecret: - # -- Image pull secret to create to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) - # Note: This value needs to adhere to the [(base64 encoded) .dockerconfigjson format](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials). - # Furthermore, if 'imagePullSecret.dockerconfigjson' is defined, it takes precedence over 'imagePullSecrets'. - dockerconfigjson: "" - -# -- Overrides the charts name -nameOverride: "" - -# -- Overrides the releases full name -fullnameOverride: "" - -serviceAccount: - # -- Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release - create: true - # -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account - annotations: {} - # -- The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template - name: "" - -# -- Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod -automountServiceAccountToken: false - -# -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) -podAnnotations: {} - -# The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment -podSecurityContext: {} - -# The [container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) defines privilege and access control settings for a Container within a pod -securityContext: {} - -service: - # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. - type: ClusterIP - # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) to expose the running application on a set of Pods as a network service. - port: 4567 - -# -- [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod -resources: {} - -autoscaling: - # -- Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) - enabled: false - # -- Minimal replicas if resource consumption falls below resource threshholds - minReplicas: 1 - # -- Maximum replicas if resource consumption exceeds resource threshholds - maxReplicas: 100 - # -- targetAverageUtilization of cpu provided to a pod - targetCPUUtilizationPercentage: 80 - # -- targetAverageUtilization of memory provided to a pod - targetMemoryUtilizationPercentage: 80 - -# -- [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. -nodeSelector: {} - -# -- [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. -tolerations: [] - -# -- [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. -affinity: {} - -# List of connector clients. Certificate and Client-ID must be configured in parallel. -#
-# Example Connector: -# - id: grMsEz3EcsS3ENYJufNgUIeg4QsaL49M0gWxSexPdC4pon96Nvju90D8RlvAJB21 -# name: my-connector -# attributes: -# issuerConnector: http://localhost:8080/ -# certificate: |- -# -----BEGIN CERTIFICATE----- -# foo -# -----END CERTIFICATE----- -connectors: [] diff --git a/charts/tractusx-connector-memory/templates/deployment-runtime.yaml b/charts/tractusx-connector-memory/templates/deployment-runtime.yaml index f383b101f..c2a1d61b7 100644 --- a/charts/tractusx-connector-memory/templates/deployment-runtime.yaml +++ b/charts/tractusx-connector-memory/templates/deployment-runtime.yaml @@ -115,21 +115,22 @@ spec: - name: EDC_PARTICIPANT_ID value: {{ .Values.participant.id | required ".Values.participant.id is required" | quote }} - ######################## - ## DAPS CONFIGURATION ## - ######################## + ########################## + # SSI / MIW CONFIGURATION + ########################## + - name: "TX_SSI_MIW_URL" + value: {{ .Values.runtime.ssi.miw.url }} + - name: "TX_SSI_MIW_AUTHORITY_ID" + value: {{ .Values.runtime.ssi.miw.authorityId }} + - name: "TX_SSI_OAUTH_TOKEN_URL" + value: {{ .Values.runtime.ssi.oauth.tokenurl }} + - name: "TX_SSI_OAUTH_CLIENT_ID" + value: {{ .Values.runtime.ssi.oauth.client.id }} + - name: "TX_SSI_OAUTH_CLIENT_SECRET_ALIAS" + value: {{ .Values.runtime.ssi.oauth.client.secretAlias }} + - name: "TX_SSI_ENDPOINT_AUDIENCE" + value: {{ printf "%s%s" (include "txdc.runtime.url.protocol" .) .Values.runtime.endpoints.protocol.path | quote }} - # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/iam/oauth2/oauth2-core - - name: EDC_OAUTH_CLIENT_ID - value: {{ .Values.daps.clientId | required ".Values.daps.clientId is required" | quote }} - - name: EDC_OAUTH_PROVIDER_JWKS_URL - value: {{ printf "%s%s" .Values.daps.url .Values.daps.paths.jwks }} - - name: EDC_OAUTH_TOKEN_URL - value: {{ printf "%s%s" .Values.daps.url .Values.daps.paths.token }} - - name: EDC_OAUTH_PRIVATE_KEY_ALIAS - value: {{ .Values.vault.secretNames.dapsPrivateKey | required ".Values.vault.secretNames.dapsPrivateKey is required" | quote }} - - name: EDC_OAUTH_PUBLIC_KEY_ALIAS - value: {{ .Values.vault.secretNames.dapsPublicKey | required ".Values.vault.secretNames.dapsPublicKey is required" | quote }} ####### # API # @@ -209,10 +210,14 @@ spec: # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/data-plane-transfer - name: "EDC_TRANSFER_PROXY_ENDPOINT" value: {{ include "txdc.dataplane.url.public" . }} + {{- if .Values.vault.secretNames.transferProxyTokenSignerPrivateKey }} - name: "EDC_TRANSFER_PROXY_TOKEN_SIGNER_PRIVATEKEY_ALIAS" value: {{ .Values.vault.secretNames.transferProxyTokenSignerPrivateKey | quote }} + {{- end }} + {{- if .Values.vault.secretNames.transferProxyTokenSignerPublicKey }} - name: "EDC_TRANSFER_PROXY_TOKEN_VERIFIER_PUBLICKEY_ALIAS" value: {{ .Values.vault.secretNames.transferProxyTokenSignerPublicKey | quote }} + {{- end }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/http-receiver - name: "EDC_RECEIVER_HTTP_ENDPOINT" diff --git a/charts/tractusx-connector-memory/templates/ingress-runtime.yaml b/charts/tractusx-connector-memory/templates/ingress-runtime.yaml index a5209ebbf..48ce33b8c 100644 --- a/charts/tractusx-connector-memory/templates/ingress-runtime.yaml +++ b/charts/tractusx-connector-memory/templates/ingress-runtime.yaml @@ -21,7 +21,7 @@ # {{- $fullName := include "txdc.fullname" . }} -{{- $controlLabels := include "txdc.runtime.labels" . | nindent 4 }} +{{- $controlLabels := include "txdc.runtime.labels" . }} {{- $controlEdcEndpoints := .Values.runtime.endpoints }} {{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} {{- $namespace := .Release.Namespace }} @@ -29,6 +29,7 @@ {{- range .Values.runtime.ingresses }} {{- if and .enabled .endpoints }} {{- $controlIngressName := printf "%s-runtime-%s" $fullName .hostname }} +{{- $annotations := .annotations | default dict }} --- {{- if semverCompare ">=1.19-0" $gitVersion }} apiVersion: networking.k8s.io/v1 @@ -42,22 +43,22 @@ metadata: name: {{ $controlIngressName }} namespace: {{ $namespace | default "default" | quote }} labels: - {{- $controlLabels | nindent 2 }} + {{- $controlLabels | nindent 4 }} annotations: {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} - {{- if not (hasKey .annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .annotations "kubernetes.io/ingress.class" .className}} + {{- if not (hasKey $annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $annotations "kubernetes.io/ingress.class" .className}} {{- end }} {{- end }} {{- if .certManager }} {{- if .certManager.issuer }} - {{- $_ := set .annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- $_ := set $annotations "cert-manager.io/issuer" .certManager.issuer}} {{- end }} {{- if .certManager.clusterIssuer }} - {{- $_ := set .annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- $_ := set $annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} {{- end }} {{- end }} - {{- with .annotations }} + {{- with $annotations }} {{- toYaml . | nindent 4 }} {{- end }} spec: diff --git a/charts/tractusx-connector-memory/templates/tests/test-readiness.yaml b/charts/tractusx-connector-memory/templates/tests/test-readiness.yaml index ad051af69..f62d619cb 100644 --- a/charts/tractusx-connector-memory/templates/tests/test-readiness.yaml +++ b/charts/tractusx-connector-memory/templates/tests/test-readiness.yaml @@ -29,6 +29,7 @@ metadata: {{- include "txdc.runtime.labels" . | nindent 4 }} annotations: "helm.sh/hook": test + "helm.sh/hook-delete-policy": {{ .Values.tests.hookDeletePolicy }} spec: containers: - name: wget diff --git a/charts/tractusx-connector-memory/values.yaml b/charts/tractusx-connector-memory/values.yaml index 4668714cf..b0b9b2351 100644 --- a/charts/tractusx-connector-memory/values.yaml +++ b/charts/tractusx-connector-memory/values.yaml @@ -23,8 +23,6 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. -install: - daps: true fullnameOverride: "" nameOverride: "" # -- Existing image pull secret to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) @@ -130,6 +128,19 @@ runtime: businessPartnerValidation: log: agreementValidation: true + # SSI configuration + ssi: + miw: + url: "" + authorityId: "" + oauth: + tokenurl: "" + client: + id: "" + secretAlias: "client-secret" + endpoint: + audience: "http://this.audience" + service: # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. type: ClusterIP @@ -290,16 +301,11 @@ vault: # secrets can be seeded by supplying them in a comma separated list key1:secret2,key2:secret2 secrets: "" secretNames: - transferProxyTokenSignerPrivateKey: transfer-proxy-token-signer-private-key - transferProxyTokenSignerPublicKey: transfer-proxy-token-signer-public-key transferProxyTokenEncryptionAesKey: transfer-proxy-token-encryption-aes-key - dapsPrivateKey: daps-private-key - dapsPublicKey: daps-public-key server: postStart: |- daps: - fullnameOverride: "daps" - url: "" + url: "http://{{ .Release.Name }}-daps:4567" clientId: "" paths: jwks: /jwks.json @@ -323,6 +329,7 @@ serviceAccount: name: "" # -- Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) imagePullSecrets: [] -idsdaps: - connectors: - - certificate: |- +# -- Configurations for Helm tests +tests: + # -- Configure the hook-delete-policy for Helm tests + hookDeletePolicy: before-hook-creation,hook-succeeded diff --git a/charts/tractusx-connector/Chart.yaml b/charts/tractusx-connector/Chart.yaml index 307be2907..a92e55e5b 100644 --- a/charts/tractusx-connector/Chart.yaml +++ b/charts/tractusx-connector/Chart.yaml @@ -40,22 +40,16 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.1 +version: 0.5.0-rc1 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "0.4.1" +appVersion: "0.5.0-rc1" home: https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector sources: - https://github.com/eclipse-tractusx/tractusx-edc/tree/main/charts/tractusx-connector dependencies: - # IDS Dynamic Attribute Provisioning Service (IAM) - - name: daps - version: 0.0.1 - repository: "file://./subcharts/omejdn" - alias: daps - condition: install.daps # HashiCorp Vault - name: vault alias: vault diff --git a/charts/tractusx-connector/README.md b/charts/tractusx-connector/README.md index cfb07b537..161996f33 100644 --- a/charts/tractusx-connector/README.md +++ b/charts/tractusx-connector/README.md @@ -1,6 +1,6 @@ # tractusx-connector -![Version: 0.4.1](https://img.shields.io/badge/Version-0.4.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.4.1](https://img.shields.io/badge/AppVersion-0.4.1-informational?style=flat-square) +![Version: 0.5.0-rc1](https://img.shields.io/badge/Version-0.5.0--rc1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.5.0-rc1](https://img.shields.io/badge/AppVersion-0.5.0--rc1-informational?style=flat-square) A Helm chart for Tractus-X Eclipse Data Space Connector. The connector deployment consists of two runtime consists of a Control Plane and a Data Plane. Note that _no_ external dependencies such as a PostgreSQL database and HashiCorp Vault are included. @@ -37,7 +37,7 @@ Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev -helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0.4.1 \ +helm install my-release tractusx-edc/tractusx-connector --version 0.5.0-rc1 \ -f /tractusx-connector-test.yaml ``` @@ -49,7 +49,6 @@ helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0. | Repository | Name | Version | |------------|------|---------| -| file://./subcharts/omejdn | daps(daps) | 0.0.1 | | https://charts.bitnami.com/bitnami | postgresql(postgresql) | 12.1.6 | | https://helm.releases.hashicorp.com | vault(vault) | 0.20.0 | @@ -155,20 +154,17 @@ helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0. | controlplane.securityContext.runAsUser | int | `10001` | The container's process will run with the specified uid | | controlplane.service.annotations | object | `{}` | | | controlplane.service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | +| controlplane.ssi.endpoint.audience | string | `"http://this.audience"` | | +| controlplane.ssi.miw.authorityId | string | `""` | | +| controlplane.ssi.miw.url | string | `""` | | +| controlplane.ssi.oauth.client.id | string | `""` | | +| controlplane.ssi.oauth.client.secretAlias | string | `"client-secret"` | | +| controlplane.ssi.oauth.tokenurl | string | `""` | | | controlplane.tolerations | list | `[]` | | | controlplane.url.ids | string | `""` | Explicitly declared url for reaching the ids api (e.g. if ingresses not used) | | controlplane.volumeMounts | list | `[]` | declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container | | controlplane.volumes | list | `[]` | [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories | | customLabels | object | `{}` | | -| daps.clientId | string | `""` | | -| daps.connectors[0].attributes.referringConnector | string | `"http://sokrates-controlplane/BPNSOKRATES"` | | -| daps.connectors[0].certificate | string | `""` | | -| daps.connectors[0].id | string | `"E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65"` | | -| daps.connectors[0].name | string | `"sokrates"` | | -| daps.fullnameOverride | string | `"daps"` | | -| daps.paths.jwks | string | `"/jwks.json"` | | -| daps.paths.token | string | `"/token"` | | -| daps.url | string | `""` | | | dataplane.affinity | object | `{}` | | | dataplane.autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | | dataplane.autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | @@ -249,38 +245,39 @@ helm install my-release tractusx-edc/tractusx-connector-azure-vault --version 0. | dataplane.volumeMounts | list | `[]` | declare where to mount [volumes](https://kubernetes.io/docs/concepts/storage/volumes/) into the container | | dataplane.volumes | list | `[]` | [volume](https://kubernetes.io/docs/concepts/storage/volumes/) directories | | fullnameOverride | string | `""` | | -| idsdaps.connectors[0].certificate | string | `""` | | | imagePullSecrets | list | `[]` | Existing image pull secret to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | -| install.daps | bool | `true` | | | install.postgresql | bool | `true` | | | install.vault | bool | `true` | | | nameOverride | string | `""` | | +| networkPolicy.controlplane | object | `{"from":[{"namespaceSelector":{}}]}` | Configuration of the controlplane component | +| networkPolicy.controlplane.from | list | `[{"namespaceSelector":{}}]` | Specify from rule network policy for cp (defaults to all namespaces) | +| networkPolicy.dataplane | object | `{"from":[{"namespaceSelector":{}}]}` | Configuration of the dataplane component | +| networkPolicy.dataplane.from | list | `[{"namespaceSelector":{}}]` | Specify from rule network policy for dp (defaults to all namespaces) | +| networkPolicy.enabled | bool | `false` | If `true` network policy will be created to restrict access to control- and dataplane | | participant.id | string | `""` | | | postgresql.auth.database | string | `"edc"` | | | postgresql.auth.password | string | `"password"` | | | postgresql.auth.username | string | `"user"` | | -| postgresql.fullnameOverride | string | `"postgresql"` | | -| postgresql.jdbcUrl | string | `""` | | +| postgresql.jdbcUrl | string | `"jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc"` | | | postgresql.primary.persistence.enabled | bool | `false` | | | postgresql.readReplicas.persistence.enabled | bool | `false` | | | serviceAccount.annotations | object | `{}` | | | serviceAccount.create | bool | `true` | | | serviceAccount.imagePullSecrets | list | `[]` | Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) | | serviceAccount.name | string | `""` | | -| vault.fullnameOverride | string | `"vault"` | | +| tests | object | `{"hookDeletePolicy":"before-hook-creation,hook-succeeded"}` | Configurations for Helm tests | +| tests.hookDeletePolicy | string | `"before-hook-creation,hook-succeeded"` | Configure the hook-delete-policy for Helm tests | | vault.hashicorp.healthCheck.enabled | bool | `true` | | | vault.hashicorp.healthCheck.standbyOk | bool | `true` | | | vault.hashicorp.paths.health | string | `"/v1/sys/health"` | | | vault.hashicorp.paths.secret | string | `"/v1/secret"` | | | vault.hashicorp.timeout | int | `30` | | | vault.hashicorp.token | string | `""` | | -| vault.hashicorp.url | string | `""` | | +| vault.hashicorp.url | string | `"http://{{ .Release.Name }}-vault:8200"` | | | vault.injector.enabled | bool | `false` | | -| vault.secretNames.dapsPrivateKey | string | `"daps-private-key"` | | -| vault.secretNames.dapsPublicKey | string | `"daps-public-key"` | | | vault.secretNames.transferProxyTokenEncryptionAesKey | string | `"transfer-proxy-token-encryption-aes-key"` | | -| vault.secretNames.transferProxyTokenSignerPrivateKey | string | `"transfer-proxy-token-signer-private-key"` | | -| vault.secretNames.transferProxyTokenSignerPublicKey | string | `"transfer-proxy-token-signer-public-key"` | | +| vault.secretNames.transferProxyTokenSignerPrivateKey | string | `nil` | | +| vault.secretNames.transferProxyTokenSignerPublicKey | string | `nil` | | | vault.server.dev.devRootToken | string | `"root"` | | | vault.server.dev.enabled | bool | `true` | | | vault.server.postStart | string | `nil` | | diff --git a/charts/tractusx-connector/README.md.gotmpl b/charts/tractusx-connector/README.md.gotmpl index 267a294f3..210216e6c 100644 --- a/charts/tractusx-connector/README.md.gotmpl +++ b/charts/tractusx-connector/README.md.gotmpl @@ -36,7 +36,7 @@ Combined, run this shell command to start the in-memory Tractus-X EDC runtime: ```shell helm repo add tractusx-edc https://eclipse-tractusx.github.io/charts/dev -helm install my-release tractusx-edc/tractusx-connector-azure-vault --version {{ .Version }} \ +helm install my-release tractusx-edc/tractusx-connector --version {{ .Version }} \ -f /tractusx-connector-test.yaml ``` diff --git a/charts/tractusx-connector/subcharts/omejdn/.helmignore b/charts/tractusx-connector/subcharts/omejdn/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/charts/tractusx-connector/subcharts/omejdn/Chart.yaml b/charts/tractusx-connector/subcharts/omejdn/Chart.yaml deleted file mode 100644 index 3e10aa1fc..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/Chart.yaml +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: v2 -name: daps -description: A Helm chart for Kubernetes -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.4.1 -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -# It is recommended to use it with quotes. -appVersion: "0.4.1" diff --git a/charts/tractusx-connector/subcharts/omejdn/README.md b/charts/tractusx-connector/subcharts/omejdn/README.md deleted file mode 100644 index d23a9f9fa..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# daps - -![Version: 0.4.1](https://img.shields.io/badge/Version-0.4.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 0.4.1](https://img.shields.io/badge/AppVersion-0.4.1-informational?style=flat-square) - -A Helm chart for Kubernetes - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. | -| automountServiceAccountToken | bool | `false` | Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod | -| autoscaling.enabled | bool | `false` | Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) | -| autoscaling.maxReplicas | int | `100` | Maximum replicas if resource consumption exceeds resource threshholds | -| autoscaling.minReplicas | int | `1` | Minimal replicas if resource consumption falls below resource threshholds | -| autoscaling.targetCPUUtilizationPercentage | int | `80` | targetAverageUtilization of cpu provided to a pod | -| autoscaling.targetMemoryUtilizationPercentage | int | `80` | targetAverageUtilization of memory provided to a pod | -| connectors | list | `[]` | | -| fullnameOverride | string | `""` | Overrides the releases full name | -| image.pullPolicy | string | `"IfNotPresent"` | [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use | -| image.repository | string | `"ghcr.io/fraunhofer-aisec/omejdn-server"` | Which omjedn container image to use | -| image.tag | string | `"1.7.1"` | Overrides the image tag whose default is the chart appVersion | -| imagePullSecret.dockerconfigjson | string | `""` | Image pull secret to create to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) Note: This value needs to adhere to the [(base64 encoded) .dockerconfigjson format](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials). Furthermore, if 'imagePullSecret.dockerconfigjson' is defined, it takes precedence over 'imagePullSecrets'. | -| nameOverride | string | `""` | Overrides the charts name | -| nodeSelector | object | `{}` | [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. | -| podAnnotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) | -| podSecurityContext | object | `{}` | | -| replicaCount | int | `1` | Specifies how many replicas of a deployed pod shall be created during the deployment Note: If horizontal pod autoscaling is enabled this setting has no effect | -| resources | object | `{}` | [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod | -| securityContext | object | `{}` | | -| service.port | int | `4567` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) to expose the running application on a set of Pods as a network service. | -| service.type | string | `"ClusterIP"` | [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. | -| serviceAccount.annotations | object | `{}` | [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account | -| serviceAccount.create | bool | `true` | Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release | -| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template | -| tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. | - ----------------------------------------------- -Autogenerated from chart metadata using [helm-docs v1.10.0](https://github.com/norwoodj/helm-docs/releases/v1.10.0) diff --git a/charts/tractusx-connector/subcharts/omejdn/templates/_helpers.tpl b/charts/tractusx-connector/subcharts/omejdn/templates/_helpers.tpl deleted file mode 100644 index 95b115eee..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "omejdn.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "omejdn.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "omejdn.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "omejdn.labels" -}} -helm.sh/chart: {{ include "omejdn.chart" . }} -{{ include "omejdn.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "omejdn.selectorLabels" -}} -app.kubernetes.io/name: {{ include "omejdn.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "omejdn.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "omejdn.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/charts/tractusx-connector/subcharts/omejdn/templates/deployment.yaml b/charts/tractusx-connector/subcharts/omejdn/templates/deployment.yaml deleted file mode 100644 index 58bfff105..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/templates/deployment.yaml +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "omejdn.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "omejdn.selectorLabels" . | nindent 8 }} - spec: - {{- if .Values.imagePullSecret.dockerconfigjson }} - imagePullSecrets: - - name: {{ include "omejdn.fullname" . }}-imagepullsecret - {{- else }} - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- end }} - serviceAccountName: {{ include "omejdn.serviceAccountName" . }} - automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - initContainers: - - name: init-daps-pvc - image: alpine - command: - - "sh" - - "-c" - args: - - | - cp /opt/config/omejdn.yml /etc/daps/omejdn.yml - cp /opt/config/clients.yml /etc/daps/clients.yml - cp /opt/config/plugins.yml /etc/daps/plugins.yml - cp /opt/config/scope_mapping.yml /etc/daps/scope_mapping.yml - apk add --update openssl - openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout /etc/keys/omejdn/omejdn.key \ - -subj "/C=DE/ST=Berlin/L=Berlin/O=Tractus-X-EDC-Test, Inc./OU=DE" - volumeMounts: - - mountPath: /etc/daps - name: config-dir - - mountPath: /etc/keys/omejdn - name: omejdn-key-dir - - mountPath: /opt/config/omejdn.yml - name: omejdn-config - subPath: omejdn.yml - - mountPath: /opt/config/scope_mapping.yml - name: scope-mapping - subPath: scope_mapping.yml - - mountPath: /opt/config/clients.yml - name: clients-config - subPath: clients.yml - - mountPath: /opt/config/plugins.yml - name: plugins-config - subPath: plugins.yml - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - volumeMounts: - - mountPath: /opt/config/ - name: config-dir - - mountPath: /opt/keys/omejdn/omejdn.key - name: omejdn-key-dir - subPath: omejdn.key - - mountPath: /opt/keys/clients/ - name: client-certificates - ports: - - name: http - containerPort: 4567 - protocol: TCP - livenessProbe: - httpGet: - path: /jwks.json - port: http - readinessProbe: - httpGet: - path: /jwks.json - port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - env: - - name: OMEJDN_JWT_AUD_OVERRIDE - value: "idsc:IDS_CONNECTORS_ALL" - - name: OMEJDN_PLUGINS - value: "config/plugins.yml" - volumes: - - name: config-dir - emptyDir: { } - - name: omejdn-key-dir - emptyDir: { } - - name: omejdn-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: omejdn.yml - path: omejdn.yml - - name: scope-mapping - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: scope_mapping.yml - path: scope_mapping.yml - - name: clients-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: clients.yml - path: clients.yml - - name: plugins-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: plugins.yml - path: plugins.yml - - name: client-certificates - configMap: - name: {{ include "omejdn.fullname" . }} - items: - {{- range $i, $val := .Values.connectors }} - - key: {{ $val.name }} - path: {{ $val.id }}.cert - {{- end }} diff --git a/charts/tractusx-connector/subcharts/omejdn/templates/hpa.yaml b/charts/tractusx-connector/subcharts/omejdn/templates/hpa.yaml deleted file mode 100644 index f1f072f6c..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/templates/hpa.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation - # - # See the NOTICE file(s) distributed with this work for additional - # information regarding copyright ownership. - # - # 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 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - # License for the specific language governing permissions and limitations - # under the License. - # - # SPDX-License-Identifier: Apache-2.0 - # - -{{- if .Values.autoscaling.enabled }} ---- -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "omejdn.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/charts/tractusx-connector/subcharts/omejdn/templates/imagepullsecret.yaml b/charts/tractusx-connector/subcharts/omejdn/templates/imagepullsecret.yaml deleted file mode 100644 index 44f573e0f..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/templates/imagepullsecret.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation - # - # See the NOTICE file(s) distributed with this work for additional - # information regarding copyright ownership. - # - # 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 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - # License for the specific language governing permissions and limitations - # under the License. - # - # SPDX-License-Identifier: Apache-2.0 - # - -{{- if .Values.imagePullSecret.dockerconfigjson }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "edc-dataplane.fullname" . }}-imagepullsecret - namespace: {{ .Release.Namespace | default "default" | quote }} - labels: - {{- include "edc-dataplane.labels" . | nindent 4 }} -data: - .dockerconfigjson: {{ .Values.imagePullSecret.dockerconfigjson }} -type: kubernetes.io/dockerconfigjson -{{- end }} diff --git a/charts/tractusx-connector/subcharts/omejdn/values.yaml b/charts/tractusx-connector/subcharts/omejdn/values.yaml deleted file mode 100644 index f411b8774..000000000 --- a/charts/tractusx-connector/subcharts/omejdn/values.yaml +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -# Default values for omejdn. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -# -- Specifies how many replicas of a deployed pod shall be created during the deployment -# Note: If horizontal pod autoscaling is enabled this setting has no effect -replicaCount: 1 - -image: - # -- Which omjedn container image to use - repository: ghcr.io/fraunhofer-aisec/omejdn-server - # -- [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use - pullPolicy: IfNotPresent - # -- Overrides the image tag whose default is the chart appVersion - tag: "1.7.1" - -imagePullSecret: - # -- Image pull secret to create to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) - # Note: This value needs to adhere to the [(base64 encoded) .dockerconfigjson format](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials). - # Furthermore, if 'imagePullSecret.dockerconfigjson' is defined, it takes precedence over 'imagePullSecrets'. - dockerconfigjson: "" - -# -- Overrides the charts name -nameOverride: "" - -# -- Overrides the releases full name -fullnameOverride: "" - -serviceAccount: - # -- Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release - create: true - # -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account - annotations: {} - # -- The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template - name: "" - -# -- Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod -automountServiceAccountToken: false - -# -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) -podAnnotations: {} - -# The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment -podSecurityContext: {} - -# The [container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) defines privilege and access control settings for a Container within a pod -securityContext: {} - -service: - # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. - type: ClusterIP - # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) to expose the running application on a set of Pods as a network service. - port: 4567 - -# -- [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod -resources: {} - -autoscaling: - # -- Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) - enabled: false - # -- Minimal replicas if resource consumption falls below resource threshholds - minReplicas: 1 - # -- Maximum replicas if resource consumption exceeds resource threshholds - maxReplicas: 100 - # -- targetAverageUtilization of cpu provided to a pod - targetCPUUtilizationPercentage: 80 - # -- targetAverageUtilization of memory provided to a pod - targetMemoryUtilizationPercentage: 80 - -# -- [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. -nodeSelector: {} - -# -- [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. -tolerations: [] - -# -- [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. -affinity: {} - -# List of connector clients. Certificate and Client-ID must be configured in parallel. -#
-# Example Connector: -# - id: grMsEz3EcsS3ENYJufNgUIeg4QsaL49M0gWxSexPdC4pon96Nvju90D8RlvAJB21 -# name: my-connector -# attributes: -# issuerConnector: http://localhost:8080/ -# certificate: |- -# -----BEGIN CERTIFICATE----- -# foo -# -----END CERTIFICATE----- -connectors: [] diff --git a/charts/tractusx-connector/templates/deployment-controlplane.yaml b/charts/tractusx-connector/templates/deployment-controlplane.yaml index f4cc125e1..27eafea69 100644 --- a/charts/tractusx-connector/templates/deployment-controlplane.yaml +++ b/charts/tractusx-connector/templates/deployment-controlplane.yaml @@ -1,24 +1,24 @@ # -# Copyright (c) 2023 ZF Friedrichshafen AG -# Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH -# Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) -# Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# + # Copyright (c) 2023 ZF Friedrichshafen AG + # Copyright (c) 2023 Mercedes-Benz Tech Innovation GmbH + # Copyright (c) 2023 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + # Copyright (c) 2021, 2023 Contributors to the Eclipse Foundation + # + # See the NOTICE file(s) distributed with this work for additional + # information regarding copyright ownership. + # + # 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 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + # License for the specific language governing permissions and limitations + # under the License. + # + # SPDX-License-Identifier: Apache-2.0 + # --- apiVersion: apps/v1 @@ -115,21 +115,21 @@ spec: - name: EDC_PARTICIPANT_ID value: {{ .Values.participant.id | required ".Values.participant.id is required" | quote }} - ######################## - ## DAPS CONFIGURATION ## - ######################## - - # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/iam/oauth2/oauth2-core - - name: EDC_OAUTH_CLIENT_ID - value: {{ .Values.daps.clientId | required ".Values.daps.clientId is required" | quote }} - - name: EDC_OAUTH_PROVIDER_JWKS_URL - value: {{ printf "%s%s" .Values.daps.url .Values.daps.paths.jwks }} - - name: EDC_OAUTH_TOKEN_URL - value: {{ printf "%s%s" .Values.daps.url .Values.daps.paths.token }} - - name: EDC_OAUTH_PRIVATE_KEY_ALIAS - value: {{ .Values.vault.secretNames.dapsPrivateKey | required ".Values.vault.secretNames.dapsPrivateKey is required" | quote }} - - name: EDC_OAUTH_CERTIFICATE_ALIAS - value: {{ .Values.vault.secretNames.dapsPublicKey | required ".Values.vault.secretNames.dapsPublicKey is required" | quote }} + ########################## + # SSI / MIW CONFIGURATION + ########################## + - name: "TX_SSI_MIW_URL" + value: {{ .Values.controlplane.ssi.miw.url }} + - name: "TX_SSI_MIW_AUTHORITY_ID" + value: {{ .Values.controlplane.ssi.miw.authorityId }} + - name: "TX_SSI_OAUTH_TOKEN_URL" + value: {{ .Values.controlplane.ssi.oauth.tokenurl }} + - name: "TX_SSI_OAUTH_CLIENT_ID" + value: {{ .Values.controlplane.ssi.oauth.client.id }} + - name: "TX_SSI_OAUTH_CLIENT_SECRET_ALIAS" + value: {{ .Values.controlplane.ssi.oauth.client.secretAlias }} + - name: "TX_SSI_ENDPOINT_AUDIENCE" + value: {{ printf "%s%s" (include "txdc.controlplane.url.protocol" .) .Values.controlplane.endpoints.protocol.path | quote }} ####### # API # @@ -182,7 +182,7 @@ spec: - name: "EDC_DATASOURCE_ASSET_PASSWORD" value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_ASSET_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/contract-definition-store-sql - name: "EDC_DATASOURCE_CONTRACTDEFINITION_NAME" @@ -192,7 +192,7 @@ spec: - name: "EDC_DATASOURCE_CONTRACTDEFINITION_PASSWORD" value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_CONTRACTDEFINITION_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/contract-negotiation-store-sql - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_NAME" @@ -202,7 +202,7 @@ spec: - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_PASSWORD" value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_CONTRACTNEGOTIATION_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/policy-store-sql - name: "EDC_DATASOURCE_POLICY_NAME" @@ -212,7 +212,7 @@ spec: - name: "EDC_DATASOURCE_POLICY_PASSWORD" value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_POLICY_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/store/sql/transfer-process-store-sql - name: "EDC_DATASOURCE_TRANSFERPROCESS_NAME" @@ -222,17 +222,17 @@ spec: - name: "EDC_DATASOURCE_TRANSFERPROCESS_PASSWORD" value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_TRANSFERPROCESS_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/edr-cache-sql - name: "EDC_DATASOURCE_EDR_NAME" value: "edr" - name: "EDC_DATASOURCE_EDR_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_EDR_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_EDR_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} ################ ## DATA PLANE ## @@ -252,11 +252,14 @@ spec: # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/data-plane-transfer - name: "EDC_TRANSFER_PROXY_ENDPOINT" value: {{ include "txdc.dataplane.url.public" . }} + {{- if .Values.vault.secretNames.transferProxyTokenSignerPrivateKey }} - name: "EDC_TRANSFER_PROXY_TOKEN_SIGNER_PRIVATEKEY_ALIAS" value: {{ .Values.vault.secretNames.transferProxyTokenSignerPrivateKey | quote }} + {{- end }} + {{- if .Values.vault.secretNames.transferProxyTokenSignerPublicKey }} - name: "EDC_TRANSFER_PROXY_TOKEN_VERIFIER_PUBLICKEY_ALIAS" value: {{ .Values.vault.secretNames.transferProxyTokenSignerPublicKey | quote }} - + {{- end }} # see extension https://github.com/eclipse-edc/Connector/tree/main/extensions/control-plane/transfer/transfer-pull-http-dynamic-receiver - name: "EDC_RECEIVER_HTTP_DYNAMIC_ENDPOINT" @@ -268,7 +271,7 @@ spec: # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/hashicorp-vault - name: "EDC_VAULT_HASHICORP_URL" - value: {{ .Values.vault.hashicorp.url | required ".Values.vault.hashicorp.url is required" | quote }} + value: {{ tpl .Values.vault.hashicorp.url . | quote }} - name: "EDC_VAULT_HASHICORP_TOKEN" value: {{ .Values.vault.hashicorp.token | required ".Values.vault.hashicorp.token is required" | quote }} - name: "EDC_VAULT_HASHICORP_TIMEOUT_SECONDS" diff --git a/charts/tractusx-connector/templates/deployment-dataplane.yaml b/charts/tractusx-connector/templates/deployment-dataplane.yaml index 5a911dea2..01ef5ca33 100644 --- a/charts/tractusx-connector/templates/deployment-dataplane.yaml +++ b/charts/tractusx-connector/templates/deployment-dataplane.yaml @@ -155,11 +155,11 @@ spec: - name: "EDC_DATASOURCE_EDR_NAME" value: "edr" - name: "EDC_DATASOURCE_EDR_USER" - value: {{ .Values.postgresql.username | required ".Values.postgresql.username is required" | quote }} + value: {{ .Values.postgresql.auth.username | required ".Values.postgresql.auth.username is required" | quote }} - name: "EDC_DATASOURCE_EDR_PASSWORD" - value: {{ .Values.postgresql.password | required ".Values.postgresql.password is required" | quote }} + value: {{ .Values.postgresql.auth.password | required ".Values.postgresql.auth.password is required" | quote }} - name: "EDC_DATASOURCE_EDR_URL" - value: {{ .Values.postgresql.jdbcUrl | required ".Values.postgresql.jdbcUrl is required" | quote }} + value: {{ tpl .Values.postgresql.jdbcUrl . | quote }} ########### ## VAULT ## @@ -167,7 +167,7 @@ spec: # see extension https://github.com/eclipse-tractusx/tractusx-edc/tree/main/edc-extensions/hashicorp-vault - name: "EDC_VAULT_HASHICORP_URL" - value: {{ .Values.vault.hashicorp.url | required ".Values.vault.hashicorp.url is required" | quote }} + value: {{ tpl .Values.vault.hashicorp.url . | quote }} - name: "EDC_VAULT_HASHICORP_TOKEN" value: {{ .Values.vault.hashicorp.token | required ".Values.vault.hashicorp.token is required" | quote }} - name: "EDC_VAULT_HASHICORP_TIMEOUT_SECONDS" diff --git a/charts/tractusx-connector/templates/ingress-controlplane.yaml b/charts/tractusx-connector/templates/ingress-controlplane.yaml index ee490510f..abc90106e 100644 --- a/charts/tractusx-connector/templates/ingress-controlplane.yaml +++ b/charts/tractusx-connector/templates/ingress-controlplane.yaml @@ -21,7 +21,7 @@ # {{- $fullName := include "txdc.fullname" . }} -{{- $controlLabels := include "txdc.controlplane.labels" . | nindent 4 }} +{{- $controlLabels := include "txdc.controlplane.labels" . }} {{- $controlEdcEndpoints := .Values.controlplane.endpoints }} {{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} {{- $namespace := .Release.Namespace }} @@ -29,6 +29,7 @@ {{- range .Values.controlplane.ingresses }} {{- if and .enabled .endpoints }} {{- $controlIngressName := printf "%s-controlplane-%s" $fullName .hostname }} +{{- $annotations := .annotations | default dict }} --- {{- if semverCompare ">=1.19-0" $gitVersion }} apiVersion: networking.k8s.io/v1 @@ -42,22 +43,22 @@ metadata: name: {{ $controlIngressName }} namespace: {{ $namespace | default "default" | quote }} labels: - {{- $controlLabels | nindent 2 }} + {{- $controlLabels | nindent 4 }} annotations: {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} - {{- if not (hasKey .annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .annotations "kubernetes.io/ingress.class" .className}} + {{- if not (hasKey $annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $annotations "kubernetes.io/ingress.class" .className}} {{- end }} {{- end }} {{- if .certManager }} {{- if .certManager.issuer }} - {{- $_ := set .annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- $_ := set $annotations "cert-manager.io/issuer" .certManager.issuer}} {{- end }} {{- if .certManager.clusterIssuer }} - {{- $_ := set .annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- $_ := set $annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} {{- end }} {{- end }} - {{- with .annotations }} + {{- with $annotations }} {{- toYaml . | nindent 4 }} {{- end }} spec: diff --git a/charts/tractusx-connector/templates/ingress-dataplane.yaml b/charts/tractusx-connector/templates/ingress-dataplane.yaml index 14e88bff9..4777a55d4 100644 --- a/charts/tractusx-connector/templates/ingress-dataplane.yaml +++ b/charts/tractusx-connector/templates/ingress-dataplane.yaml @@ -21,7 +21,7 @@ # {{- $fullName := include "txdc.fullname" . }} -{{- $dataLabels := include "txdc.dataplane.labels" . | nindent 4 }} +{{- $dataLabels := include "txdc.dataplane.labels" . }} {{- $dataEdcEndpoints := .Values.dataplane.endpoints }} {{- $gitVersion := .Capabilities.KubeVersion.GitVersion }} {{- $namespace := .Release.Namespace }} @@ -29,6 +29,7 @@ {{- range .Values.dataplane.ingresses }} {{- if and .enabled .endpoints }} {{- $dataIngressName := printf "%s-dataplane-%s" $fullName .hostname }} +{{- $annotations := .annotations | default dict }} --- {{- if semverCompare ">=1.19-0" $gitVersion }} apiVersion: networking.k8s.io/v1 @@ -42,22 +43,22 @@ metadata: name: {{ $dataIngressName }} namespace: {{ $namespace | default "default" | quote }} labels: - {{- $dataLabels | nindent 2 }} + {{- $dataLabels | nindent 4 }} annotations: {{- if and .className (not (semverCompare ">=1.18-0" $gitVersion)) }} - {{- if not (hasKey .annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .annotations "kubernetes.io/ingress.class" .className}} + {{- if not (hasKey $annotations "kubernetes.io/ingress.class") }} + {{- $_ := set $annotations "kubernetes.io/ingress.class" .className}} {{- end }} {{- end }} {{- if .certManager }} {{- if .certManager.issuer }} - {{- $_ := set .annotations "cert-manager.io/issuer" .certManager.issuer}} + {{- $_ := set $annotations "cert-manager.io/issuer" .certManager.issuer}} {{- end }} {{- if .certManager.clusterIssuer }} - {{- $_ := set .annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} + {{- $_ := set $annotations "cert-manager.io/cluster-issuer" .certManager.clusterIssuer}} {{- end }} {{- end }} - {{- with .annotations }} + {{- with $annotations }} {{- toYaml . | nindent 4 }} {{- end }} spec: diff --git a/charts/tractusx-connector/templates/networkpolicy.yaml b/charts/tractusx-connector/templates/networkpolicy.yaml new file mode 100644 index 000000000..7a40cb6a3 --- /dev/null +++ b/charts/tractusx-connector/templates/networkpolicy.yaml @@ -0,0 +1,45 @@ +# +# Copyright (c) 2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +{{- if eq (.Values.networkPolicy.enabled | toString) "true" }} +{{- range tuple "controlplane" "dataplane" }} +{{- $name := . }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: {{ include "txdc.fullname" $ }}-{{ $name }} + labels: + {{- include (printf "txdc.%s.labels" $name) $ | nindent 4 }} +spec: + podSelector: + matchLabels: + {{- include (printf "txdc.%s.selectorLabels" $name) $ | nindent 6 }} + ingress: + - from: + {{- toYaml (index $.Values.networkPolicy $name "from") | nindent 6 }} + ports: + {{- range $key,$value := (index $.Values $name "endpoints") }} + - port: {{ $value.port }} + protocol: TCP + {{- end }} + policyTypes: + - Ingress +--- +{{- end }} +{{- end }} diff --git a/charts/tractusx-connector/templates/tests/test-controlplane-readiness.yaml b/charts/tractusx-connector/templates/tests/test-controlplane-readiness.yaml index f43ce52eb..694084ded 100644 --- a/charts/tractusx-connector/templates/tests/test-controlplane-readiness.yaml +++ b/charts/tractusx-connector/templates/tests/test-controlplane-readiness.yaml @@ -26,6 +26,7 @@ metadata: {{- include "txdc.controlplane.labels" . | nindent 4 }} annotations: "helm.sh/hook": test + "helm.sh/hook-delete-policy": {{ .Values.tests.hookDeletePolicy }} spec: containers: - name: wget diff --git a/charts/tractusx-connector/templates/tests/test-dataplane-readiness.yaml b/charts/tractusx-connector/templates/tests/test-dataplane-readiness.yaml index 0d013ea66..0ecc0ce32 100644 --- a/charts/tractusx-connector/templates/tests/test-dataplane-readiness.yaml +++ b/charts/tractusx-connector/templates/tests/test-dataplane-readiness.yaml @@ -26,6 +26,7 @@ metadata: {{- include "txdc.dataplane.labels" . | nindent 4 }} annotations: "helm.sh/hook": test + "helm.sh/hook-delete-policy": {{ .Values.tests.hookDeletePolicy }} spec: containers: - name: wget diff --git a/charts/tractusx-connector/values.yaml b/charts/tractusx-connector/values.yaml index 2825a2e7f..21b4a4edc 100644 --- a/charts/tractusx-connector/values.yaml +++ b/charts/tractusx-connector/values.yaml @@ -27,7 +27,6 @@ # Declare variables to be passed into your templates. install: - daps: true postgresql: true vault: true fullnameOverride: "" @@ -130,6 +129,20 @@ controlplane: businessPartnerValidation: log: agreementValidation: true + + # SSI configuration + ssi: + miw: + url: "" + authorityId: "" + oauth: + tokenurl: "" + client: + id: "" + secretAlias: "client-secret" + endpoint: + audience: "http://this.audience" + service: # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. type: ClusterIP @@ -489,8 +502,7 @@ dataplane: # -- Explicitly declared url for reaching the public api (e.g. if ingresses not used) public: "" postgresql: - jdbcUrl: "" - fullnameOverride: "postgresql" + jdbcUrl: "jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc" primary: persistence: enabled: false @@ -502,17 +514,15 @@ postgresql: username: "user" password: "password" vault: - fullnameOverride: "vault" injector: enabled: false server: dev: enabled: true devRootToken: "root" - # Must be the same certificate that is configured in section 'daps' postStart: # must be set externally! hashicorp: - url: "" + url: "http://{{ .Release.Name }}-vault:8200" token: "" timeout: 30 healthCheck: @@ -522,27 +532,26 @@ vault: secret: /v1/secret health: /v1/sys/health secretNames: - transferProxyTokenSignerPrivateKey: transfer-proxy-token-signer-private-key - transferProxyTokenSignerPublicKey: transfer-proxy-token-signer-public-key + transferProxyTokenSignerPrivateKey: + transferProxyTokenSignerPublicKey: transferProxyTokenEncryptionAesKey: transfer-proxy-token-encryption-aes-key - dapsPrivateKey: daps-private-key - dapsPublicKey: daps-public-key -daps: - fullnameOverride: "daps" - url: "" - clientId: "" - paths: - jwks: /jwks.json - token: /token - connectors: - - id: E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65 - name: sokrates - attributes: - referringConnector: http://sokrates-controlplane/BPNSOKRATES - # Must be the same certificate that is stores in section 'sokrates-vault' - certificate: "" # must be set externally! backendService: httpProxyTokenReceiverUrl: "" + +networkPolicy: + # -- If `true` network policy will be created to restrict access to control- and dataplane + enabled: false + # -- Configuration of the controlplane component + controlplane: + # -- Specify from rule network policy for cp (defaults to all namespaces) + from: + - namespaceSelector: {} + # -- Configuration of the dataplane component + dataplane: + # -- Specify from rule network policy for dp (defaults to all namespaces) + from: + - namespaceSelector: {} + serviceAccount: # Specifies whether a service account should be created create: true @@ -553,6 +562,8 @@ serviceAccount: name: "" # -- Existing image pull secret bound to the service account to use to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) imagePullSecrets: [] -idsdaps: - connectors: - - certificate: |- + +# -- Configurations for Helm tests +tests: + # -- Configure the hook-delete-policy for Helm tests + hookDeletePolicy: before-hook-creation,hook-succeeded diff --git a/core/json-ld-core/build.gradle.kts b/core/json-ld-core/build.gradle.kts new file mode 100644 index 000000000..22bf99e1a --- /dev/null +++ b/core/json-ld-core/build.gradle.kts @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2023 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` +} + +dependencies { + implementation(libs.edc.spi.core) + implementation(libs.edc.spi.jsonld) + testImplementation(testFixtures(libs.edc.junit)) +} \ No newline at end of file diff --git a/core/json-ld-core/src/main/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtension.java b/core/json-ld-core/src/main/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtension.java new file mode 100644 index 000000000..cf80367fe --- /dev/null +++ b/core/json-ld-core/src/main/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtension.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.jsonld; + +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Map; + +import static java.lang.String.format; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + +public class JsonLdExtension implements ServiceExtension { + + public static final String CREDENTIALS_V_1 = "https://www.w3.org/2018/credentials/v1"; + public static final String CREDENTIALS_SUMMARY_V_1 = "https://w3id.org/2023/catenax/credentials/summary/v1"; + private static final String PREFIX = "document" + File.separator; + private static final Map FILES = Map.of( + CREDENTIALS_V_1, PREFIX + "credential-v1.jsonld", + CREDENTIALS_SUMMARY_V_1, PREFIX + "summary-vc-context-v1.jsonld"); + @Inject + private JsonLd jsonLdService; + + @Inject + private Monitor monitor; + + @Override + public void initialize(ServiceExtensionContext context) { + FILES.entrySet().stream().map(this::mapToFile) + .forEach(result -> result.onSuccess(entry -> jsonLdService.registerCachedDocument(entry.getKey(), entry.getValue())) + .onFailure(failure -> monitor.warning("Failed to register cached json-ld document: " + failure.getFailureDetail()))); + } + + private Result> mapToFile(Map.Entry fileEntry) { + return getResourceFile(fileEntry.getValue()) + .map(file1 -> Map.entry(fileEntry.getKey(), file1)); + } + + @NotNull + private Result getResourceFile(String name) { + try (var stream = getClass().getClassLoader().getResourceAsStream(name)) { + if (stream == null) { + return Result.failure(format("Cannot find resource %s", name)); + } + + var filename = Path.of(name).getFileName().toString(); + var parts = filename.split("\\."); + var tempFile = Files.createTempFile(parts[0], "." + parts[1]); + Files.copy(stream, tempFile, REPLACE_EXISTING); + return Result.success(tempFile.toFile()); + } catch (Exception e) { + return Result.failure(format("Cannot read resource %s: ", name)); + } + } + +} diff --git a/core/json-ld-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/core/json-ld-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..b427bdb0b --- /dev/null +++ b/core/json-ld-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 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 +# +# + +org.eclipse.tractusx.edc.jsonld.JsonLdExtension \ No newline at end of file diff --git a/core/json-ld-core/src/main/resources/document/credential-v1.jsonld b/core/json-ld-core/src/main/resources/document/credential-v1.jsonld new file mode 100644 index 000000000..0124a3c41 --- /dev/null +++ b/core/json-ld-core/src/main/resources/document/credential-v1.jsonld @@ -0,0 +1,237 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "VerifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "credentialSchema": { + "@id": "cred:credentialSchema", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + + "JsonSchemaValidator2018": "cred:JsonSchemaValidator2018" + } + }, + "credentialStatus": {"@id": "cred:credentialStatus", "@type": "@id"}, + "credentialSubject": {"@id": "cred:credentialSubject", "@type": "@id"}, + "evidence": {"@id": "cred:evidence", "@type": "@id"}, + "expirationDate": {"@id": "cred:expirationDate", "@type": "xsd:dateTime"}, + "holder": {"@id": "cred:holder", "@type": "@id"}, + "issued": {"@id": "cred:issued", "@type": "xsd:dateTime"}, + "issuer": {"@id": "cred:issuer", "@type": "@id"}, + "issuanceDate": {"@id": "cred:issuanceDate", "@type": "xsd:dateTime"}, + "proof": {"@id": "sec:proof", "@type": "@id", "@container": "@graph"}, + "refreshService": { + "@id": "cred:refreshService", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + + "ManualRefreshService2018": "cred:ManualRefreshService2018" + } + }, + "termsOfUse": {"@id": "cred:termsOfUse", "@type": "@id"}, + "validFrom": {"@id": "cred:validFrom", "@type": "xsd:dateTime"}, + "validUntil": {"@id": "cred:validUntil", "@type": "xsd:dateTime"} + } + }, + + "VerifiablePresentation": { + "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + "sec": "https://w3id.org/security#", + + "holder": {"@id": "cred:holder", "@type": "@id"}, + "proof": {"@id": "sec:proof", "@type": "@id", "@container": "@graph"}, + "verifiableCredential": {"@id": "cred:verifiableCredential", "@type": "@id", "@container": "@graph"} + } + }, + + "EcdsaSecp256k1Signature2019": { + "@id": "https://w3id.org/security#EcdsaSecp256k1Signature2019", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "EcdsaSecp256r1Signature2019": { + "@id": "https://w3id.org/security#EcdsaSecp256r1Signature2019", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "Ed25519Signature2018": { + "@id": "https://w3id.org/security#Ed25519Signature2018", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "RsaSignature2018": { + "@id": "https://w3id.org/security#RsaSignature2018", + "@context": { + "@version": 1.1, + "@protected": true, + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "proof": {"@id": "https://w3id.org/security#proof", "@type": "@id", "@container": "@graph"} + } +} diff --git a/core/json-ld-core/src/main/resources/document/summary-vc-context-v1.jsonld b/core/json-ld-core/src/main/resources/document/summary-vc-context-v1.jsonld new file mode 100644 index 000000000..de053634a --- /dev/null +++ b/core/json-ld-core/src/main/resources/document/summary-vc-context-v1.jsonld @@ -0,0 +1,26 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "summary": "https://w3id.org/2023/catenax/credentials/summary/", + "id": "@id", + "type": "@type", + "SummaryCredential": { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "@id": "summary:SummaryCredential" + }, + "holderIdentifier": { + "@id": "summary:holderIdentifier" + }, + "items": { + "@id": "summary:items", + "@type": "https://schema.org/Text" + }, + "contract-template": { + "@id": "summary:contract-template", + "@type": "https://schema.org/Text" + } + } +} \ No newline at end of file diff --git a/core/json-ld-core/src/test/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtensionTest.java b/core/json-ld-core/src/test/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtensionTest.java new file mode 100644 index 000000000..c0626b7d0 --- /dev/null +++ b/core/json-ld-core/src/test/java/org/eclipse/tractusx/edc/jsonld/JsonLdExtensionTest.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.jsonld; + +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.injection.ObjectFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.eclipse.tractusx.edc.jsonld.JsonLdExtension.CREDENTIALS_SUMMARY_V_1; +import static org.eclipse.tractusx.edc.jsonld.JsonLdExtension.CREDENTIALS_V_1; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; + +@ExtendWith(DependencyInjectionExtension.class) +public class JsonLdExtensionTest { + + JsonLdExtension extension; + + JsonLd jsonLdService = mock(JsonLd.class); + + @BeforeEach + void setup(ObjectFactory factory, ServiceExtensionContext context) { + context.registerService(JsonLd.class, jsonLdService); + extension = factory.constructInstance(JsonLdExtension.class); + } + + @Test + void initialize(ServiceExtensionContext context) { + extension.initialize(context); + jsonLdService.registerCachedDocument(eq(CREDENTIALS_V_1), any()); + jsonLdService.registerCachedDocument(eq(CREDENTIALS_SUMMARY_V_1), any()); + } +} diff --git a/docs/development/decision-records/2023-06-13_use_of_iron_library/README.md b/docs/development/decision-records/2023-06-13_use_of_iron_library/README.md new file mode 100644 index 000000000..1a51f0c18 --- /dev/null +++ b/docs/development/decision-records/2023-06-13_use_of_iron_library/README.md @@ -0,0 +1,22 @@ +# Usage of `iron-verifiable-credentials` + +## Decision + +Tractus-X EDC will use the [iron-verifiable-credentials](https://github.com/filip26/iron-verifiable-credentials) library +for all processing of VerifiableCredentials and VerifiablePresentations. + +## Rationale + +The Eclipse Dataspaces Components project uses iron's sister +library, [titanium-json-ld](https://github.com/filip26/titanium-json-ld/) for processing JSON-LD, which achieves close +to 100% of conformance with the JSON-LD specification. + +It thus stands to reason that we use `iron-verifiable-credentials`, because it supports issuing/verifying VCs/VPs, has +support for JSON-LD (internally it also uses `titanium-json-ld`) and otherwise has a very light dependency footprint. +which means high runtime type compatibility can be expected and minimal mapping/compatibility layers are needed. Crypto +suites are pluggable, so in addition to `iron-ed25519-cryptosuite-2020`, which is also provided, we will implement +support for `JsonWebKey2020` which was mandated by the Catena-X consortium. + +## Approach + +- add support for `JsonWebKey2020` to Tractus-X EDC using `iron-verifiable-credentials`. diff --git a/docs/kit/adoption-view/page_adoption-view.md b/docs/kit/adoption-view/page_adoption-view.md index b48a23789..256557e60 100644 --- a/docs/kit/adoption-view/page_adoption-view.md +++ b/docs/kit/adoption-view/page_adoption-view.md @@ -28,7 +28,7 @@ The [EDC][edc-url] as a connector implements a framework agreement for sovereign The objective is to set up a decentralized software component on the part of the respective partner, which bundles the skills required to participate in a data room and enables peer-to-peer connections between participants. The focus here is particularly on the data sovereignty of the independent companies. -The functionality required for this is bundled in the open-source project "Eclipse Dataspace Connectors", to which the Catena-X partners contribute as part of the Eclipse Foundation. +The functionality required for this is bundled in the open-source project "Eclipse Dataspace Connector", to which members of the Eclipse Foundation contribute. The main difference between the EDC and the previous connectors of the [IDSA][idsa-url] is the separation of the communication into a channel for the metadata and one for the actual data exchange. The channel for the data supports various transmission protocols via so-called data plane extensions. The metadata is transmitted directly via the EDC interface, while the actual data exchange then takes place via the appropriate channel extension. In this way, a highly scalable data exchange is made possible. diff --git a/docs/kit/operation-view/page03_local_setup_controlplane.md b/docs/kit/operation-view/page03_local_setup_controlplane.md index aef8c9fe2..5e37c0880 100644 --- a/docs/kit/operation-view/page03_local_setup_controlplane.md +++ b/docs/kit/operation-view/page03_local_setup_controlplane.md @@ -63,7 +63,7 @@ edc.hostname=localhost edc.api.auth.key=password # OAuth / DAPS related configuration -edc.oauth.token.url=https://daps.catena-x.net +edc.oauth.token.url=https://daps.example.net edc.oauth.certificate.alias=key-to-daps-certificate-in-keyvault edc.oauth.private.key.alias=key-to-private-key-in-keyvault edc.oauth.client.id=daps-oauth-client-id diff --git a/docs/migration/Version_0.0.x_0.1.x.md b/docs/migration/Version_0.0.x_0.1.x.md index 07ea746d9..ee150291a 100644 --- a/docs/migration/Version_0.0.x_0.1.x.md +++ b/docs/migration/Version_0.0.x_0.1.x.md @@ -298,7 +298,7 @@ must be renamed to `edc.dataplane.token.validation.endpoint`. ### 3.2 DataPlane Selector With this version a new feature was introduced which allows to have separate DataPlane instances for different -transfer-flows (HttpProxy, S3, etc.). The Catena-X EDC team has additionally a new extension created which allows a -simpler registration of additional dataplanes. Therefor some changes needs to be applied. Further documentation can +transfer-flows (HttpProxy, S3, etc.). The Tractus-X EDC also has a new extension which allows for a +simpler registration of additional dataplanes. Further documentation can be found in the extension folder: [dataplane-selector-configuration](../../edc-extensions/dataplane-selector-configuration/README.md) diff --git a/docs/migration/Version_0.4.x_0.5.x.md b/docs/migration/Version_0.4.x_0.5.x.md new file mode 100644 index 000000000..9b8856e22 --- /dev/null +++ b/docs/migration/Version_0.4.x_0.5.x.md @@ -0,0 +1,66 @@ +# Migration from 0.4.x to 0.5.x + +## Replacing DAPS with SSI + +DAPS was deprecated as identity provider, and was replaced with an Self-Sovereign-Identity solution based on a +centralized Managed Identity Wallet (MIW) using VerifiableCredentials. Initially, there will be one SummaryCredential, +which conflates all relevant information. This is intended as interim solution and will later be replaced with a more +appropriate structure. + +### Relevant terminology + +Please make sure to be at least somewhat familiar with the following terms before you read on: + +- VerifiableCredential +- VerifiablePresentation +- JWT - JSON Web Token +- DSP - the DataSpace Protocol + +### Preconditions + +All of these preconditions must be met before Tractus-X EDC `v0.5.x` is usable in a production use case. Please read +them carefully and make sure you understand the implications. + +- every connector instance must have a + signed [SummaryCredential](https://github.com/eclipse-tractusx/ssi-docu/tree/main/docs/credentials/summary) sitting in + the MIW. This is typically done by the Portal during participant onboarding. +- the connector must have an account with KeyCloak and be able to obtain access tokens. +- the connector must be able to reach both MIW and KeyCloak via HTTP + +### Authentication flow - quick intro + +The basic workflow for a connector runtime to authenticate an incoming request is described in this section. Please note +that this procedure is limited to connector-to-connector communication via the Dataspace Protocol (DSP), it does not +relate to other APIs such as the Management API. + +When a request is made by the Consumer, it obtains an access token from KeyCloak, which it uses to authenticate to MIW. +It then requests its SummaryCredential from MIW, which is returned in the form of a signed JWT that contains a +VerifiablePresentation (VP). That JWT is attached to the outgoing request as authorization header. +The Provider then decodes the JWT, validates its claims, and then uploads the VP to MIW for verification. Upon +successful verification, the Provider proceeds to process the request. + +Please also check +out [this flow diagram](https://github.com/eclipse-tractusx/ssi-docu/blob/main/docs/architecture/cx-3-2/flow.svg) and +the associated [documentation](https://github.com/eclipse-tractusx/ssi-docu/tree/main/docs/architecture/cx-3-2). + +### Noteworthy things and Caveats + +- the MIWs REST API is secured with a token that can be obtained from a KeyCloak instance. This KeyCloak instance must + be configured appropriately ahead of time. +- connectors have to be able to obtain a token from KeyCloak, so it must have an account with that KeyCloak instance +- we do **not** ship either MIW or KeyCloak nor do we provide support for either of them. Please contact the respective + Tractus-X projects for instructions how to set them up. +- our official Helm charts now use SSI instead of DAPS. However, the charts do **not** include a dependency onto MIW of + KeyCloak, nor do they contain configuration for them. They do, however, contain a configuration section (titled `ssi`) + that configures EDC. +- our Helm charts can be installed, and the connector application will boot up, but unless MIW and KeyCloak are + configured properly and both can be reached over network by the connector, every DSP request to another connector will + fail. However, the ManagementAPI can still be used to create Assets, Policies and ContractDefinitions. +- the centralized MIW is an interim solution, and is bound to be replaced with a decentralized/distributed architecture + in upcoming releases. + +### Fallback chart + +There is one Helm chart named `tractusx-connector-legacy` that is a carbon-copy of the old connector chart using DAPS. +It is not recommended for production use anymore and is solely intended as a fallback or as a way to gradually move to +SSI. We do not test it, nor do we provide support for it after the release of Tractus-X EDC `0.5.0`. diff --git a/docs/release-notes/Version 0.1.1.md b/docs/release-notes/Version 0.1.1.md index 5138b8b4d..7a2cf2845 100644 --- a/docs/release-notes/Version 0.1.1.md +++ b/docs/release-notes/Version 0.1.1.md @@ -29,7 +29,7 @@ The following extensions are now included in the base image of the connector. ### 2.1 CX IAM OAuth2 Extension -Using the open source OAuth Extension it is possible for a connector to re-use an IDS DAPS Token and forge the own identity (replay attack). To mitigate the security issue for the upcoming release Catena-X introduces its own OAuth2 IAM Extension. Except for the audience, the IAM configuration stays similar. +Using the open source OAuth Extension it is possible for a connector to re-use an IDS DAPS Token and forge the own identity (replay attack). To mitigate the security issue for the upcoming release Tractus-X introduces its own OAuth2 IAM Extension. Except for the audience, the IAM configuration stays similar. [Documentation](../../edc-extensions/cx-oauth2/README.md) diff --git a/docs/samples/Local TXDC Setup.md b/docs/samples/Local TXDC Setup.md deleted file mode 100644 index ad2a0f6bc..000000000 --- a/docs/samples/Local TXDC Setup.md +++ /dev/null @@ -1,124 +0,0 @@ -# Local TXDC Setup - -This document describes how to set up two TXDConnector instances locally. The Supporting Infrastructure Deployment, used -by this example, must never be used productively. The deployment of the two TXDConnector instances, done by this example, -is not suitable for productive deployment scenarios. - -## Prerequisites - -[![Helm][helm-shield]][helm-url] - -[![Kubernetes][kubernets-shield]][kubernets-url] - -## Local Deployment - -The Local TXDC Setup consists of three separate deployments. The Supporting Infrastructure, that is required to -run connectors, and two different TXDC Connector instances, that can communicate with each other. - -- [TXDC Supporting Infrastructure](../../edc-tests/src/main/resources/deployment/helm/supporting-infrastructure/README.md) -- [TXDC Connector](../../charts/tractusx-connector/README.md) Plato -- [TXDC Connector](../../charts/tractusx-connector/README.md) Sokrates - -[helm-shield]: https://img.shields.io/badge/Helm-URL-lightgrey - -[helm-url]: https://helm.sh - -[kubernets-shield]: https://img.shields.io/badge/Kubernetes-URL-lightgrey - -[kubernets-url]: https://kubernetes.io/ - -### Supporting Infrastructure - -Before the connectors can be setup, the Supporting Infrastructure must be in place. It comes with pre-configured everything -to run two connectors independently. - -For this local test scenario, -the [Supporting Infrastructure](../../edc-tests/src/main/resources/deployment/helm/supporting-infrastructure/README.md) -of the TXDC Business Tests can be used. - -Install the TXDC Supporting Infrastructure by running the following command from the project root directory. The Minio -set can be skipped, as it's only used by AWS S3 Transfer Business Tests. Also, the PostgreSQL Database is not really -mandatory to try out the EDC. So it can be disabled as well. - -```sh -helm dependency update edc-tests/src/main/resources/deployment/helm/supporting-infrastructure -``` - -```sh -helm install infrastructure edc-tests/src/main/resources/deployment/helm/supporting-infrastructure \ - --namespace cx \ - --create-namespace \ - --set install.minio=false \ - --set install.postgresql=false -``` - -### Plato Connector - -After the supporting infrastructure is deployed the Plato Connector can be added. The Supporting Infrastructure -Deployment has a DAPS Client and Vault Secrets configured accordingly. So that the TXDConnector can use them directly. - -Install Plato by running the following command from the project root directory. - -```sh -helm install plato charts/tractusx-connector \ - --namespace cx \ - --create-namespace \ - --set fullnameOverride=plato \ - --set controlplane.image.tag=0.2.0 \ - --set controlplane.service.type=NodePort \ - --set controlplane.endpoints.data.authKey=password \ - --set vault.hashicorp.enabled=true \ - --set vault.hashicorp.url=http://vault:8200 \ - --set vault.hashicorp.token=root \ - --set vault.secretNames.transferProxyTokenSignerPublicKey=plato/daps/my-plato-daps-crt \ - --set vault.secretNames.transferProxyTokenSignerPrivateKey=plato/daps/my-plato-daps-key \ - --set vault.secretNames.transferProxyTokenEncryptionAesKey=plato/data-encryption-aes-keys \ - --set vault.secretNames.dapsPrivateKey=plato/daps/my-plato-daps-key \ - --set vault.secretNames.dapsPublicKey=plato/daps/my-plato-daps-crt \ - --set daps.url=http://ids-daps:4567 \ - --set daps.clientId=99:83:A7:17:86:FF:98:93:CE:A0:DD:A1:F1:36:FA:F6:0F:75:0A:23:keyid:99:83:A7:17:86:FF:98:93:CE:A0:DD:A1:F1:36:FA:F6:0F:75:0A:23 \ - --set backendService.httpProxyTokenReceiverUrl=http://backend:8080 -``` - -The different settings are explained in the [TXDC Connector](../../charts/tractusx-connector/README.md) documentation. -Basically this deployment overrides the full name, to avoid naming conflicts, and sets a NodePort, to access the -containers from outside the local Kubernetes cluster. Then it configures a DAPS instance and the corresponding vault, -where the DAPS secrets are persisted, so that the connector has its own identity. - -### Sokrates Connector - -After Plato is set up the same can be done for Sokrates. The main difference will be, that Sokrates uses another DAPS -Client ID with different public-/private keys. - -Install Sokrates by running the following command from the project root directory. - -```shell -helm install sokrates charts/tractusx-connector \ - --namespace cx \ - --create-namespace \ - --set fullnameOverride=sokrates \ - --set controlplane.image.tag=0.2.0 \ - --set controlplane.service.type=NodePort \ - --set controlplane.endpoints.data.authKey=password \ - --set vault.hashicorp.enabled=true \ - --set vault.hashicorp.url=http://vault:8200 \ - --set vault.hashicorp.token=root \ - --set vault.secretNames.transferProxyTokenSignerPublicKey=sokrates/daps/my-sokrates-daps-crt \ - --set vault.secretNames.transferProxyTokenSignerPrivateKey=sokrates/daps/my-sokrates-daps-key \ - --set vault.secretNames.transferProxyTokenEncryptionAesKey=sokrates/data-encryption-aes-keys \ - --set vault.secretNames.dapsPrivateKey=sokrates/daps/my-sokrates-daps-key \ - --set vault.secretNames.dapsPublicKey=sokrates/daps/my-sokrates-daps-crt \ - --set daps.url=http://ids-daps:4567 \ - --set daps.clientId=E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65 \ - --set backendService.httpProxyTokenReceiverUrl=http://backend:8080 -``` - -## Uninstall - -```shell -helm uninstall --namespace cx infrastructure -helm uninstall --namespace cx plato -helm uninstall --namespace cx sokrates -``` - -> To try out the local setup, have a look at the [Transfer Example Documentation](Transfer%20Data.md) diff --git a/docs/samples/README.md b/docs/samples/README.md index fcd5fe8bd..f14e5863a 100644 --- a/docs/samples/README.md +++ b/docs/samples/README.md @@ -2,6 +2,6 @@ In this folder are listed some documents that will help you setting up a connector execute some use cases. -- [Local setup](./Local%20TXDC%20Setup.md) +- [Local setup](./example-dataspace/README.md) - [Transfer data](./Transfer%20Data.md) - [Data Plane HTTP OAuth2](./data-plane-http-oauth2.md) diff --git a/docs/samples/example-dataspace/README.md b/docs/samples/example-dataspace/README.md index 9842186cd..11038e86b 100644 --- a/docs/samples/example-dataspace/README.md +++ b/docs/samples/example-dataspace/README.md @@ -8,6 +8,12 @@ Vault, PostgreSQL) and a DAPS instance that both share. We've tested this setup with [KinD](https://kind.sigs.k8s.io/), but other runtimes such as [Minikube](https://minikube.sigs.k8s.io/docs/start/) may work as well, we just haven't tested them. +This version of Tractus-X EDC _requires_ a running instance of the Managed Identity Wallet and KeyCloak, a connector +will not be able to communicate to another connector without it. + +Installation instructions for those are beyond the scope of this document, please refer to the respective manuals and +guides for information on how to set them up. + Furthermore, this guide assumes: - the Tractus-X EDC repository is checked out, the working directory for this guide is `docs/samples/example-dataspace` @@ -16,39 +22,40 @@ Furthermore, this guide assumes: - the following tools are available: `yq`, `openssl`, `base64` - a POSIX-compliant shell, e.g. `bash` or `zsh` unless stated otherwise -### 1.1 Create certificates for both runtimes +### 1.1 Create secrets for both runtimes We'll need a x509 certificate in order to communicate with DAPS, as well as a private key and a Data Encryption signing key. ```shell -# SOKRATES key/cert for daps -openssl req -newkey rsa:2048 -new -nodes -x509 -days 1 -keyout sokrates.key -out sokrates.cert -subj "/CN=test" +# SOKRATES aes encryption key echo "aes_enckey_test" | base64 > sokrates.aes.key -# PLATO key/cert for daps -openssl req -newkey rsa:2048 -new -nodes -x509 -days 1 -keyout plato.key -out plato.cert -subj "/CN=test" +# PLATO aes encryption key echo "aes_enckey_test" | base64 > plato.aes.key ``` Any arbitrary string can be used for the AES key, but it has to be 16, 24, or 32 characters in length, assuming UTF-8 encoding. -### 1.2 Modify the DAPS's `values.yaml` located at `daps/values.yaml` +### 1.2 Obtain configuration for MiW and KeyCloak -With the following command, we "inject" the previously created certificates and client ids into the DAPS's config: +> The following information is _required_, your connectors will **not** work properly unless you +> modify the `ssi:` section of `sokrates-values.yaml` and `plato-values.yaml` accordingly! -```shell -VALUES_FILE=daps/values.yaml +For communication with KeyCloak we need the following information -# Add both public keys to daps -yq -i ".connectors[0].certificate=\"$(cat sokrates.cert)\"" "$VALUES_FILE" -yq -i ".connectors[1].certificate=\"$(cat plato.cert)\"" "$VALUES_FILE" -``` +- the `tokenurl`: URL where access tokens can be obtained +- the `client.id`: KeyCloak identifier of the connector + +Note that the OAuth2 client secret will be stored in the vault under the alias `client-secret`. -### 1.3 Install/Launch DAPS +In order to use MiW as credential backend we need the following information: -`helm install daps daps/` +- `url`: a URL where MiW is reachable +- `authorityId`: this is the `issuerIdentifier` for MiW REST requests, please refer to the respective documentation. + +Furthermore, we need the `endpoint.audience`, which is used to verify the `aud` claim of incoming requests. This does **not** have to be set explicitly, it defaults to each connector's callback address. ## 2. Prepare Connectors @@ -57,18 +64,20 @@ a `postStart` element to the chart's configuration file: ```shell # for sokrates -CONFIG_FILE=sokrates-values.yaml - -yq -i ".vault.server.postStart |= [\"sh\",\"-c\",\"{\nsleep 5\n\ncat << EOF | /bin/vault kv put secret/daps-crt content=-\n$(cat sokrates.cert)\nEOF\n\n -cat << EOF | /bin/vault kv put secret/daps-key content=-\n$(cat sokrates.key)\nEOF\n\n -/bin/vault kv put secret/aes-keys content=$(cat sokrates.aes.key)\n\n}\"]" "$CONFIG_FILE" +VALUES_FILE=sokrates-values.yaml +CLIENT_SECRET= +AES_KEY=$(cat sokrates.aes.key) +yq -i ".vault.server.postStart |= [\"sh\",\"-c\",\"{\nsleep 5\n +/bin/vault kv put secret/client-secret content=$CLIENT_SECRET\n +/bin/vault kv put secret/aes-keys content=$AES_KEY\n}\"]" "$VALUES_FILE" # for plato -CONFIG_FILE=plato-values.yaml - -yq -i ".vault.server.postStart |= [\"sh\",\"-c\",\"{\nsleep 5\n\ncat << EOF | /bin/vault kv put secret/daps-crt content=-\n$(cat plato.cert)\nEOF\n\n -cat << EOF | /bin/vault kv put secret/daps-key content=-\n$(cat plato.key)\nEOF\n\n -/bin/vault kv put secret/aes-keys content=$(cat plato.aes.key)\n\n}\"]" "$CONFIG_FILE" +VALUES_FILE=plato-values.yaml +CLIENT_SECRET= +AES_KEY=$(cat plato.aes.key) +yq -i ".vault.server.postStart |= [\"sh\",\"-c\",\"{\nsleep 5\n +/bin/vault kv put secret/client-secret content=$CLIENT_SECRET\n +/bin/vault kv put secret/aes-keys content=$AES_KEY\n}\"]" "$VALUES_FILE" ``` ## 3 Install the connectors @@ -108,12 +117,12 @@ There is several ways of making sure everything worked out well: ```shell stern tx-sokrates ``` - + then look out for something similar to: ```shell tx-sokrates-controlplane-b9456f97b-s5jts tractusx-connector INFO 2023-05-31T07:24:53.020975888 tx-sokrates-controlplane ready ``` - + - wait for the Kubernetes rollout to be successful, e.g. `kubectl rollout status deployment tx-plato-controlplane` - use `helm test` to execute tests: `helm test tx-plato` diff --git a/docs/samples/example-dataspace/daps/.helmignore b/docs/samples/example-dataspace/daps/.helmignore deleted file mode 100644 index 0e8a0eb36..000000000 --- a/docs/samples/example-dataspace/daps/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/docs/samples/example-dataspace/daps/templates/_helpers.tpl b/docs/samples/example-dataspace/daps/templates/_helpers.tpl deleted file mode 100644 index 95b115eee..000000000 --- a/docs/samples/example-dataspace/daps/templates/_helpers.tpl +++ /dev/null @@ -1,62 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "omejdn.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "omejdn.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "omejdn.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "omejdn.labels" -}} -helm.sh/chart: {{ include "omejdn.chart" . }} -{{ include "omejdn.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "omejdn.selectorLabels" -}} -app.kubernetes.io/name: {{ include "omejdn.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "omejdn.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "omejdn.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/docs/samples/example-dataspace/daps/templates/configmap.yaml b/docs/samples/example-dataspace/daps/templates/configmap.yaml deleted file mode 100644 index 5ad21648d..000000000 --- a/docs/samples/example-dataspace/daps/templates/configmap.yaml +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -data: - scope_mapping.yml: |- - --- - idsc:IDS_CONNECTOR_ATTRIBUTES_ALL: - - referringConnector - - omejdn.yml: |- - --- - host: http://daps:4567/ - path_prefix: '' - bind_to: 0.0.0.0 - allow_origin: "*" - app_env: debug - openid: false - user_backend: - - yaml - user_backend_default: yaml - accept_audience: idsc:IDS_CONNECTORS_ALL - issuer: http://daps:4567/ - environment: development - default_audience: - - idsc:IDS_CONNECTORS_ALL - access_token: - expiration: 3600 - algorithm: RS256 - id_token: - expiration: 3600 - algorithm: RS256 - - plugins.yml: |- - --- - plugins: - token_user_attributes: - - clients.yml: |- - --- - - client_id: data-plane-oauth2 - client_secret: supersecret - name: provision oauth2 - grant_types: - - client_credentials - token_endpoint_auth_method: client_secret_post - scope: openid -{{- range $i, $val := .Values.connectors }} - - client_id: {{ quote $val.id }} - name: {{ quote $val.name }} - token_endpoint_auth_method: private_key_jwt - grant_types: - - client_credentials - scope: - - idsc:IDS_CONNECTOR_ATTRIBUTES_ALL - attributes: - - key: idsc - value: IDS_CONNECTOR_ATTRIBUTES_ALL - - key: securityProfile - value: idsc:BASE_SECURITY_PROFILE - {{- range $key, $value := $val.attributes }} - - key: {{ $key }} - value: {{ $value }} - {{- end }} - redirect_uri: http://localhost:4200 -{{ end -}} - - -{{- range $i, $val := .Values.connectors }} - {{ $val.name }}: {{ quote $val.certificate | toString }} -{{ end -}} diff --git a/docs/samples/example-dataspace/daps/templates/deployment.yaml b/docs/samples/example-dataspace/daps/templates/deployment.yaml deleted file mode 100644 index 58bfff105..000000000 --- a/docs/samples/example-dataspace/daps/templates/deployment.yaml +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "omejdn.selectorLabels" . | nindent 6 }} - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "omejdn.selectorLabels" . | nindent 8 }} - spec: - {{- if .Values.imagePullSecret.dockerconfigjson }} - imagePullSecrets: - - name: {{ include "omejdn.fullname" . }}-imagepullsecret - {{- else }} - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- end }} - serviceAccountName: {{ include "omejdn.serviceAccountName" . }} - automountServiceAccountToken: {{ .Values.automountServiceAccountToken }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - initContainers: - - name: init-daps-pvc - image: alpine - command: - - "sh" - - "-c" - args: - - | - cp /opt/config/omejdn.yml /etc/daps/omejdn.yml - cp /opt/config/clients.yml /etc/daps/clients.yml - cp /opt/config/plugins.yml /etc/daps/plugins.yml - cp /opt/config/scope_mapping.yml /etc/daps/scope_mapping.yml - apk add --update openssl - openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout /etc/keys/omejdn/omejdn.key \ - -subj "/C=DE/ST=Berlin/L=Berlin/O=Tractus-X-EDC-Test, Inc./OU=DE" - volumeMounts: - - mountPath: /etc/daps - name: config-dir - - mountPath: /etc/keys/omejdn - name: omejdn-key-dir - - mountPath: /opt/config/omejdn.yml - name: omejdn-config - subPath: omejdn.yml - - mountPath: /opt/config/scope_mapping.yml - name: scope-mapping - subPath: scope_mapping.yml - - mountPath: /opt/config/clients.yml - name: clients-config - subPath: clients.yml - - mountPath: /opt/config/plugins.yml - name: plugins-config - subPath: plugins.yml - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - volumeMounts: - - mountPath: /opt/config/ - name: config-dir - - mountPath: /opt/keys/omejdn/omejdn.key - name: omejdn-key-dir - subPath: omejdn.key - - mountPath: /opt/keys/clients/ - name: client-certificates - ports: - - name: http - containerPort: 4567 - protocol: TCP - livenessProbe: - httpGet: - path: /jwks.json - port: http - readinessProbe: - httpGet: - path: /jwks.json - port: http - resources: - {{- toYaml .Values.resources | nindent 12 }} - env: - - name: OMEJDN_JWT_AUD_OVERRIDE - value: "idsc:IDS_CONNECTORS_ALL" - - name: OMEJDN_PLUGINS - value: "config/plugins.yml" - volumes: - - name: config-dir - emptyDir: { } - - name: omejdn-key-dir - emptyDir: { } - - name: omejdn-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: omejdn.yml - path: omejdn.yml - - name: scope-mapping - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: scope_mapping.yml - path: scope_mapping.yml - - name: clients-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: clients.yml - path: clients.yml - - name: plugins-config - configMap: - name: {{ include "omejdn.fullname" . }} - items: - - key: plugins.yml - path: plugins.yml - - name: client-certificates - configMap: - name: {{ include "omejdn.fullname" . }} - items: - {{- range $i, $val := .Values.connectors }} - - key: {{ $val.name }} - path: {{ $val.id }}.cert - {{- end }} diff --git a/docs/samples/example-dataspace/daps/templates/hpa.yaml b/docs/samples/example-dataspace/daps/templates/hpa.yaml deleted file mode 100644 index f1f072f6c..000000000 --- a/docs/samples/example-dataspace/daps/templates/hpa.yaml +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation - # - # See the NOTICE file(s) distributed with this work for additional - # information regarding copyright ownership. - # - # 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 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - # License for the specific language governing permissions and limitations - # under the License. - # - # SPDX-License-Identifier: Apache-2.0 - # - -{{- if .Values.autoscaling.enabled }} ---- -apiVersion: autoscaling/v2beta1 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "omejdn.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/docs/samples/example-dataspace/daps/templates/imagepullsecret.yaml b/docs/samples/example-dataspace/daps/templates/imagepullsecret.yaml deleted file mode 100644 index 44f573e0f..000000000 --- a/docs/samples/example-dataspace/daps/templates/imagepullsecret.yaml +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation - # - # See the NOTICE file(s) distributed with this work for additional - # information regarding copyright ownership. - # - # 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 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - # License for the specific language governing permissions and limitations - # under the License. - # - # SPDX-License-Identifier: Apache-2.0 - # - -{{- if .Values.imagePullSecret.dockerconfigjson }} ---- -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "edc-dataplane.fullname" . }}-imagepullsecret - namespace: {{ .Release.Namespace | default "default" | quote }} - labels: - {{- include "edc-dataplane.labels" . | nindent 4 }} -data: - .dockerconfigjson: {{ .Values.imagePullSecret.dockerconfigjson }} -type: kubernetes.io/dockerconfigjson -{{- end }} diff --git a/docs/samples/example-dataspace/daps/templates/service.yaml b/docs/samples/example-dataspace/daps/templates/service.yaml deleted file mode 100644 index 947e69742..000000000 --- a/docs/samples/example-dataspace/daps/templates/service.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "omejdn.fullname" . }} - labels: - {{- include "omejdn.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "omejdn.selectorLabels" . | nindent 4 }} diff --git a/docs/samples/example-dataspace/daps/values.yaml b/docs/samples/example-dataspace/daps/values.yaml deleted file mode 100644 index 3553dcc86..000000000 --- a/docs/samples/example-dataspace/daps/values.yaml +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright (c) 2023 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# 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 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. -# -# SPDX-License-Identifier: Apache-2.0 -# - ---- -# Default values for omejdn. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -# -- Specifies how many replicas of a deployed pod shall be created during the deployment -# Note: If horizontal pod autoscaling is enabled this setting has no effect -replicaCount: 1 -image: - # -- Which omjedn container image to use - repository: ghcr.io/fraunhofer-aisec/omejdn-server - # -- [Kubernetes image pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) to use - pullPolicy: IfNotPresent - # -- Overrides the image tag whose default is the chart appVersion - tag: "1.7.1" -imagePullSecret: - # -- Image pull secret to create to [obtain the container image from private registries](https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry) - # Note: This value needs to adhere to the [(base64 encoded) .dockerconfigjson format](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/#registry-secret-existing-credentials). - # Furthermore, if 'imagePullSecret.dockerconfigjson' is defined, it takes precedence over 'imagePullSecrets'. - dockerconfigjson: "" -# -- Overrides the charts name -nameOverride: "" -# -- Overrides the releases full name -serviceAccount: - # -- Specifies whether a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) should be created per release - create: true - # -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) to add to the service account - annotations: { } - # -- The name of the service account to use. If not set and create is true, a name is generated using the release's fullname template - name: "" -# -- Whether to [automount kubernetes API credentials](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server) into the pod -automountServiceAccountToken: false -# -- [Annotations](https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/) added to deployed [pods](https://kubernetes.io/docs/concepts/workloads/pods/) -podAnnotations: { } -# The [pod security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod) defines privilege and access control settings for a Pod within the deployment -podSecurityContext: { } -# The [container security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container) defines privilege and access control settings for a Container within a pod -securityContext: { } -service: - # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types) to expose the running application on a set of Pods as a network service. - type: ClusterIP - # -- [Service type](https://kubernetes.io/docs/concepts/services-networking/service/#defining-a-service) to expose the running application on a set of Pods as a network service. - port: 4567 -# -- [Resource management](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) applied to the deployed pod -resources: { } -autoscaling: - # -- Enables [horizontal pod autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) - enabled: false - # -- Minimal replicas if resource consumption falls below resource threshholds - minReplicas: 1 - # -- Maximum replicas if resource consumption exceeds resource threshholds - maxReplicas: 100 - # -- targetAverageUtilization of cpu provided to a pod - targetCPUUtilizationPercentage: 80 - # -- targetAverageUtilization of memory provided to a pod - targetMemoryUtilizationPercentage: 80 -# -- [Node-Selector](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#nodeselector) to constrain the Pod to nodes with specific labels. -nodeSelector: { } -# -- [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) are applied to Pods to schedule onto nodes with matching taints. -tolerations: [ ] -# -- [Affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) constrains which nodes the Pod can be scheduled on based on node labels. -affinity: { } -# List of connector clients. Certificate and Client-ID must be configured in parallel. -fullnameOverride: "daps" -url: "" -clientId: "" -paths: - jwks: /jwks.json - token: /token -connectors: - - id: E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65 - name: sokrates - attributes: - referringConnector: http://sokrates-controlplane/BPNSOKRATES - - id: E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:69 - name: plato - attributes: - referringConnector: http://plato-controlplane/BPNPLATO diff --git a/docs/samples/example-dataspace/plato-values.yaml b/docs/samples/example-dataspace/plato-values.yaml index 21c5675d7..92bc09ce9 100644 --- a/docs/samples/example-dataspace/plato-values.yaml +++ b/docs/samples/example-dataspace/plato-values.yaml @@ -39,6 +39,16 @@ controlplane: securityContext: # avoids some errors in the log: cannot write temp files of large multipart requests when R/O readOnlyRootFilesystem: false + # SSI configuration + ssi: + miw: + url: "" + authorityId: "" + oauth: + tokenurl: "" + client: + id: "" + secretAlias: "client-secret" dataplane: image: pullPolicy: Never @@ -62,17 +72,8 @@ vault: url: http://plato-vault:8200 token: root secretNames: - transferProxyTokenSignerPublicKey: daps-crt - transferProxyTokenSignerPrivateKey: daps-key transferProxyTokenEncryptionAesKey: aes-keys - dapsPrivateKey: daps-key - dapsPublicKey: daps-crt - # this must be set through CLI args: --set vault.secrets=$YOUR_VAULT_SECRETS where YOUR_VAULT_SECRETS should - # be a string in the format "key1:secret1;key2:secret2;..." secrets: server: -daps: - url: "http://daps:4567" - clientId: "E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:69" backendService: httpProxyTokenReceiverUrl: "http://backend:8080" diff --git a/docs/samples/example-dataspace/sokrates-values.yaml b/docs/samples/example-dataspace/sokrates-values.yaml index 086eefde5..e05bf87a5 100644 --- a/docs/samples/example-dataspace/sokrates-values.yaml +++ b/docs/samples/example-dataspace/sokrates-values.yaml @@ -38,6 +38,16 @@ controlplane: securityContext: # avoids some errors in the log: cannot write temp files of large multipart requests when R/O readOnlyRootFilesystem: false + # SSI configuration + ssi: + miw: + url: "" + authorityId: "" + oauth: + tokenurl: "" + client: + id: "" + secretAlias: "client-secret" dataplane: image: pullPolicy: Never @@ -61,17 +71,8 @@ vault: url: http://sokrates-vault:8200 token: root secretNames: - transferProxyTokenSignerPublicKey: daps-crt - transferProxyTokenSignerPrivateKey: daps-key transferProxyTokenEncryptionAesKey: aes-keys - dapsPrivateKey: daps-key - dapsPublicKey: daps-crt - # this must be set through CLI args: --set vault.secrets=$YOUR_VAULT_SECRETS where YOUR_VAULT_SECRETS should - # be a string in the format "key1:secret1;key2:secret2;..." secrets: server: -daps: - url: "http://daps:4567" - clientId: "E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65" backendService: httpProxyTokenReceiverUrl: "http://backend:8080" diff --git a/edc-controlplane/edc-controlplane-base/build.gradle.kts b/edc-controlplane/edc-controlplane-base/build.gradle.kts index cc39bf725..2cb3f57a3 100644 --- a/edc-controlplane/edc-controlplane-base/build.gradle.kts +++ b/edc-controlplane/edc-controlplane-base/build.gradle.kts @@ -27,17 +27,23 @@ dependencies { runtimeOnly(project(":edc-extensions:business-partner-validation")) runtimeOnly(project(":edc-extensions:dataplane-selector-configuration")) runtimeOnly(project(":edc-extensions:data-encryption")) - runtimeOnly(project(":edc-extensions:cx-oauth2")) + runtimeOnly(project(":edc-extensions:provision-additional-headers")) runtimeOnly(project(":edc-extensions:observability-api-customization")) runtimeOnly(project(":edc-extensions:control-plane-adapter-api")) runtimeOnly(project(":edc-extensions:control-plane-adapter-callback")) + // needed for SSI integration + runtimeOnly(project(":core:json-ld-core")) + runtimeOnly(project(":edc-extensions:ssi:ssi-identity-core")) + runtimeOnly(project(":edc-extensions:ssi:ssi-miw-credential-client")) + runtimeOnly(project(":edc-extensions:ssi:ssi-identity-extractor")) + runtimeOnly(project(":edc-extensions:cx-policy")) + runtimeOnly(libs.edc.core.controlplane) runtimeOnly(libs.edc.config.filesystem) runtimeOnly(libs.edc.auth.tokenbased) - runtimeOnly(libs.edc.auth.oauth2.core) - runtimeOnly(libs.edc.auth.oauth2.daps) + runtimeOnly(libs.edc.api.management) runtimeOnly(libs.edc.dsp) runtimeOnly(libs.edc.spi.jwt) diff --git a/edc-controlplane/edc-controlplane-postgresql-azure-vault/README.md b/edc-controlplane/edc-controlplane-postgresql-azure-vault/README.md index 94792735e..44a4a13b2 100644 --- a/edc-controlplane/edc-controlplane-postgresql-azure-vault/README.md +++ b/edc-controlplane/edc-controlplane-postgresql-azure-vault/README.md @@ -35,7 +35,7 @@ Details regarding each configuration property can be found at the [documentary s | edc.ids.catalog.id | | urn:catalog:default | | | ids.webhook.address | | | | | edc.hostname | | localhost | | -| edc.oauth.token.url | X | | | +| edc.oauth.token.url | X | | | | edc.oauth.public.key.alias | X | key-to-daps-certificate-in-keyvault | | | edc.oauth.private.key.alias | X | key-to-private-key-in-keyvault | | | edc.oauth.client.id | X | daps-oauth-client-id | | @@ -103,7 +103,7 @@ edc.hostname=localhost edc.api.auth.key=password # OAuth / DAPS related configuration -edc.oauth.token.url=https://daps.catena-x.net +edc.oauth.token.url=https://daps.example.net edc.oauth.public.key.alias=key-to-daps-certificate-in-keyvault edc.oauth.private.key.alias=key-to-private-key-in-keyvault edc.oauth.client.id=daps-oauth-client-id diff --git a/edc-controlplane/edc-controlplane-postgresql-azure-vault/src/main/docker/Dockerfile b/edc-controlplane/edc-controlplane-postgresql-azure-vault/src/main/docker/Dockerfile index b4faaf422..9d7fb7801 100644 --- a/edc-controlplane/edc-controlplane-postgresql-azure-vault/src/main/docker/Dockerfile +++ b/edc-controlplane/edc-controlplane-postgresql-azure-vault/src/main/docker/Dockerfile @@ -18,7 +18,7 @@ # # SPDX-License-Identifier: Apache-2.0 # -FROM alpine:3.18.0 AS otel +FROM alpine:3.18.2 AS otel ENV OTEL_AGENT_LOCATION "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.12.1/opentelemetry-javaagent.jar" diff --git a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/README.md b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/README.md new file mode 100644 index 000000000..4d73773fb --- /dev/null +++ b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/README.md @@ -0,0 +1,178 @@ +# EDC Control-Plane backed by [Postgresql](https://www.postgresql.org/) and [HashiCorp vault](https://www.vaultproject.io/docs) + +## Building + +```shell +./gardlew :edc-controlplane:edc-controlplane-postgresql-hashicorp-vault:dockerize +``` + +## Configuration + +Listed below are configuration keys needed to get the `edc-controlplane-postgresql-hashicorp-vault` up and running. +Details regarding each configuration property can be found at the [documentary section of the EDC](https://github.com/eclipse-edc/Connector/tree/main/docs). + +| Key | Required | Example | Description | +|--------------------------------------------------|----------|------------------------------------------------------------------------------|----------------------------| +| edc.api.auth.key | | password | default value: random UUID | +| web.http.default.port | X | 8080 | | +| web.http.default.path | X | /api | | +| web.http.data.port | X | 8181 | | +| web.http.data.path | X | /data | | +| web.http.validation.port | X | 8182 | | +| web.http.validation.path | X | /validation | | +| web.http.control.port | X | 9999 | | +| web.http.control.path | X | /api/controlplane/control | | +| web.http.ids.port | X | 8282 | | +| web.http.ids.path | X | /api/v1/ids | | +| edc.receiver.http.endpoint | X | | | +| edc.ids.title | | Eclipse Dataspace Connector | | +| edc.ids.description | | Eclipse Dataspace Connector | | +| edc.ids.id | | urn:connector:edc | | +| edc.ids.security.profile | | base | | +| edc.ids.endpoint | | | | +| edc.ids.maintainer | | | | +| edc.ids.curator | | | | +| edc.ids.catalog.id | | urn:catalog:default | | +| ids.webhook.address | | | | +| edc.hostname | | localhost | | +| edc.oauth.token.url | X | | | +| edc.oauth.public.key.alias | X | key-to-daps-certificate-in-keyvault | | +| edc.oauth.private.key.alias | X | key-to-private-key-in-keyvault | | +| edc.oauth.client.id | X | daps-oauth-client-id | | +| edc.vault.hashicorp.url | X | | | +| edc.vault.hashicorp.token | X | 55555555-6666-7777-8888-999999999999 | | +| edc.vault.hashicorp.timeout.seconds | | 30 | | +| edc.datasource.asset.name | X | asset | | +| edc.datasource.asset.url | X | jdbc:postgresql://postgres.svc.cluster.local:5432/edc_asset_db | | +| edc.datasource.asset.user | X | username | | +| edc.datasource.asset.password | X | password | | +| edc.datasource.contractdefinition.name | X | contractdefinition | | +| edc.datasource.contractdefinition.url | X | jdbc:postgresql://postgres.svc.cluster.local:5432/edc_contractdefinition_db | | +| edc.datasource.contractdefinition.user | X | username | | +| edc.datasource.contractdefinition.password | X | password | | +| edc.datasource.contractnegotiation.name | X | contractnegotiation | | +| edc.datasource.contractnegotiation.url | X | jdbc:postgresql://postgres.svc.cluster.local:5432/edc_contractnegotiation_db | | +| edc.datasource.contractnegotiation.user | X | username | | +| edc.datasource.contractnegotiation.password | X | password | | +| edc.datasource.policy.name | X | policy | | +| edc.datasource.policy.url | X | jdbc:postgresql://postgres.svc.cluster.local:5432/edc_policy_db | | +| edc.datasource.policy.user | X | username | | +| edc.datasource.policy.password | X | password | | +| edc.datasource.transferprocess.name | X | transferprocess | | +| edc.datasource.transferprocess.url | X | jdbc:postgresql://postgres.svc.cluster.local:5432/edc_transferprocess_db | | +| edc.datasource.transferprocess.user | X | username | | +| edc.datasource.transferprocess.password | X | password | | +| edc.transfer.proxy.endpoint | X | | | +| edc.transfer.proxy.token.signer.privatekey.alias | X | | | + +### Example configuration.properties + +JDK properties-style configuration of the EDC Control-Plane is expected to be mounted to `/app/configuration.properties` within the container. + +```shell +# Create configuration.properties +export CONFIGURATION_PROPERTIES_FILE=$(mktemp /tmp/configuration.properties.XXXXXX) +cat << 'EOF' > ${CONFIGURATION_PROPERTIES_FILE} + +web.http.default.port=8080 +web.http.default.path=/api +web.http.data.port=8181 +web.http.data.path=/data +web.http.validation.port=8182 +web.http.validation.path=/validation +web.http.control.port=9999 +web.http.control.path=/api/controlplane/control +web.http.ids.port=8282 +web.http.ids.path=/api/v1/ids + +edc.receiver.http.endpoint=http://backend-service + +edc.ids.title=Eclipse Dataspace Connector +edc.ids.description=Eclipse Dataspace Connector +edc.ids.id=urn:connector:edc +edc.ids.security.profile=base +edc.ids.endpoint=http://localhost:8282/api/v1/ids +edc.ids.maintainer=http://localhost +edc.ids.curator=http://localhost +edc.ids.catalog.id=urn:catalog:default +ids.webhook.address=http://localhost:8282/api/v1/ids + +edc.hostname=localhost + +edc.api.auth.key=password + +# OAuth / DAPS related configuration +edc.oauth.token.url=https://daps.example.net +edc.oauth.public.key.alias=key-to-daps-certificate-in-keyvault +edc.oauth.private.key.alias=key-to-private-key-in-keyvault +edc.oauth.client.id=daps-oauth-client-id + +# HashiCorp vault related configuration +edc.vault.hashicorp.url=http://vault +edc.vault.hashicorp.token=55555555-6666-7777-8888-999999999999 +edc.vault.hashicorp.timeout.seconds=30 + +# Control- / Data- Plane configuration +edc.transfer.proxy.endpoint=http://dataplane-public-endpoint/public +edc.transfer.proxy.token.signer.privatekey.alias=token-signer-private-key + +# Postgresql related configuration +edc.datasource.asset.name=asset +edc.datasource.asset.url=jdbc:postgresql://postgres.svc.cluster.local:5432/edc_asset +edc.datasource.asset.user=user +edc.datasource.asset.password=pass +edc.datasource.contractdefinition.name=contractdefinition +edc.datasource.contractdefinition.url=jdbc:postgresql://postgres.svc.cluster.local:5432/edc_contractdefinition +edc.datasource.contractdefinition.user=user +edc.datasource.contractdefinition.password=pass +edc.datasource.contractnegotiation.name=contractnegotiation +edc.datasource.contractnegotiation.url=jdbc:postgresql://postgres.svc.cluster.local:5432/edc_contractnegotiation +edc.datasource.contractnegotiation.user=user +edc.datasource.contractnegotiation.password=pass +edc.datasource.policy.name=policy +edc.datasource.policy.url=jdbc:postgresql://postgres.svc.cluster.local:5432/edc_policy +edc.datasource.policy.user=user +edc.datasource.policy.password=pass +edc.datasource.transferprocess.name=transferprocess +edc.datasource.transferprocess.url=jdbc:postgresql://postgres.svc.cluster.local:5432/edc_transferprocess +edc.datasource.transferprocess.user=user +edc.datasource.transferprocess.password=pass +EOF +``` + +### Example logging.properties + +```shell +# Create logging.properties +export LOGGING_PROPERTIES_FILE=$(mktemp /tmp/logging.properties.XXXXXX) +cat << 'EOF' > ${LOGGING_PROPERTIES_FILE} +.level=INFO +org.eclipse.edc.level=ALL +handlers=java.util.logging.ConsoleHandler +java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter +java.util.logging.ConsoleHandler.level=ALL +java.util.logging.SimpleFormatter.format=[%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS] [%4$-7s] %5$s%6$s%n +EOF +``` + +### Example opentelemetry.properties + +```shell +# Create opentelemetry.properties +export OPENTELEMETRY_PROPERTIES_FILE=$(mktemp /tmp/opentelemetry.properties.XXXXXX) +cat << 'EOF' > ${OPENTELEMETRY_PROPERTIES_FILE} +otel.javaagent.enabled=false +otel.javaagent.debug=false +EOF +``` + +## Running + +```shell +docker run \ + -p 8080:8080 -p 8181:8181 -p 8182:8182 -p 8282:8282 -p 9090:9090 -p 9999:9999 \ + -v ${CONFIGURATION_PROPERTIES_FILE:-/dev/null}:/app/configuration.properties \ + -v ${LOGGING_PROPERTIES_FILE:-/dev/null}:/app/logging.properties \ + -v ${OPENTELEMETRY_PROPERTIES_FILE:-/dev/null}:/app/opentelemetry.properties \ + -i edc-controlplane-postgresql-hashicorp-vault:latest +``` diff --git a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/build.gradle.kts b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/build.gradle.kts new file mode 100644 index 000000000..a613fb262 --- /dev/null +++ b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/build.gradle.kts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022 Mercedes-Benz Tech Innovation GmbH + * Copyright (c) 2021,2022 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * 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 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar + +plugins { + `java-library` + id("application") + id("com.github.johnrengelman.shadow") version "8.1.1" +} + +dependencies { + runtimeOnly(project(":core:edr-cache-core")) + runtimeOnly(project(":edc-extensions:business-partner-validation")) + runtimeOnly(project(":edc-extensions:dataplane-selector-configuration")) + runtimeOnly(project(":edc-extensions:data-encryption")) + runtimeOnly(project(":edc-extensions:cx-oauth2")) + runtimeOnly(project(":edc-extensions:provision-additional-headers")) + runtimeOnly(project(":edc-extensions:observability-api-customization")) + runtimeOnly(project(":edc-extensions:control-plane-adapter-api")) + runtimeOnly(project(":edc-extensions:control-plane-adapter-callback")) + + runtimeOnly(libs.edc.core.controlplane) + runtimeOnly(libs.edc.config.filesystem) + runtimeOnly(libs.edc.auth.tokenbased) + runtimeOnly(libs.edc.auth.oauth2.core) + runtimeOnly(libs.edc.auth.oauth2.daps) + runtimeOnly(libs.edc.api.management) + runtimeOnly(libs.edc.dsp) + runtimeOnly(libs.edc.spi.jwt) + runtimeOnly(libs.bundles.edc.dpf) + + runtimeOnly(libs.edc.ext.http) + runtimeOnly(libs.bundles.edc.monitoring) + runtimeOnly(libs.edc.transfer.dynamicreceiver) + runtimeOnly(libs.edc.controlplane.callback.dispatcher.event) + runtimeOnly(libs.edc.controlplane.callback.dispatcher.http) + + runtimeOnly(project(":edc-extensions:postgresql-migration")) + runtimeOnly(project(":edc-extensions:hashicorp-vault")) + runtimeOnly(project(":edc-extensions:edr-cache-sql")) + runtimeOnly(libs.bundles.edc.sqlstores) + runtimeOnly(libs.edc.transaction.local) + runtimeOnly(libs.edc.sql.pool) + runtimeOnly(libs.edc.core.controlplane) + runtimeOnly(libs.edc.dpf.transfer) + runtimeOnly(libs.postgres) + + // needed for DAPS - not officially supported anymore + runtimeOnly(project(":edc-extensions:cx-oauth2")) + runtimeOnly(libs.edc.auth.oauth2.core) + runtimeOnly(libs.edc.auth.oauth2.daps) +} + + +tasks.withType { + exclude("**/pom.properties", "**/pom.xm") + mergeServiceFiles() + archiveFileName.set("${project.name}.jar") +} + + +application { + mainClass.set("org.eclipse.edc.boot.system.runtime.BaseRuntime") +} diff --git a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/notice.md b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/notice.md new file mode 100644 index 000000000..381253ec9 --- /dev/null +++ b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/notice.md @@ -0,0 +1,28 @@ +# Notice for Docker image + +An EDC Control Plane using PostgreSQL as persistence backend, and HashiCorp Vault as secret store. + +DockerHub: https://hub.docker.com/r/tractusx/edc-controlplane-postgresql-hashicorp-vault + +Eclipse Tractus-X product(s) installed within the image: + +## Tractus-X EDC Control Plane + +- GitHub: https://github.com/eclipse-tractusx/tractusx-edc +- Project home: https://projects.eclipse.org/projects/automotive.tractusx +- Dockerfile: https://github.com/eclipse-tractusx/tractusx-edc/blob/main/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/src/main/docker/Dockerfile +- Project license: [Apache License, Version 2.0](https://github.com/eclipse-tractusx/tractusx-edc/blob/main/LICENSE) + +## Used base image + +- [eclipse-temurin:17.0.6_10-jre-alpine](https://github.com/adoptium/containers) +- Official Eclipse Temurin DockerHub page: https://hub.docker.com/_/eclipse-temurin +- Eclipse Temurin Project: https://projects.eclipse.org/projects/adoptium.temurin +- Additional information about the Eclipse Temurin + images: https://github.com/docker-library/repo-info/tree/master/repos/eclipse-temurin + +As with all Docker images, these likely also contain other software which may be under other licenses (such as Bash, etc +from the base distribution, along with any direct or indirect dependencies of the primary software being contained). + +As for any pre-built image usage, it is the image user's responsibility to ensure that any use of this image complies +with any relevant licenses for all software contained within. diff --git a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/src/main/docker/Dockerfile b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/src/main/docker/Dockerfile new file mode 100644 index 000000000..9d7fb7801 --- /dev/null +++ b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault-legacy/src/main/docker/Dockerfile @@ -0,0 +1,64 @@ +# +# Copyright (c) 2023 ZF Friedrichshafen AG +# Copyright (c) 2022,2023 Mercedes-Benz Tech Innovation GmbH +# Copyright (c) 2021,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# 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 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +FROM alpine:3.18.2 AS otel + +ENV OTEL_AGENT_LOCATION "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.12.1/opentelemetry-javaagent.jar" + +HEALTHCHECK NONE + +RUN apk update && apk add curl=8.1.2-r0 --no-cache +RUN curl -L --proto "=https" -sSf ${OTEL_AGENT_LOCATION} --output /tmp/opentelemetry-javaagent.jar + +FROM eclipse-temurin:17.0.6_10-jre-alpine +ARG JAR + +ARG APP_USER=docker +ARG APP_UID=10100 + +RUN addgroup --system "$APP_USER" + +RUN adduser \ + --shell /sbin/nologin \ + --disabled-password \ + --gecos "" \ + --ingroup "$APP_USER" \ + --no-create-home \ + --uid "$APP_UID" \ + "$APP_USER" + +USER "$APP_USER" +WORKDIR /app + +COPY --from=otel /tmp/opentelemetry-javaagent.jar . +COPY ${JAR} edc-controlplane.jar + +HEALTHCHECK NONE + +CMD ["java", \ + "-javaagent:/app/opentelemetry-javaagent.jar", \ + "-Dedc.fs.config=/app/configuration.properties", \ + "-Djava.util.logging.config.file=/app/logging.properties", \ + "-Dotel.javaagent.configuration-file=/app/opentelemetry.properties", \ + "-Dotel.metrics.exporter=prometheus", \ + "-Dotel.exporter.prometheus.port=9090", \ + "-Djava.security.egd=file:/dev/urandom", \ + "-jar", \ + "edc-controlplane.jar"] diff --git a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/README.md b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/README.md index 636d8a8b8..4d73773fb 100644 --- a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/README.md +++ b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/README.md @@ -35,7 +35,7 @@ Details regarding each configuration property can be found at the [documentary s | edc.ids.catalog.id | | urn:catalog:default | | | ids.webhook.address | | | | | edc.hostname | | localhost | | -| edc.oauth.token.url | X | | | +| edc.oauth.token.url | X | | | | edc.oauth.public.key.alias | X | key-to-daps-certificate-in-keyvault | | | edc.oauth.private.key.alias | X | key-to-private-key-in-keyvault | | | edc.oauth.client.id | X | daps-oauth-client-id | | @@ -102,7 +102,7 @@ edc.hostname=localhost edc.api.auth.key=password # OAuth / DAPS related configuration -edc.oauth.token.url=https://daps.catena-x.net +edc.oauth.token.url=https://daps.example.net edc.oauth.public.key.alias=key-to-daps-certificate-in-keyvault edc.oauth.private.key.alias=key-to-private-key-in-keyvault edc.oauth.client.id=daps-oauth-client-id diff --git a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/src/main/docker/Dockerfile b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/src/main/docker/Dockerfile index b4faaf422..9d7fb7801 100644 --- a/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/src/main/docker/Dockerfile +++ b/edc-controlplane/edc-controlplane-postgresql-hashicorp-vault/src/main/docker/Dockerfile @@ -18,7 +18,7 @@ # # SPDX-License-Identifier: Apache-2.0 # -FROM alpine:3.18.0 AS otel +FROM alpine:3.18.2 AS otel ENV OTEL_AGENT_LOCATION "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.12.1/opentelemetry-javaagent.jar" diff --git a/edc-controlplane/edc-runtime-memory/README.md b/edc-controlplane/edc-runtime-memory/README.md index caf7fe24e..150a8f680 100644 --- a/edc-controlplane/edc-runtime-memory/README.md +++ b/edc-controlplane/edc-runtime-memory/README.md @@ -48,7 +48,7 @@ the [documentary section of the EDC](https://github.com/eclipse-edc/Connector/tr | edc.ids.catalog.id | | urn:catalog:default | | | ids.webhook.address | | | | | edc.hostname | | localhost | | -| edc.oauth.token.url | X | | | +| edc.oauth.token.url | X | | | | edc.oauth.public.key.alias | X | key-to-daps-certificate-in-keyvault | | | edc.oauth.private.key.alias | X | key-to-private-key-in-keyvault | | | edc.oauth.client.id | X | daps-oauth-client-id | | @@ -93,7 +93,7 @@ edc.hostname=localhost edc.api.auth.key=password # OAuth / DAPS related configuration -edc.oauth.token.url=https://daps.catena-x.net +edc.oauth.token.url=https://daps.example.net edc.oauth.public.key.alias=key-to-daps-certificate-in-keyvault edc.oauth.private.key.alias=key-to-private-key-in-keyvault edc.oauth.client.id=daps-oauth-client-id diff --git a/edc-controlplane/edc-runtime-memory/build.gradle.kts b/edc-controlplane/edc-runtime-memory/build.gradle.kts index 1df3d6915..191e11d67 100644 --- a/edc-controlplane/edc-runtime-memory/build.gradle.kts +++ b/edc-controlplane/edc-runtime-memory/build.gradle.kts @@ -30,6 +30,7 @@ dependencies { } runtimeOnly(project(":edc-dataplane:edc-dataplane-base")) runtimeOnly(libs.edc.core.controlplane) + testImplementation(libs.edc.junit) } tasks.withType { diff --git a/edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/InMemoryVault.java b/edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/InMemoryVault.java deleted file mode 100644 index 9b92a83c0..000000000 --- a/edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/InMemoryVault.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2023 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.tractusx.edc.vault.memory; - -import org.eclipse.edc.spi.monitor.Monitor; -import org.eclipse.edc.spi.result.Result; -import org.eclipse.edc.spi.security.Vault; -import org.jetbrains.annotations.Nullable; - -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public class InMemoryVault implements Vault { - private final Map secrets = new ConcurrentHashMap<>(); - private final Monitor monitor; - - public InMemoryVault(Monitor monitor) { - this.monitor = monitor; - } - - @Override - public @Nullable String resolveSecret(String s) { - monitor.debug("resolving secret " + s); - return secrets.getOrDefault(s, null); - } - - @Override - public Result storeSecret(String s, String s1) { - monitor.debug("storing secret " + s); - secrets.put(s, s1); - return Result.success(); - } - - @Override - public Result deleteSecret(String s) { - monitor.debug("deleting secret " + s); - return secrets.remove(s) == null ? - Result.failure("Secret with key " + s + " does not exist") : - Result.success(); - } -} diff --git a/edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/VaultMemoryExtension.java b/edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/VaultSeedExtension.java similarity index 66% rename from edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/VaultMemoryExtension.java rename to edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/VaultSeedExtension.java index 434e7886f..67c64bfa6 100644 --- a/edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/VaultMemoryExtension.java +++ b/edc-controlplane/edc-runtime-memory/src/main/java/org/eclipse/tractusx/edc/vault/memory/VaultSeedExtension.java @@ -13,27 +13,27 @@ */ package org.eclipse.tractusx.edc.vault.memory; +import org.eclipse.edc.runtime.metamodel.annotation.BaseExtension; import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; import org.eclipse.edc.runtime.metamodel.annotation.Provider; -import org.eclipse.edc.runtime.metamodel.annotation.Provides; import org.eclipse.edc.runtime.metamodel.annotation.Setting; -import org.eclipse.edc.spi.security.CertificateResolver; -import org.eclipse.edc.spi.security.PrivateKeyResolver; import org.eclipse.edc.spi.security.Vault; -import org.eclipse.edc.spi.security.VaultCertificateResolver; -import org.eclipse.edc.spi.security.VaultPrivateKeyResolver; import org.eclipse.edc.spi.system.ServiceExtension; import org.eclipse.edc.spi.system.ServiceExtensionContext; import java.util.stream.Stream; -@Provides({PrivateKeyResolver.class, CertificateResolver.class}) -@Extension(value = "In-memory vault extension", categories = {"vault", "security"}) -public class VaultMemoryExtension implements ServiceExtension { +@Extension(value = "Vault seed extension: adds secrets to the vault", categories = {"vault", "security"}) +@BaseExtension +public class VaultSeedExtension implements ServiceExtension { @Setting(value = "Secrets with which the vault gets initially populated. Specify as comma-separated list of key:secret pairs.") public static final String VAULT_MEMORY_SECRETS_PROPERTY = "edc.vault.secrets"; - public static final String NAME = "In-Memory Vault Extension"; + public static final String NAME = "Vault Seed Extension"; + + @Inject + private Vault vault; @Override public String name() { @@ -43,9 +43,6 @@ public String name() { @Provider public Vault createInMemVault(ServiceExtensionContext context) { var seedSecrets = context.getSetting(VAULT_MEMORY_SECRETS_PROPERTY, null); - var vault = new InMemoryVault(context.getMonitor()); - context.registerService(PrivateKeyResolver.class, new VaultPrivateKeyResolver(vault)); - context.registerService(CertificateResolver.class, new VaultCertificateResolver(vault)); if (seedSecrets != null) { Stream.of(seedSecrets.split(";")) .filter(pair -> pair.contains(":")) diff --git a/edc-controlplane/edc-runtime-memory/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-controlplane/edc-runtime-memory/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension index b105388ea..59e5aeac1 100644 --- a/edc-controlplane/edc-runtime-memory/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ b/edc-controlplane/edc-runtime-memory/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -18,4 +18,4 @@ # SPDX-License-Identifier: Apache-2.0 # -org.eclipse.tractusx.edc.vault.memory.VaultMemoryExtension +org.eclipse.tractusx.edc.vault.memory.VaultSeedExtension diff --git a/edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/InMemoryVaultTest.java b/edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/InMemoryVaultTest.java deleted file mode 100644 index c00ae8180..000000000 --- a/edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/InMemoryVaultTest.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 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.tractusx.edc.vault.memory; - -import org.eclipse.edc.spi.monitor.Monitor; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; - -class InMemoryVaultTest { - - private InMemoryVault vault; - - @BeforeEach - void setUp() { - vault = new InMemoryVault(mock(Monitor.class)); - } - - @Test - void resolveSecret() { - assertThat(vault.resolveSecret("key")).isNull(); - vault.storeSecret("key", "secret"); - assertThat(vault.resolveSecret("key")).isEqualTo("secret"); - } - - @Test - void storeSecret() { - assertThat(vault.storeSecret("key", "value1").succeeded()).isTrue(); - assertThat(vault.resolveSecret("key")).isEqualTo("value1"); - assertThat(vault.storeSecret("key", "value2").succeeded()).isTrue(); - assertThat(vault.resolveSecret("key")).isEqualTo("value2"); - } - - @Test - void deleteSecret() { - assertThat(vault.deleteSecret("key").succeeded()).isFalse(); - assertThat(vault.storeSecret("key", "value1").succeeded()).isTrue(); - assertThat(vault.deleteSecret("key").succeeded()).isTrue(); - assertThat(vault.resolveSecret("key")).isNull(); - - } -} diff --git a/edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/VaultMemoryExtensionTest.java b/edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/VaultSeedExtensionTest.java similarity index 61% rename from edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/VaultMemoryExtensionTest.java rename to edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/VaultSeedExtensionTest.java index 7012d5285..e0ffd32cd 100644 --- a/edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/VaultMemoryExtensionTest.java +++ b/edc-controlplane/edc-runtime-memory/src/test/java/org/eclipse/tractusx/edc/vault/memory/VaultSeedExtensionTest.java @@ -14,10 +14,15 @@ package org.eclipse.tractusx.edc.vault.memory; +import org.eclipse.edc.connector.core.vault.InMemoryVault; +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.security.Vault; import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.injection.ObjectFactory; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -25,32 +30,35 @@ import static org.mockito.Mockito.anyString; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -class VaultMemoryExtensionTest { - private VaultMemoryExtension extension; +@ExtendWith(DependencyInjectionExtension.class) +class VaultSeedExtensionTest { + private VaultSeedExtension extension; private ServiceExtensionContext context; private Monitor monitor; @BeforeEach - void setup() { - extension = new VaultMemoryExtension(); - context = mock(ServiceExtensionContext.class); + void setup(ServiceExtensionContext context, ObjectFactory factory) { + this.context = spy(context); monitor = mock(Monitor.class); - when(context.getMonitor()).thenReturn(monitor); + context.registerService(Monitor.class, monitor); + context.registerService(Vault.class, new InMemoryVault(monitor)); + extension = factory.constructInstance(VaultSeedExtension.class); } @Test void name() { - assertThat(extension.name()).isEqualTo("In-Memory Vault Extension"); + assertThat(extension.name()).isEqualTo("Vault Seed Extension"); } @ParameterizedTest @ValueSource(strings = {"key1:", "key1:value1", "key1:value1;", ";key1:value1", ";sdf;key1:value1"}) void createInMemVault_validString(String secret) { - when(context.getSetting(eq(VaultMemoryExtension.VAULT_MEMORY_SECRETS_PROPERTY), eq(null))).thenReturn(secret); + when(context.getSetting(eq(VaultSeedExtension.VAULT_MEMORY_SECRETS_PROPERTY), eq(null))).thenReturn(secret); extension.createInMemVault(context); verify(monitor, times(1)).debug(anyString()); } diff --git a/edc-dataplane/edc-dataplane-azure-vault/src/main/docker/Dockerfile b/edc-dataplane/edc-dataplane-azure-vault/src/main/docker/Dockerfile index 32add3db5..9475ed4f0 100644 --- a/edc-dataplane/edc-dataplane-azure-vault/src/main/docker/Dockerfile +++ b/edc-dataplane/edc-dataplane-azure-vault/src/main/docker/Dockerfile @@ -18,7 +18,7 @@ # # SPDX-License-Identifier: Apache-2.0 # -FROM alpine:3.18.0 AS otel +FROM alpine:3.18.2 AS otel ENV OTEL_AGENT_LOCATION "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.12.1/opentelemetry-javaagent.jar" diff --git a/edc-dataplane/edc-dataplane-base/build.gradle.kts b/edc-dataplane/edc-dataplane-base/build.gradle.kts index 4b2999a02..4f46c6700 100644 --- a/edc-dataplane/edc-dataplane-base/build.gradle.kts +++ b/edc-dataplane/edc-dataplane-base/build.gradle.kts @@ -25,9 +25,9 @@ plugins { dependencies { runtimeOnly(project(":core:edr-cache-core")) runtimeOnly(project(":edc-extensions:observability-api-customization")) - runtimeOnly(project(":edc-dataplane:edc-dataplane-proxy-consumer-api")) - runtimeOnly(project(":edc-dataplane:edc-dataplane-proxy-provider-api")) - runtimeOnly(project(":edc-dataplane:edc-dataplane-proxy-provider-core")) + runtimeOnly(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-consumer-api")) + runtimeOnly(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-api")) + runtimeOnly(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-core")) runtimeOnly(libs.edc.config.filesystem) runtimeOnly(libs.edc.dpf.awss3) diff --git a/edc-dataplane/edc-dataplane-hashicorp-vault/src/main/docker/Dockerfile b/edc-dataplane/edc-dataplane-hashicorp-vault/src/main/docker/Dockerfile index 32add3db5..9475ed4f0 100644 --- a/edc-dataplane/edc-dataplane-hashicorp-vault/src/main/docker/Dockerfile +++ b/edc-dataplane/edc-dataplane-hashicorp-vault/src/main/docker/Dockerfile @@ -18,7 +18,7 @@ # # SPDX-License-Identifier: Apache-2.0 # -FROM alpine:3.18.0 AS otel +FROM alpine:3.18.2 AS otel ENV OTEL_AGENT_LOCATION "https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/download/v1.12.1/opentelemetry-javaagent.jar" diff --git a/edc-extensions/business-partner-validation/README.md b/edc-extensions/business-partner-validation/README.md index 79a0d7fc3..339417771 100644 --- a/edc-extensions/business-partner-validation/README.md +++ b/edc-extensions/business-partner-validation/README.md @@ -1,7 +1,7 @@ # Business Partner Validation Extension Using the Business Partner Validation Extension it's possible to add configurable validation against -Catena-X `Participants` in the `ContractDefinition.AccessPolicy`. Using a BPN in `ContractDefinition.ContractPolicy` is possible, too, but once the contract is complete there is no policy enforcement in place from the EDC. +BPNs in the `ContractDefinition.AccessPolicy`. Using a BPN in `ContractDefinition.ContractPolicy` is possible, too, but once the contract is complete there is no policy enforcement in place from the EDC. It is recommended to have a basic understanding of the EDC contract/policy domain before using this extension. The corresponding documentation can be found in the [EDC GitHub Repository](https://github.com/eclipse-edc/Connector). @@ -73,7 +73,7 @@ It will permit the constraints contained to be evaluated using the `OR` operator { "edctype": "dataspaceconnector:permission", "action": { - "type": "USE", + "type": "USE" }, "constraints": [ { diff --git a/edc-extensions/business-partner-validation/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/functions/AbstractBusinessPartnerValidation.java b/edc-extensions/business-partner-validation/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/functions/AbstractBusinessPartnerValidation.java index cd124684b..000630b19 100644 --- a/edc-extensions/business-partner-validation/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/functions/AbstractBusinessPartnerValidation.java +++ b/edc-extensions/business-partner-validation/src/main/java/org/eclipse/tractusx/edc/validation/businesspartner/functions/AbstractBusinessPartnerValidation.java @@ -25,8 +25,8 @@ import org.eclipse.edc.policy.model.Operator; import org.eclipse.edc.spi.agent.ParticipantAgent; import org.eclipse.edc.spi.monitor.Monitor; +import org.jetbrains.annotations.Nullable; -import java.util.Map; import java.util.Objects; import static java.lang.String.format; @@ -104,18 +104,11 @@ protected boolean evaluate( } final ParticipantAgent participantAgent = policyContext.getParticipantAgent(); - final Map claims = participantAgent.getClaims(); - if (!claims.containsKey(REFERRING_CONNECTOR_CLAIM)) { + if (participantAgent == null) { return false; } - - Object referringConnectorClaimObject = claims.get(REFERRING_CONNECTOR_CLAIM); - String referringConnectorClaim = null; - - if (referringConnectorClaimObject instanceof String) { - referringConnectorClaim = (String) referringConnectorClaimObject; - } + var referringConnectorClaim = getReferringConnectorClaim(participantAgent); if (referringConnectorClaim == null || referringConnectorClaim.isEmpty()) { return false; @@ -131,6 +124,24 @@ protected boolean evaluate( } } + @Nullable + private String getReferringConnectorClaim(ParticipantAgent participantAgent) { + Object referringConnectorClaimObject = null; + String referringConnectorClaim = null; + var claims = participantAgent.getClaims(); + + referringConnectorClaimObject = claims.get(REFERRING_CONNECTOR_CLAIM); + + if (referringConnectorClaimObject instanceof String) { + referringConnectorClaim = (String) referringConnectorClaimObject; + } + if (referringConnectorClaim == null) { + referringConnectorClaim = participantAgent.getIdentity(); + } + + return referringConnectorClaim; + } + private boolean isBusinessPartnerNumber(String referringConnectorClaim, Object businessPartnerNumber, PolicyContext policyContext) { if (businessPartnerNumber == null) { final String message = format(FAIL_EVALUATION_BECAUSE_RIGHT_VALUE_NOT_STRING, "null"); diff --git a/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/AdapterEdrControllerTest.java b/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/AdapterEdrControllerTest.java index a345406b1..afd6f92ec 100644 --- a/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/AdapterEdrControllerTest.java +++ b/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/AdapterEdrControllerTest.java @@ -44,8 +44,8 @@ import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; +import static org.eclipse.tractusx.edc.api.cp.adapter.TestFunctions.negotiationRequest; import static org.eclipse.tractusx.edc.api.cp.adapter.TestFunctions.openRequest; -import static org.eclipse.tractusx.edc.api.cp.adapter.TestFunctions.requestDto; import static org.eclipse.tractusx.edc.edr.spi.CoreConstants.TX_NAMESPACE; import static org.eclipse.tractusx.edc.edr.spi.EndpointDataReferenceEntry.EDR_ENTRY_AGREEMENT_ID; import static org.eclipse.tractusx.edc.edr.spi.EndpointDataReferenceEntry.EDR_ENTRY_ASSET_ID; @@ -82,7 +82,8 @@ void initEdrNegotiation_shouldWork_whenValidRequest() { when(transformerRegistry.transform(any(), eq(NegotiateEdrRequest.class))).thenReturn(Result.success(openRequest)); when(adapterTransferProcessService.initiateEdrNegotiation(openRequest)).thenReturn(ServiceResult.success(contractNegotiation)); when(transformerRegistry.transform(any(IdResponseDto.class), eq(JsonObject.class))).thenReturn(Result.success(responseBody)); - var request = requestDto(); + + var request = negotiationRequest(); baseRequest() .contentType(MediaType.APPLICATION_JSON) @@ -127,7 +128,7 @@ void getEdr_shouldReturnDataAddress_whenFound() { var transferProcessId = "id"; var edr = EndpointDataReference.Builder.newInstance().endpoint("test").id(transferProcessId).build(); var response = Json.createObjectBuilder() - .add(DataAddress.TYPE, EndpointDataReference.EDR_SIMPLE_TYPE) + .add(DataAddress.EDC_DATA_ADDRESS_TYPE_PROPERTY, EndpointDataReference.EDR_SIMPLE_TYPE) .add(EndpointDataReference.ENDPOINT, edr.getEndpoint()) .add(EndpointDataReference.ID, edr.getId()) .build(); @@ -164,7 +165,7 @@ void queryEdrs_shouldReturnCachedEntries_whenAssetIdIsProvided() { .add(EDR_ENTRY_TRANSFER_PROCESS_ID, entry.getTransferProcessId()) .add(EDR_ENTRY_AGREEMENT_ID, entry.getAgreementId()) .build(); - + when(adapterTransferProcessService.findByAssetAndAgreement(assetId, null)).thenReturn(ServiceResult.success(List.of(entry))); when(transformerRegistry.transform(any(EndpointDataReferenceEntry.class), eq(JsonObject.class))).thenReturn(Result.success(response)); diff --git a/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/TestFunctions.java b/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/TestFunctions.java index ec1a89824..c3ad7947a 100644 --- a/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/TestFunctions.java +++ b/edc-extensions/control-plane-adapter-api/src/test/java/org/eclipse/tractusx/edc/api/cp/adapter/TestFunctions.java @@ -14,6 +14,8 @@ package org.eclipse.tractusx.edc.api.cp.adapter; +import jakarta.json.Json; +import jakarta.json.JsonObject; import org.eclipse.edc.connector.api.management.contractnegotiation.model.ContractOfferDescription; import org.eclipse.edc.connector.contract.spi.types.offer.ContractOffer; import org.eclipse.edc.policy.model.Policy; @@ -22,6 +24,9 @@ import java.util.UUID; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; +import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; + public class TestFunctions { public static ContractOfferDescription createOffer(String offerId, String assetId) { @@ -48,15 +53,18 @@ public static ContractOfferDescription createOffer() { return createOffer(UUID.randomUUID().toString(), UUID.randomUUID().toString()); } - public static NegotiateEdrRequestDto requestDto() { - return NegotiateEdrRequestDto.Builder.newInstance() - .connectorAddress("test") - .connectorId("id") - .protocol("test-protocol") - .offer(ContractOfferDescription.Builder.newInstance() - .offerId("offerId") - .assetId("assetId") - .policy(Policy.Builder.newInstance().build()).build()) + public static JsonObject negotiationRequest() { + return Json.createObjectBuilder() + .add(TYPE, NegotiateEdrRequestDto.EDR_REQUEST_DTO_TYPE) + .add(EDC_NAMESPACE + "connectorId", "test") + .add(EDC_NAMESPACE + "providerId", "test") + .add(EDC_NAMESPACE + "connectorAddress", "test") + .add(EDC_NAMESPACE + "protocol", "dataspace-protocol-http") + .add(EDC_NAMESPACE + "offer", Json.createObjectBuilder() + .add(EDC_NAMESPACE + "offerId", "offerId") + .add(EDC_NAMESPACE + "assetId", "assetId") + .add(EDC_NAMESPACE + "policy", Json.createObjectBuilder().build()) + ) .build(); } diff --git a/edc-extensions/control-plane-adapter-callback/src/main/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallback.java b/edc-extensions/control-plane-adapter-callback/src/main/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallback.java index 04040b0fa..cfb8518a1 100644 --- a/edc-extensions/control-plane-adapter-callback/src/main/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallback.java +++ b/edc-extensions/control-plane-adapter-callback/src/main/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallback.java @@ -43,8 +43,7 @@ public TransferProcessLocalCallback(EndpointDataReferenceCache edrCache, Transfe @Override public Result invoke(CallbackEventRemoteMessage message) { - if (message.getEventEnvelope().getPayload() instanceof TransferProcessStarted) { - var transferProcessStarted = (TransferProcessStarted) message.getEventEnvelope().getPayload(); + if (message.getEventEnvelope().getPayload() instanceof TransferProcessStarted transferProcessStarted) { if (transferProcessStarted.getDataAddress() != null) { return EndpointDataAddressConstants.to(transferProcessStarted.getDataAddress()) .compose(this::storeEdr) @@ -57,8 +56,7 @@ public Result invoke(CallbackEventRemoteMessage messa private Result storeEdr(EndpointDataReference edr) { return transactionContext.execute(() -> { // TODO upstream api for getting the TP with the DataRequest#id - var transferProcessId = transferProcessStore.processIdForDataRequestId(edr.getId()); - var transferProcess = transferProcessStore.findById(transferProcessId); + var transferProcess = transferProcessStore.findForCorrelationId(edr.getId()); if (transferProcess != null) { var cacheEntry = EndpointDataReferenceEntry.Builder.newInstance() .transferProcessId(transferProcess.getId()) @@ -69,7 +67,7 @@ private Result storeEdr(EndpointDataReference edr) { edrCache.save(cacheEntry, edr); return Result.success(); } else { - return Result.failure(format("Failed to find a transfer process with ID %s", transferProcessId)); + return Result.failure(format("Failed to find a transfer process with correlation ID %s", edr.getId())); } }); diff --git a/edc-extensions/control-plane-adapter-callback/src/test/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallbackTest.java b/edc-extensions/control-plane-adapter-callback/src/test/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallbackTest.java index b4b6d8480..6f508990e 100644 --- a/edc-extensions/control-plane-adapter-callback/src/test/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallbackTest.java +++ b/edc-extensions/control-plane-adapter-callback/src/test/java/org/eclipse/tractusx/edc/cp/adapter/callback/TransferProcessLocalCallbackTest.java @@ -79,8 +79,6 @@ void invoke_shouldStoreTheEdrInCache_whenDataAddressIsPresent() { var edr = getEdr(); - when(transferProcessStore.processIdForDataRequestId(edr.getId())).thenReturn(transferProcessId); - var dataRequest = DataRequest.Builder.newInstance().id(edr.getId()) .destinationType("HttpProxy") .assetId(assetId) @@ -92,6 +90,8 @@ void invoke_shouldStoreTheEdrInCache_whenDataAddressIsPresent() { .dataRequest(dataRequest) .build(); + when(transferProcessStore.findForCorrelationId(edr.getId())).thenReturn(transferProcess); + when(transferProcessStore.findById(transferProcessId)).thenReturn(transferProcess); @@ -130,7 +130,7 @@ void invoke_shouldNotFail_whenTransferProcessNotFound() { var edr = getEdr(); - when(transferProcessStore.processIdForDataRequestId(edr.getId())).thenReturn(transferProcessId); + when(transferProcessStore.findForCorrelationId(edr.getId())).thenReturn(null); when(transferProcessStore.findById(transferProcessId)).thenReturn(null); diff --git a/edc-extensions/cx-oauth2/README.md b/edc-extensions/cx-oauth2/README.md index f9ca70637..77ee53642 100644 --- a/edc-extensions/cx-oauth2/README.md +++ b/edc-extensions/cx-oauth2/README.md @@ -1,6 +1,6 @@ -# Catena-X OAuth2 Extension +# Tractus-X OAuth2 Extension -## Why Catena-X needs this extension +## Why Tractus-X needs this extension In IDS the DAPS token audience is always `idsc:IDS_CONNECTORS_ALL`. At first glance this makes it possible for other connectors to steal and reuse an received token. To mitigate this security risk IDS introduces something called `transportCertsSha256`, which couples the connector audience with its corresponding TLS/SSL certificate. @@ -8,7 +8,7 @@ From [GitHub IDS-G](https://github.com/International-Data-Spaces-Association/IDS > - **transportCertsSha256** Contains the public keys of the used transport certificates, hashed using SHA256. The identifying X509 certificate should not be used for the communication encryption. Therefore, the receiving party needs to connect the identity of a connector by relating its hostname (from the communication encryption layer) and the used private/public key pair, with its IDS identity claim of the DAT. The public transportation key must be one of the `transportCertsSha256` values. Otherwise, the receiving connector must expect that the requesting connector is using a false identity claim. In general, this claim holds an Array of Strings, but it may optionally hold a single String instead if the Array would have exactly one element. -The reason IDS did this is to prevent the IDS DAPS to know, which connectors talk to each other. But this solution introduces a new level of complexity for different deployment scenarios. The Catena-X OAuth2 Extension introduces the classic audience validation again, so that Catena-X does not have to deal with these things for now. +The reason IDS did this is to prevent the IDS DAPS to know, which connectors talk to each other. But this solution introduces a new level of complexity for different deployment scenarios. The OAuth2 Extension introduces the classic audience validation again, so that users do not have to deal with these things for now. ## Configuration @@ -32,12 +32,12 @@ When a connector receives a message, it will checks the token audience is equal ![sequence diagram](./diagrams/sequence.png) -## Catena-X Participant Extension +## Participant Extension Starting from `0.0.1-milestone-9` EDC requires a mandatory setting `edc.participant.id`, which in this case should be the BPN number which is transmitted over the wire to identifying the participants IDs. To verify that in the DAPS token an extension has been created, that extract from the `ClaimToken` the BPN number and then EDC compare that identity with the one provided over the wire, for security reason. -By default the extension parse the `referringConnector` url and extract the BPN number as the last parameter in the URL eg (http://sokrates-controlplane/BPNSOKRATES). +By default, the extension parse the `referringConnector` url and extract the BPN number as the last parameter in the URL eg (http://sokrates-controlplane/BPNSOKRATES). ### Configuration diff --git a/edc-extensions/cx-policy/build.gradle.kts b/edc-extensions/cx-policy/build.gradle.kts new file mode 100644 index 000000000..b146181fc --- /dev/null +++ b/edc-extensions/cx-policy/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 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` +} + +dependencies { + implementation(project(":spi:ssi-spi")) + implementation(libs.edc.spi.policyengine) + implementation(libs.jakartaJson) + testImplementation(libs.jacksonJsonP) + testImplementation(libs.titaniumJsonLd) + testImplementation(testFixtures(project(":spi:ssi-spi"))) +} diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/CxPolicyExtension.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/CxPolicyExtension.java new file mode 100644 index 000000000..50faac428 --- /dev/null +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/CxPolicyExtension.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx; + +import org.eclipse.edc.policy.engine.spi.PolicyEngine; +import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; + +import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerBindings; +import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerFunctions; + +/** + * Provides implementations of standard CX usage policies. + */ +public class CxPolicyExtension implements ServiceExtension { + private static final String NAME = "CX Policy"; + + @Inject + private PolicyEngine policyEngine; + + @Inject + private RuleBindingRegistry bindingRegistry; + + @Override + public String name() { + return NAME; + } + + @Override + public void initialize(ServiceExtensionContext context) { + registerFunctions(policyEngine); + registerBindings(bindingRegistry); + } +} diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/common/AbstractVpConstraintFunction.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/common/AbstractVpConstraintFunction.java new file mode 100644 index 000000000..0a055d78e --- /dev/null +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/common/AbstractVpConstraintFunction.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.common; + +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.eclipse.edc.policy.engine.spi.AtomicConstraintFunction; +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Operator; +import org.eclipse.edc.policy.model.Permission; +import org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdFieldExtractor; +import org.jetbrains.annotations.Nullable; + +import java.util.stream.Collectors; + +import static jakarta.json.JsonValue.ValueType.OBJECT; +import static java.lang.String.format; +import static java.util.Arrays.stream; +import static java.util.Objects.requireNonNull; +import static java.util.stream.Collectors.joining; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CREDENTIAL_SUBJECT; + +/** + * Base processing for constraint functions that verify a permission against a Catena-X verifiable presentation. + */ +public abstract class AbstractVpConstraintFunction implements AtomicConstraintFunction { + + protected static final String VALUE = "@value"; + private static final String ERROR_PREFIX_TEMPLATE = "Invalid %s VC format: "; + protected final String errorPrefix; + protected final String credentialType; + private JsonLdFieldExtractor credentialSubjectExtractor = JsonLdFieldExtractor.Builder.newInstance() + .field(CREDENTIAL_SUBJECT) + .fieldAlias("credentialSubject") + .build(); + + /** + * Ctor. + * + * @param credentialType the credential type that will be verified against. + */ + public AbstractVpConstraintFunction(String credentialType) { + requireNonNull(credentialType); + this.credentialType = credentialType; + this.errorPrefix = format(ERROR_PREFIX_TEMPLATE, credentialType); + this.credentialSubjectExtractor = JsonLdFieldExtractor.Builder.newInstance() + .field(CREDENTIAL_SUBJECT) + .fieldAlias("credentialSubject") + .errorPrefix(errorPrefix) + .build(); + } + + /** + * Validates the operator is in the set of expected operators. + */ + protected boolean validateOperator(Operator operator, PolicyContext context, Operator... expectedOperators) { + var set = stream(expectedOperators).collect(Collectors.toSet()); + if (!set.contains(operator)) { + var valid = set.stream().map(Enum::toString).collect(joining(",")); + context.reportProblem(format("Unsupported operator for %s credential constraint, only %s allowed: %s", credentialType, valid, operator)); + return false; + } + return true; + } + + /** + * Validates the VP by checking that it is a {@link JsonObject}. + */ + protected boolean validatePresentation(@Nullable Object vp, PolicyContext context) { + if (vp == null) { + context.reportProblem(format("%s VP not found", credentialType)); + return false; + } + + if (!(vp instanceof JsonValue jsonValue)) { + context.reportProblem(format("%s VP is not a JSON type: %s", credentialType, vp.getClass().getName())); + return false; + } + + if (!(OBJECT == jsonValue.getValueType())) { + context.reportProblem(format("%s VP must be type %s but was: %s", credentialType, OBJECT, jsonValue.getValueType())); + return false; + } + + return true; + } + + /** + * Returns the credential subject portion of a VC or null if there was an error. Error information will be reported to the context. + */ + @Nullable + protected JsonObject extractCredentialSubject(JsonObject credential, PolicyContext context) { + return credentialSubjectExtractor.extract(credential).onFailure(failure -> context.reportProblem(failure.getFailureDetail())).getContent(); + } + + /** + * Returns true if the actual operand value is a string literal case-insensitive equal to the expected value. + */ + protected boolean validateRightOperand(String expectedValue, Object actualValue, PolicyContext context) { + if (!(actualValue instanceof String)) { + context.reportProblem(format("Invalid right operand format specified for %s credential", credentialType)); + return false; + } + + if (!expectedValue.equalsIgnoreCase(actualValue.toString().trim())) { + context.reportProblem(format("Invalid right operand specified for %s credential: %s", credentialType, actualValue)); + return false; + } + + return true; + } + +} diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/common/PolicyScopes.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/common/PolicyScopes.java new file mode 100644 index 000000000..99304a9d9 --- /dev/null +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/common/PolicyScopes.java @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.common; + +/** + * Defines standard EDC policy scopes. + */ +public interface PolicyScopes { + String CATALOG_REQUEST_SCOPE = "request.catalog"; + String NEGOTIATION_REQUEST_SCOPE = "request.contract.negotiation"; + String TRANSFER_PROCESS_REQUEST_SCOPE = "request.transfer.process"; + + String CATALOG_SCOPE = "catalog"; + String NEGOTIATION_SCOPE = "contract.negotiation"; + String TRANSFER_PROCESS_SCOPE = "transfer.process"; +} diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/framework/FrameworkAgreementConstraintFunction.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/framework/FrameworkAgreementConstraintFunction.java new file mode 100644 index 000000000..bc9fca518 --- /dev/null +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/framework/FrameworkAgreementConstraintFunction.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.framework; + +import jakarta.json.JsonObject; +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Operator; +import org.eclipse.edc.policy.model.Permission; +import org.eclipse.tractusx.edc.policy.cx.common.AbstractVpConstraintFunction; + +import java.util.Objects; + +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; +import static org.eclipse.edc.policy.model.Operator.EQ; +import static org.eclipse.edc.policy.model.Operator.GEQ; +import static org.eclipse.edc.policy.model.Operator.GT; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CX_USE_CASE_NS; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.VP_PROPERTY; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTypeFunctions.extractObjectsOfType; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdValueFunctions.extractStringValue; + + +/** + * Enforces a Framework Agreement constraint. + *

+ * A policy constraints requiring a usecase framework credential take a left operand in the form: + *

FrameworkAgreement.[type]
+ *

+ * The following example requires a client to present a sustainability credential: + *

+ * "constraint": {
+ *     "leftOperand": "FrameworkAgreement.sustainability",
+ *     "operator": "eq",
+ *     "rightOperand": "active"
+ * }
+ * 
+ *

+ * NB: This function will be enabled in the 3.2 release. + */ +public class FrameworkAgreementConstraintFunction extends AbstractVpConstraintFunction { + public static final String CONTRACT_VERSION_PROPERTY = CX_USE_CASE_NS + "/contractVersion"; + private static final String ACTIVE = "active"; + private String agreementType; + private String agreementVersion; + + private FrameworkAgreementConstraintFunction(String credentialType) { + super(credentialType); + } + + @Override + public boolean evaluate(Operator operator, Object rightValue, Permission permission, PolicyContext context) { + if (!validateOperator(operator, context, EQ, GT, GEQ)) { + return false; + } + + if (!validateRightOperand(ACTIVE, rightValue, context)) { + return false; + } + + var vp = (JsonObject) context.getParticipantAgent().getClaims().get(VP_PROPERTY); + if (!validatePresentation(vp, context)) { + return false; + } + + return extractObjectsOfType(credentialType, vp) + .map(credential -> extractCredentialSubject(credential, context)) + .filter(Objects::nonNull) + .anyMatch(credentialSubject -> validateUseCase(credentialSubject, operator, context)); + } + + private boolean validateUseCase(JsonObject credentialSubject, Operator operator, PolicyContext context) { + var usecaseAgreement = extractObjectsOfType(agreementType, credentialSubject).findFirst().orElse(null); + if (usecaseAgreement == null) { + context.reportProblem(format("%s is missing the usecase type: %s", credentialType, agreementType)); + return false; + } + + return validateVersion(context, operator, usecaseAgreement); + } + + private boolean validateVersion(PolicyContext context, Operator operator, JsonObject usecaseAgreement) { + if (agreementVersion == null) { + return true; + } + var version = extractStringValue(usecaseAgreement.get(CONTRACT_VERSION_PROPERTY)); + if (version == null || version.trim().length() == 0) { + context.reportProblem(format("%s is missing a %s property", credentialType, CONTRACT_VERSION_PROPERTY)); + return false; + } + + switch (operator) { + case EQ -> { + if (!version.equals(agreementVersion)) { + context.reportProblem(format("%s version %s does not match required version: %s", credentialType, version, agreementVersion)); + return false; + } + return true; + } + case GT -> { + if (version.compareTo(agreementVersion) <= 0) { + context.reportProblem(format("%s version %s must be at greater than the required version: %s", credentialType, version, agreementVersion)); + return false; + } + return true; + } + case GEQ -> { + if (version.compareTo(agreementVersion) < 0) { + context.reportProblem(format("%s version %s must be at least the required version: %s", credentialType, version, agreementVersion)); + return false; + } + return true; + } + default -> { + return false; + } + } + } + + /** + * Configures a new constraint instance. + */ + public static class Builder { + private final FrameworkAgreementConstraintFunction constraint; + + private Builder(String credentialType) { + constraint = new FrameworkAgreementConstraintFunction(credentialType); + } + + /** + * Ctor. + * + * @param credentialType the framework credential type required by the constraint instance. + * @return the builder + */ + public static Builder newInstance(String credentialType) { + return new Builder(credentialType); + } + + /** + * Sets the framework agreement type. + */ + public Builder agreementType(String agreementType) { + constraint.agreementType = agreementType; + return this; + } + + /** + * Sets the optional required agreement version. Equals, greater than, and greater than or equals operations are supported. + */ + public Builder agreementVersion(String version) { + constraint.agreementVersion = version; + return this; + } + + public FrameworkAgreementConstraintFunction build() { + requireNonNull(constraint.agreementType, "agreementType"); + return constraint; + } + } + + +} diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunction.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunction.java new file mode 100644 index 000000000..448cc6795 --- /dev/null +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunction.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.summary; + +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Operator; +import org.eclipse.edc.policy.model.Permission; +import org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces; +import org.eclipse.tractusx.edc.policy.cx.common.AbstractVpConstraintFunction; + +import java.util.Map; + +import static jakarta.json.JsonValue.ValueType.ARRAY; +import static jakarta.json.JsonValue.ValueType.OBJECT; +import static jakarta.json.JsonValue.ValueType.STRING; +import static java.lang.String.format; +import static java.util.Objects.requireNonNull; +import static org.eclipse.edc.policy.model.Operator.EQ; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.SUMMARY_CREDENTIAL_TYPE; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.VP_PROPERTY; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTypeFunctions.extractObjectsOfType; + + +/** + * Implements Catena-X policies by verifying policy constraints against the summary credential. + *

+ * Verifies the presence of an entry in the {@link #SUMMARY_CREDENTIAL_ITEMS} of a summary credential token. + */ +public class SummaryConstraintFunction extends AbstractVpConstraintFunction { + private static final String SUMMARY_CREDENTIAL_ITEMS = CredentialsNamespaces.CX_SUMMARY_NS + "/items"; + private static final String CREDENTIAL_SUBJECT = "credentialSubject"; + + private static final String ACTIVE = "active"; + + private final String summaryType; + + public SummaryConstraintFunction(String summaryType) { + super("Summary"); + requireNonNull(summaryType); + this.summaryType = summaryType; + } + + @Override + public boolean evaluate(Operator operator, Object rightValue, Permission rule, PolicyContext context) { + if (!validateOperator(operator, context, EQ)) { + return false; + } + + if (!validateRightOperand(ACTIVE, rightValue, context)) { + return false; + } + + var vp = (JsonObject) context.getParticipantAgent().getClaims().get(VP_PROPERTY); + if (!validatePresentation(vp, context)) { + return false; + } + + return extractObjectsOfType(SUMMARY_CREDENTIAL_TYPE, vp).anyMatch(credential -> hasSummaryType(credential, context)); + } + + /** + * Returns true if the summary credential has the item specified by {@link #summaryType}. + */ + private boolean hasSummaryType(JsonObject credential, PolicyContext context) { + var credentialSubject = extractCredentialSubject(credential, context); + if (credentialSubject == null) { + return false; + } + var items = credentialSubject.get(SUMMARY_CREDENTIAL_ITEMS); + + if (items == null || items.getValueType() != ARRAY) { + context.reportProblem(format("%s items not found in %s", errorPrefix, CREDENTIAL_SUBJECT)); + return false; + } + + if (items.asJsonArray().isEmpty()) { + context.reportProblem(format("%s empty %s items graph container", errorPrefix, CREDENTIAL_SUBJECT)); + return false; + } + + return items.asJsonArray().stream().filter(e -> e.getValueType() == OBJECT) + .flatMap(o -> o.asJsonObject().entrySet().stream()) + .anyMatch(this::matchSummaryType); + } + + /** + * Returns true if the entry is a string and matches the Json-Ld {@link #VALUE} type. + */ + private boolean matchSummaryType(Map.Entry e) { + return VALUE.equals(e.getKey()) && + e.getValue().getValueType() == STRING && + summaryType.equals(((JsonString) e.getValue()).getString()); + } + + +} diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProvider.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProvider.java new file mode 100644 index 000000000..a7f27fe8f --- /dev/null +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProvider.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.summary; + +import org.eclipse.edc.policy.engine.spi.PolicyEngine; +import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; +import org.eclipse.edc.policy.model.Permission; + +import java.util.Map; + +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.CATALOG_REQUEST_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.CATALOG_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.NEGOTIATION_REQUEST_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.NEGOTIATION_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.TRANSFER_PROCESS_REQUEST_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.TRANSFER_PROCESS_SCOPE; + +/** + * Registers {@link SummaryConstraintFunction} and {@link SummaryTokenPolicyFunction} instances with the runtime policy engine. + */ +public class SummaryConstraintFunctionsProvider { + + /** + * Mappings from policy constraint left operand values to the corresponding item value in the summary VP. + */ + static final Map CREDENTIAL_MAPPINGS = Map.of( + "Membership", "MembershipCredential", + "Dismantler", "DismantlerCredential", + "FrameworkAgreement.pcf", "PcfCredential", + "FrameworkAgreement.sustainability", "SustainabilityCredential", + "FrameworkAgreement.quality", "QualityCredential", + "FrameworkAgreement.traceability", "TraceabilityCredential", + "FrameworkAgreement.behavioraltwin", "BehaviorTwinCredential", + "BPN", "BpnCredential" + ); + + /** + * Configures and registers required summary functions with the policy engine. + */ + public static void registerFunctions(PolicyEngine engine) { + var tokenPolicyFunction = new SummaryTokenPolicyFunction(); + engine.registerPreValidator(CATALOG_REQUEST_SCOPE, tokenPolicyFunction); + engine.registerPreValidator(NEGOTIATION_REQUEST_SCOPE, tokenPolicyFunction); + engine.registerPreValidator(TRANSFER_PROCESS_REQUEST_SCOPE, tokenPolicyFunction); + + CREDENTIAL_MAPPINGS.forEach((constraintName, summaryType) -> { + + engine.registerFunction(CATALOG_SCOPE, + Permission.class, + constraintName, + new SummaryConstraintFunction(summaryType)); + + engine.registerFunction(NEGOTIATION_SCOPE, + Permission.class, + constraintName, + new SummaryConstraintFunction(summaryType)); + + engine.registerFunction(TRANSFER_PROCESS_SCOPE, + Permission.class, + constraintName, + new SummaryConstraintFunction(summaryType)); + }); + + } + + public static void registerBindings(RuleBindingRegistry registry) { + CREDENTIAL_MAPPINGS.forEach((constraintName, summaryType) -> { + registry.bind(constraintName, CATALOG_REQUEST_SCOPE); + registry.bind(constraintName, NEGOTIATION_REQUEST_SCOPE); + registry.bind(constraintName, TRANSFER_PROCESS_REQUEST_SCOPE); + registry.bind(constraintName, CATALOG_SCOPE); + registry.bind(constraintName, NEGOTIATION_SCOPE); + registry.bind(constraintName, TRANSFER_PROCESS_SCOPE); + }); + } + +} diff --git a/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryTokenPolicyFunction.java b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryTokenPolicyFunction.java new file mode 100644 index 000000000..693325e5d --- /dev/null +++ b/edc-extensions/cx-policy/src/main/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryTokenPolicyFunction.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.summary; + +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.iam.TokenParameters; + +import java.util.function.BiFunction; + +import static java.lang.String.format; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CX_SUMMARY_CREDENTIAL; + +/** + * Includes a summary credential in the token parameters. + */ +public class SummaryTokenPolicyFunction implements BiFunction { + + @Override + public Boolean apply(Policy policy, PolicyContext context) { + var params = context.getContextData(TokenParameters.Builder.class); + if (params == null) { + throw new EdcException(format("%s not set in policy context", TokenParameters.Builder.class.getName())); + } + params.additional(CX_SUMMARY_CREDENTIAL, CX_SUMMARY_CREDENTIAL); + return true; + } +} diff --git a/edc-extensions/cx-policy/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-extensions/cx-policy/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..eeb06425e --- /dev/null +++ b/edc-extensions/cx-policy/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,16 @@ +# +# Copyright (c) 2023 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 +# +# + +org.eclipse.tractusx.edc.policy.cx.CxPolicyExtension + diff --git a/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/common/AbstractVpConstraintFunctionTest.java b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/common/AbstractVpConstraintFunctionTest.java new file mode 100644 index 000000000..03df86e46 --- /dev/null +++ b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/common/AbstractVpConstraintFunctionTest.java @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.common; + +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Operator; +import org.eclipse.edc.policy.model.Permission; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.createObjectMapper; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.expand; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class AbstractVpConstraintFunctionTest { + private static final String FOO_CREDENTIAL = """ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "FooCredential" + ], + "issuer": "did:web:test", + "credentialSubject": { + "id": "did:web:test" + } + } + """; + private static final String PRESENTATION = """ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": "VerifiablePresentation" + } + """; + private AbstractVpConstraintFunction function; + private PolicyContext context; + + @Test + void verify_operators() { + assertThat(function.validateOperator(Operator.EQ, context, Operator.EQ)).isEqualTo(true); + } + + @Test + void verify_invalid_operators() { + assertThat(function.validateOperator(Operator.NEQ, context, Operator.EQ)).isEqualTo(false); + verify(context).reportProblem(anyString()); + } + + @Test + void verify_presentation() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(PRESENTATION, JsonObject.class), Map.of()); + + assertThat(function.validatePresentation(vp, context)).isTrue(); + + assertThat(function.validatePresentation(null, context)).isFalse(); + + assertThat(function.validatePresentation("invalid", context)).isFalse(); + + var array = Json.createArrayBuilder().build(); + assertThat(function.validatePresentation(array, context)).isFalse(); + } + + @Test + void verify_extract_credential_subject() throws JsonProcessingException { + var credential = expand(createObjectMapper().readValue(FOO_CREDENTIAL, JsonObject.class), Map.of()); + + var subject = function.extractCredentialSubject(credential, context); + + assertThat(subject).isNotNull(); + assertThat(((JsonString) subject.get("@id")).getString()).isEqualTo("did:web:test"); + } + + @BeforeEach + void setUp() { + context = mock(PolicyContext.class); + function = new AbstractVpConstraintFunction("FooCredential") { + @Override + public boolean evaluate(Operator operator, Object rightValue, Permission rule, PolicyContext context) { + throw new UnsupportedOperationException(); + } + }; + } +} diff --git a/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/FrameworkAgreementConstraintFunctionTest.java b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/FrameworkAgreementConstraintFunctionTest.java new file mode 100644 index 000000000..3cc5085af --- /dev/null +++ b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/FrameworkAgreementConstraintFunctionTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.framework; + +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.json.JsonObject; +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Permission; +import org.eclipse.edc.spi.agent.ParticipantAgent; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.policy.model.Operator.EQ; +import static org.eclipse.edc.policy.model.Operator.GEQ; +import static org.eclipse.edc.policy.model.Operator.GT; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CX_USE_CASE_NS_V1; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.VP_PROPERTY; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.createObjectMapper; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.expand; +import static org.eclipse.tractusx.edc.policy.cx.framework.PcfCredential.PCF_VP; +import static org.eclipse.tractusx.edc.policy.cx.framework.UseCaseContext.USE_CASE_CONTEXT; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +class FrameworkAgreementConstraintFunctionTest { + private static final Map CONTEXT_CACHE = Map.of(CX_USE_CASE_NS_V1, USE_CASE_CONTEXT); + private Permission permission; + private PolicyContext context; + + @Test + void verify_constraint() throws JsonProcessingException { + var function = FrameworkAgreementConstraintFunction.Builder + .newInstance("PcfCredential") + .agreementType("PcfAgreement") + .build(); + + setVpInContextVp(); + + var result = function.evaluate(EQ, "active", permission, context); + + assertThat(result).isTrue(); + } + + @Test + void verify_contract_version() throws JsonProcessingException { + var function = FrameworkAgreementConstraintFunction.Builder + .newInstance("PcfCredential") + .agreementType("PcfAgreement") + .agreementVersion("1.0.0") + .build(); + + setVpInContextVp(); + + var result = function.evaluate(EQ, "active", permission, context); + assertThat(result).isTrue(); + + result = function.evaluate(GEQ, "active", permission, context); + assertThat(result).isTrue(); + + result = function.evaluate(GT, "active", permission, context); + assertThat(result).isFalse(); // should fail because version is equal + } + + @Test + void verify_contract_version_gt_fail() throws JsonProcessingException { + var function = FrameworkAgreementConstraintFunction.Builder + .newInstance("PcfCredential") + .agreementType("PcfAgreement") + .agreementVersion("2.0.0") + .build(); + + setVpInContextVp(); + + var result = function.evaluate(GT, "active", permission, context); + assertThat(result).isFalse(); // should fail because version is equal + + verify(context, times(1)).reportProblem(Mockito.contains("version")); + } + + @Test + void verify_invalid_agreement_fail() throws JsonProcessingException { + var function = FrameworkAgreementConstraintFunction.Builder + .newInstance("PcfCredential") + .agreementType("UnknownAgreement") + .build(); + + setVpInContextVp(); + + var result = function.evaluate(EQ, "active", permission, context); + + assertThat(result).isFalse(); + + verify(context, times(1)).reportProblem(Mockito.contains("missing the usecase type")); + } + + @Test + void verify_no_credential_fail() { + var function = FrameworkAgreementConstraintFunction.Builder + .newInstance("PcfCredential") + .agreementType("PcfAgreement") + .build(); + + when(context.getParticipantAgent()).thenReturn(new ParticipantAgent(Map.of(), Map.of())); + + var result = function.evaluate(EQ, "active", permission, context); + + assertThat(result).isFalse(); + + verify(context, times(1)).reportProblem(Mockito.contains("VP not found")); + } + + @BeforeEach + void setUp() { + permission = Permission.Builder.newInstance().build(); + context = mock(PolicyContext.class); + } + + private void setVpInContextVp() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(PCF_VP, JsonObject.class), CONTEXT_CACHE); + when(context.getParticipantAgent()).thenReturn(new ParticipantAgent(Map.of(VP_PROPERTY, vp), Map.of())); + } + + +} diff --git a/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/PcfCredential.java b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/PcfCredential.java new file mode 100644 index 000000000..c9c0bbb1a --- /dev/null +++ b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/PcfCredential.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.framework; + +public interface PcfCredential { + + String PCF_VP = """ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/2023/catenax/credentials/usecase/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "PcfCredential" + ], + "issuer": "did:web:issuer.example.com", + "issuanceDate": "2023-06-02T12:00:00Z", + "expirationDate": "2022-06-16T18:56:59Z", + "credentialSubject": { + "id": "did:web:example.com", + "holderIdentifier": "BPN of holder", + "usecaseAgreement": { + "value": "PCF", + "type": "PcfAgreement", + "contractTemplate": "https://public.catena-x.org/contracts/pcf.v1.pdf", + "contractVersion": "1.0.0" + } + }, + "proof": { + "type": "Ed25519Signature2018", + "created": "2023-06-02T12:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:web:issuer.example.com#key-1", + "jws": "xxx" + } + } + ] + }"""; +} diff --git a/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/UseCaseContext.java b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/UseCaseContext.java new file mode 100644 index 000000000..249cd31ba --- /dev/null +++ b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/framework/UseCaseContext.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.framework; + +/** + * Defines the context for use case credentials. + */ +public interface UseCaseContext { + + String USE_CASE_CONTEXT = """ + { + "@context": { + "@version": 1.1, + "@protected": true, + "usecase": "https://w3id.org/2023/catenax/credentials/usecase/", + "id": "@id", + "type": "@type", + "usecaseAgreement": { + "@id": "usecase:usecaseAgreement", + "@context": { + "contractTemplate": { + "@id": "usecase:contractTemplate", + "@type": "https://schema.org/Text" + }, + "contractVersion": { + "@id": "usecase:contractVersion", + "@type": "https://schema.org/Text" + } + } + } + } + }"""; + + +} diff --git a/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionTest.java b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionTest.java new file mode 100644 index 000000000..44c1854a1 --- /dev/null +++ b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.summary; + +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.json.JsonObject; +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Permission; +import org.eclipse.edc.spi.agent.ParticipantAgent; +import org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.SummaryContext; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.policy.model.Operator.EQ; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CX_SUMMARY_NS_V1; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.VP_PROPERTY; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.createObjectMapper; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.expand; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.SummaryCredential.SUMMARY_VP; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class SummaryConstraintFunctionTest { + public static final String CX_QUALITY = "QualityCredential"; + private static final Map CONTEXT_CACHE = Map.of(CX_SUMMARY_NS_V1, SummaryContext.SUMMARY_CONTEXT); + private Permission permission; + private PolicyContext context; + + @Test + void verify_constraint_success() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(SUMMARY_VP, JsonObject.class), CONTEXT_CACHE); + + var function = new SummaryConstraintFunction(CX_QUALITY); + + when(context.getParticipantAgent()).thenReturn(new ParticipantAgent(Map.of(VP_PROPERTY, vp), Map.of())); + + var result = function.evaluate(EQ, "active", permission, context); + + assertThat(result).isTrue(); + + verify(context, atLeastOnce()).getParticipantAgent(); + } + + @BeforeEach + void setUp() { + permission = Permission.Builder.newInstance().build(); + context = mock(PolicyContext.class); + } +} diff --git a/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProviderTest.java b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProviderTest.java new file mode 100644 index 000000000..d3e22122e --- /dev/null +++ b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryConstraintFunctionsProviderTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.summary; + +import org.eclipse.edc.policy.engine.spi.PolicyEngine; +import org.eclipse.edc.policy.engine.spi.RuleBindingRegistry; +import org.eclipse.edc.policy.model.Permission; +import org.junit.jupiter.api.Test; + +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.CATALOG_REQUEST_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.CATALOG_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.NEGOTIATION_REQUEST_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.NEGOTIATION_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.TRANSFER_PROCESS_REQUEST_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.common.PolicyScopes.TRANSFER_PROCESS_SCOPE; +import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerBindings; +import static org.eclipse.tractusx.edc.policy.cx.summary.SummaryConstraintFunctionsProvider.registerFunctions; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +class SummaryConstraintFunctionsProviderTest { + + @Test + void verify_function_registrations() { + var policyEngine = mock(PolicyEngine.class); + + registerFunctions(policyEngine); + + assertTokenFunctionsRegistered(CATALOG_REQUEST_SCOPE, policyEngine); + assertTokenFunctionsRegistered(NEGOTIATION_REQUEST_SCOPE, policyEngine); + assertTokenFunctionsRegistered(TRANSFER_PROCESS_REQUEST_SCOPE, policyEngine); + + SummaryConstraintFunctionsProvider.CREDENTIAL_MAPPINGS.forEach((credentialName, summaryType) -> { + assertSummaryFunctionsRegistered(CATALOG_SCOPE, policyEngine, credentialName); + assertSummaryFunctionsRegistered(NEGOTIATION_SCOPE, policyEngine, credentialName); + assertSummaryFunctionsRegistered(TRANSFER_PROCESS_SCOPE, policyEngine, credentialName); + }); + } + + @Test + void verify_binding_registrations() { + var bindingRegistry = mock(RuleBindingRegistry.class); + + registerBindings(bindingRegistry); + + assertRuleTypeRegistered("Membership", bindingRegistry); + assertRuleTypeRegistered("Dismantler", bindingRegistry); + assertRuleTypeRegistered("FrameworkAgreement.pcf", bindingRegistry); + assertRuleTypeRegistered("FrameworkAgreement.sustainability", bindingRegistry); + assertRuleTypeRegistered("FrameworkAgreement.quality", bindingRegistry); + assertRuleTypeRegistered("FrameworkAgreement.traceability", bindingRegistry); + assertRuleTypeRegistered("FrameworkAgreement.behavioraltwin", bindingRegistry); + } + + private void assertTokenFunctionsRegistered(String scope, PolicyEngine policyEngine) { + verify(policyEngine, times(1)).registerPreValidator(eq(scope), any()); + } + + private void assertSummaryFunctionsRegistered(String scope, PolicyEngine policyEngine, String credentialName) { + verify(policyEngine, times(1)).registerFunction( + eq(scope), + eq(Permission.class), + eq(credentialName), + any(SummaryConstraintFunction.class)); + } + + private void assertRuleTypeRegistered(String ruleType, RuleBindingRegistry bindingRegistry) { + verify(bindingRegistry, times(1)).bind(ruleType, CATALOG_REQUEST_SCOPE); + verify(bindingRegistry, times(1)).bind(ruleType, CATALOG_SCOPE); + verify(bindingRegistry, times(1)).bind(ruleType, NEGOTIATION_REQUEST_SCOPE); + verify(bindingRegistry, times(1)).bind(ruleType, NEGOTIATION_SCOPE); + verify(bindingRegistry, times(1)).bind(ruleType, TRANSFER_PROCESS_REQUEST_SCOPE); + verify(bindingRegistry, times(1)).bind(ruleType, TRANSFER_PROCESS_SCOPE); + } + +} diff --git a/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryTokenPolicyFunctionTest.java b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryTokenPolicyFunctionTest.java new file mode 100644 index 000000000..d6d9a26ca --- /dev/null +++ b/edc-extensions/cx-policy/src/test/java/org/eclipse/tractusx/edc/policy/cx/summary/SummaryTokenPolicyFunctionTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.policy.cx.summary; + +import org.eclipse.edc.policy.engine.spi.PolicyContext; +import org.eclipse.edc.policy.model.Policy; +import org.eclipse.edc.spi.iam.TokenParameters; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CX_SUMMARY_CREDENTIAL; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +class SummaryTokenPolicyFunctionTest { + + @Test + void verify_add_credential() { + var function = new SummaryTokenPolicyFunction(); + + var context = mock(PolicyContext.class); + var builder = TokenParameters.Builder.newInstance().audience("aud"); + when(context.getContextData(eq(TokenParameters.Builder.class))).thenReturn(builder); + + var policy = Policy.Builder.newInstance().build(); + + function.apply(policy, context); + + assertThat(builder.build().getAdditional().containsKey(CX_SUMMARY_CREDENTIAL)).isTrue(); + } +} diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/build.gradle.kts b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/build.gradle.kts similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/build.gradle.kts rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/build.gradle.kts diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/DataPlaneProxyConsumerApiExtension.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/DataPlaneProxyConsumerApiExtension.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/DataPlaneProxyConsumerApiExtension.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/DataPlaneProxyConsumerApiExtension.java diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ClientErrorExceptionMapper.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ClientErrorExceptionMapper.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ClientErrorExceptionMapper.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ClientErrorExceptionMapper.java diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestApi.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestApi.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestApi.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestApi.java diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestController.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestController.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestController.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/ConsumerAssetRequestController.java diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/PreconditionFailedException.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/PreconditionFailedException.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/PreconditionFailedException.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/PreconditionFailedException.java diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequest.java diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension diff --git a/edc-dataplane/edc-dataplane-proxy-consumer-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequestTest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequestTest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-consumer-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequestTest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-consumer-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/consumer/api/asset/model/AssetRequestTest.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/build.gradle.kts b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/build.gradle.kts similarity index 90% rename from edc-dataplane/edc-dataplane-proxy-provider-api/build.gradle.kts rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/build.gradle.kts index 9a9158299..b331a5946 100644 --- a/edc-dataplane/edc-dataplane-proxy-provider-api/build.gradle.kts +++ b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/build.gradle.kts @@ -30,6 +30,6 @@ dependencies { implementation(libs.jakarta.rsApi) implementation(libs.nimbus.jwt) - implementation(project(":edc-dataplane:edc-dataplane-proxy-provider-spi")) + implementation(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-spi")) } diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/DataPlaneProxyProviderApiExtension.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/DataPlaneProxyProviderApiExtension.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/DataPlaneProxyProviderApiExtension.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/DataPlaneProxyProviderApiExtension.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayApi.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayApi.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayApi.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayApi.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayController.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayController.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayController.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/gateway/ProviderGatewayController.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelper.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelper.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelper.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelper.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension diff --git a/edc-dataplane/edc-dataplane-proxy-provider-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelperTest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelperTest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelperTest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-api/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/api/response/ResponseHelperTest.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/build.gradle.kts b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/build.gradle.kts similarity index 89% rename from edc-dataplane/edc-dataplane-proxy-provider-core/build.gradle.kts rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/build.gradle.kts index 338cab554..8ec7a9641 100644 --- a/edc-dataplane/edc-dataplane-proxy-provider-core/build.gradle.kts +++ b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/build.gradle.kts @@ -30,6 +30,6 @@ dependencies { implementation(libs.jakarta.rsApi) implementation(libs.nimbus.jwt) - implementation(project(":edc-dataplane:edc-dataplane-proxy-provider-spi")) + implementation(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-spi")) } diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/ProxyProviderCoreExtension.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/ProxyProviderCoreExtension.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/ProxyProviderCoreExtension.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/ProxyProviderCoreExtension.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImpl.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImpl.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImpl.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImpl.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandler.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandler.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandler.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandler.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParser.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParser.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParser.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParser.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoader.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoader.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoader.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoader.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImpl.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImpl.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImpl.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImpl.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImplTest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImplTest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImplTest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/AuthorizationHandlerRegistryImplTest.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandlerTest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandlerTest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandlerTest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/JwtAuthorizationHandlerTest.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParserTest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParserTest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParserTest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/RsaPublicKeyParserTest.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/TestTokens.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/TestTokens.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/TestTokens.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/auth/TestTokens.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoaderTest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoaderTest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoaderTest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationLoaderTest.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImplTest.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImplTest.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImplTest.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-core/src/test/java/org/eclipse/tractusx/edc/dataplane/proxy/provider/core/gateway/configuration/GatewayConfigurationRegistryImplTest.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-spi/build.gradle.kts b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/build.gradle.kts similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-spi/build.gradle.kts rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/build.gradle.kts diff --git a/edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationExtension.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationExtension.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationExtension.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationExtension.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandler.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandler.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandler.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandler.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandlerRegistry.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandlerRegistry.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandlerRegistry.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/authorization/AuthorizationHandlerRegistry.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfiguration.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfiguration.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfiguration.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfiguration.java diff --git a/edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfigurationRegistry.java b/edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfigurationRegistry.java similarity index 100% rename from edc-dataplane/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfigurationRegistry.java rename to edc-extensions/dataplane-proxy/edc-dataplane-proxy-provider-spi/src/main/java/org/eclipse/tractusx/edc/dataplane/proxy/spi/provider/gateway/configuration/GatewayConfigurationRegistry.java diff --git a/edc-extensions/hashicorp-vault/README.md b/edc-extensions/hashicorp-vault/README.md index c3964605b..f0e861b16 100644 --- a/edc-extensions/hashicorp-vault/README.md +++ b/edc-extensions/hashicorp-vault/README.md @@ -30,9 +30,9 @@ with level _WARNING_. --- -### Health Checks in Catena-X +### Health Checks -If your project uses the Catena-X HashiCorp Vault please set `edc.vault.hashicorp.health.check.standby.ok` to _true_. Otherwise the health check would fail if the Vault is in standby. +If your project uses the Tractus-X HashiCorp Vault please set `edc.vault.hashicorp.health.check.standby.ok` to _true_. Otherwise, the health check would fail if the Vault is in standby. ```plain # Logs of successful check with standby vault @@ -90,14 +90,14 @@ or edc.oauth.private.key.alias=my-daps-key ``` -## Example: Catena-X Argo CD Vault Configuration +## Example: Argo CD Vault Configuration ```properties ######### # Vault # ######### -edc.vault.hashicorp.url=https://vault.demo.catena-x.net +edc.vault.hashicorp.url=https://vault.demo.tractus-x.net # or even better configure token as k8 secret edc.vault.hashicorp.token= edc.vault.hashicorp.api.secret.path=/v1// @@ -107,6 +107,6 @@ edc.vault.hashicorp.health.check.standby.ok=true # E.g. OAuth Extension # ######################## -# from UI: secret stored in https://vault.demo.catena-x.net/ui/vault/secrets//show/my-daps-key +# from UI: secret stored in https://vault.demo.tractus-x.net/ui/vault/secrets//show/my-daps-key edc.oauth.private.key.alias=my-daps-key ``` diff --git a/edc-extensions/hashicorp-vault/build.gradle.kts b/edc-extensions/hashicorp-vault/build.gradle.kts index afc22687d..42b59548a 100644 --- a/edc-extensions/hashicorp-vault/build.gradle.kts +++ b/edc-extensions/hashicorp-vault/build.gradle.kts @@ -27,7 +27,7 @@ dependencies { implementation(libs.edc.junit) implementation(libs.bouncyCastle.bcpkixJdk18on) implementation(libs.okhttp) - implementation("org.testcontainers:vault:1.18.2") - implementation("org.testcontainers:junit-jupiter:1.18.2") + implementation("org.testcontainers:vault:1.18.3") + implementation("org.testcontainers:junit-jupiter:1.18.3") testImplementation(libs.mockito.inline) } diff --git a/edc-extensions/observability-api-customization/src/test/java/org/eclipse/tractusx/edc/api/observability/TxObservabilityApiControllerTest.java b/edc-extensions/observability-api-customization/src/test/java/org/eclipse/tractusx/edc/api/observability/TxObservabilityApiControllerTest.java index 2d0c1f570..5770ac4c6 100644 --- a/edc-extensions/observability-api-customization/src/test/java/org/eclipse/tractusx/edc/api/observability/TxObservabilityApiControllerTest.java +++ b/edc-extensions/observability-api-customization/src/test/java/org/eclipse/tractusx/edc/api/observability/TxObservabilityApiControllerTest.java @@ -22,6 +22,7 @@ import org.eclipse.edc.connector.spi.contractnegotiation.ContractNegotiationService; import org.eclipse.edc.connector.spi.policydefinition.PolicyDefinitionService; import org.eclipse.edc.connector.spi.transferprocess.TransferProcessService; +import org.eclipse.edc.jsonld.spi.JsonLd; import org.eclipse.edc.junit.annotations.ApiTest; import org.eclipse.edc.junit.extensions.EdcExtension; import org.eclipse.edc.spi.asset.DataAddressResolver; @@ -45,6 +46,35 @@ public class TxObservabilityApiControllerTest { private static final String API_KEY = "12345"; + // register all services that are required by the management API + protected void registerServiceMocks(EdcExtension extension) { + extension.registerServiceMock(DataAddressResolver.class, mock(DataAddressResolver.class)); + extension.registerServiceMock(CatalogService.class, mock(CatalogService.class)); + extension.registerServiceMock(ContractAgreementService.class, mock(ContractAgreementService.class)); + extension.registerServiceMock(ContractDefinitionService.class, mock(ContractDefinitionService.class)); + extension.registerServiceMock(AssetService.class, mock(AssetService.class)); + extension.registerServiceMock(ContractNegotiationService.class, mock(ContractNegotiationService.class)); + extension.registerServiceMock(PolicyDefinitionService.class, mock(PolicyDefinitionService.class)); + extension.registerServiceMock(TransferProcessService.class, mock(TransferProcessService.class)); + extension.registerServiceMock(JsonLd.class, mock(JsonLd.class)); + } + + static class BaseTest { + protected final int port = getFreePort(); + protected String basePath; + + protected BaseTest(String basePath) { + this.basePath = basePath; + } + + protected RequestSpecification baseRequest() { + return given() + .baseUri("http://localhost:" + port) + .basePath(basePath) + .when(); + } + } + @Nested @DisplayName("Allow unauthenticated access") class AllowsUnauthenticatedContextTest extends BaseTest { @@ -118,33 +148,4 @@ void defaultContext_whenNoAuthHeader_shouldReturn401(String path) { .body(notNullValue()); } } - - // register all services that are required by the management API - protected void registerServiceMocks(EdcExtension extension) { - extension.registerServiceMock(DataAddressResolver.class, mock(DataAddressResolver.class)); - extension.registerServiceMock(CatalogService.class, mock(CatalogService.class)); - extension.registerServiceMock(ContractAgreementService.class, mock(ContractAgreementService.class)); - extension.registerServiceMock(ContractDefinitionService.class, mock(ContractDefinitionService.class)); - extension.registerServiceMock(AssetService.class, mock(AssetService.class)); - extension.registerServiceMock(ContractNegotiationService.class, mock(ContractNegotiationService.class)); - extension.registerServiceMock(PolicyDefinitionService.class, mock(PolicyDefinitionService.class)); - extension.registerServiceMock(TransferProcessService.class, mock(TransferProcessService.class)); - } - - static class BaseTest { - protected final int port = getFreePort(); - protected String basePath; - - protected BaseTest(String basePath) { - this.basePath = basePath; - } - - protected RequestSpecification baseRequest() { - return given() - .baseUri("http://localhost:" + port) - .basePath(basePath) - .when(); - } - } - } diff --git a/edc-extensions/postgresql-migration/README.md b/edc-extensions/postgresql-migration/README.md index 73f94eb56..7a8b848c6 100644 --- a/edc-extensions/postgresql-migration/README.md +++ b/edc-extensions/postgresql-migration/README.md @@ -7,3 +7,15 @@ This extension applies SQL migrations to * contract-negotiation store * policy store * transfer-process store + +## Configuration + +| Key | Description | Mandatory | Default | +|:--------------------------------------------------------------------------|:-------------------------------------------------|-----------|----------| +| org.eclipse.tractusx.edc.postgresql.migration.asset.enabled | Enable migration for asset tables | | true | +| org.eclipse.tractusx.edc.postgresql.migration.contractdefinition.enabled | Enable migration for contract definition tables | | true | +| org.eclipse.tractusx.edc.postgresql.migration.contractnegotiation.enabled | Enable migration for contract negotiation tables | | true | +| org.eclipse.tractusx.edc.postgresql.migration.edr.enabled | Enable migration for edr tables | | true | +| org.eclipse.tractusx.edc.postgresql.migration.policy.enabled | Enable migration for policy tables | | true | +| org.eclipse.tractusx.edc.postgresql.migration.transferprocess.enabled | Enable migration for transfer process tables | | true | +| org.eclipse.tractusx.edc.postgresql.migration.schema | The DB schema to be used during migration | | "public" | diff --git a/edc-extensions/postgresql-migration/build.gradle.kts b/edc-extensions/postgresql-migration/build.gradle.kts index 09d549b82..3ba3449de 100644 --- a/edc-extensions/postgresql-migration/build.gradle.kts +++ b/edc-extensions/postgresql-migration/build.gradle.kts @@ -30,5 +30,5 @@ dependencies { implementation(libs.edc.sql.core) runtimeOnly(libs.postgres) - implementation("org.flywaydb:flyway-core:9.19.1") + implementation("org.flywaydb:flyway-core:9.20.0") } diff --git a/edc-extensions/postgresql-migration/src/main/java/org/eclipse/tractusx/edc/postgresql/migration/AbstractPostgresqlMigrationExtension.java b/edc-extensions/postgresql-migration/src/main/java/org/eclipse/tractusx/edc/postgresql/migration/AbstractPostgresqlMigrationExtension.java index 722518e5f..e069ca128 100644 --- a/edc-extensions/postgresql-migration/src/main/java/org/eclipse/tractusx/edc/postgresql/migration/AbstractPostgresqlMigrationExtension.java +++ b/edc-extensions/postgresql-migration/src/main/java/org/eclipse/tractusx/edc/postgresql/migration/AbstractPostgresqlMigrationExtension.java @@ -53,6 +53,8 @@ public void initialize(final ServiceExtensionContext context) { boolean enabled = context.getConfig() .getBoolean(String.format("org.eclipse.tractusx.edc.postgresql.migration.%s.enabled", subSystemName), true); + String schema = context.getConfig() + .getString("org.eclipse.tractusx.edc.postgresql.migration.schema", "public"); if (!enabled) { return; @@ -79,6 +81,7 @@ public void initialize(final ServiceExtensionContext context) { .dataSource(dataSource) .table(schemaHistoryTableName) .locations(migrationsLocation) + .defaultSchema(schema) .load(); flyway.baseline(); diff --git a/edc-extensions/provision-additional-headers/src/test/java/org/eclipse/tractusx/edc/provision/additionalheaders/ProvisionAdditionalHeadersExtensionTest.java b/edc-extensions/provision-additional-headers/src/test/java/org/eclipse/tractusx/edc/provision/additionalheaders/ProvisionAdditionalHeadersExtensionTest.java index 723398a3e..ad88b6bc2 100644 --- a/edc-extensions/provision-additional-headers/src/test/java/org/eclipse/tractusx/edc/provision/additionalheaders/ProvisionAdditionalHeadersExtensionTest.java +++ b/edc-extensions/provision-additional-headers/src/test/java/org/eclipse/tractusx/edc/provision/additionalheaders/ProvisionAdditionalHeadersExtensionTest.java @@ -101,7 +101,6 @@ void shouldPutContractIdAsHeaderInDataAddress( var transferMessage = TransferRequestMessage.Builder.newInstance() .id("id") .protocol("protocol") - .assetId("assetId") .contractId("1:assetId:aContractId") .dataDestination(DataAddress.Builder.newInstance().type("HttpProxy").build()) .callbackAddress("callbackAddress") diff --git a/edc-extensions/ssi/jws2020-crypto-suite/README.md b/edc-extensions/ssi/jws2020-crypto-suite/README.md new file mode 100644 index 000000000..4a11e93dd --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/README.md @@ -0,0 +1,70 @@ +# JsonWebSignature2020 + +This module extends the [iron-verifiable-credentials library](https://github.com/filip26/iron-verifiable-credentials), +which we use in conjunction with [titanium-ld](https://github.com/filip26/titanium-json-ld/) with an implementation for +the [JsonWebSignature2020](https://www.w3.org/community/reports/credentials/CG-FINAL-lds-jws2020-20220721) crypto suite. + +## Technical aspects + +This implementation is actually mostly glue code between the `iron-verifiable-credentials` lib and the +well-known [Nimbus JOSE lib](https://connect2id.com/products/nimbus-jose-jwt), as all cryptographic primitives are taken +from Nimbus. + +VerifiableCredentials and VerifiablePresentations are processed as JSON(-LD) objects, so some familiarity with JSON-LD +is required. +The entrypoint into the cryptographic suite is the `Vc` class, which allows signing/issuing and verifying JSON-LD +structures. The following samples use explicit types for clarity. These are just some illustrative examples, please +check the `IssuerTests` and the `VerifierTests` for more comprehensive explanations. + +### Sign a VC + +```java +JwsSignature2020Suite suite = new JwsSignature2020Suite(JacksonJsonLd.createObjectMapper()); +JsonObject vc = createVcAsJsonLd(); +JWK keyPair = createKeyPairAsJwk(); +JwkMethod signKeys = new JwkMethod(id,type,controller,keyPair); + +var options = suite.createOptions() + .created(Instant.now()) + .verificationMethod(signKeys) // embeds the proof + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + +Issuer signedVc = Vc.sign(vc, signKeys, options); + +JsonObject compacted = IssuerCompat.compact(signedVc); +``` + +### Verify a VC + +```java +JwsSignature2020Suite suite = new JwsSignature2020Suite(JacksonJsonLd.createObjectMapper()); +JsonObject vc = readSignedVc(); +Verifier result = Vc.verify(vc, suite); + +try { + result.isValid(); +} catch(VerificationError error) { + //handle +} +``` + +## Limitations & Known Issues + +Java 17 [dropped support](https://connect2id.com/products/nimbus-jose-jwt/examples/jwt-with-es256k-signature) for +the `secp256k1` curve. Alternatively, the BouncyCastle JCA provider could be used. +For this implementation, we chose to forego this at the benefit of a smaller library footprint. There is plenty of other +curves to choose from. + +On a similar note, support for Octet Keypairs (`"OKP"`) has not yet been added to the standard Java JCA, thus an +additional dependency `tink` is needed, +check [here](https://connect2id.com/products/nimbus-jose-jwt/examples/jwk-generation#okp) for details. If that is not +acceptable to you, please add a dependency exclusion to your build script. + +`iron-verifiable-credentials` is not 100% agnostic toward its crypto suites, for example there is +a [hard-coded context](https://github.com/filip26/iron-verifiable-credentials/blob/82d13326c5f64a0f38c75d417ffc263febfd970d/src/main/java/com/apicatalog/vc/processor/Issuer.java#L122) +added to the compacted JSON-LD, which is incorrect. It doesn't negatively impact the resulting JSON-LD, other than +possibly affecting processing times, but unfortunately it also makes it impossible to add more contexts, such +as https://w3id.org/security/suites/jws-2020/v1. We mitigated this with +the [`IssuerCompat.java`](./src/main/java/org/eclipse/edc/security/signature/jws2020/IssuerCompat.java), which should be +used +for compaction. diff --git a/edc-extensions/ssi/jws2020-crypto-suite/build.gradle.kts b/edc-extensions/ssi/jws2020-crypto-suite/build.gradle.kts new file mode 100644 index 000000000..9694fcc9f --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/build.gradle.kts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 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` +} + +dependencies { + implementation(libs.edc.spi.jwt) + implementation(libs.nimbus.jwt) + implementation(libs.edc.spi.jsonld) + implementation(libs.edc.jsonld) + implementation(libs.edc.util) + // used for the Ed25519 Verifier in conjunction with OctetKeyPairs (OKP) + runtimeOnly(libs.tink) + implementation(libs.jakartaJson) + + implementation(libs.apicatalog.iron.vc) { + exclude("com.github.multiformats") + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/ByteArrayAdapter.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/ByteArrayAdapter.java new file mode 100644 index 000000000..02c98fc20 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/ByteArrayAdapter.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.jsonld.lang.Keywords; +import com.apicatalog.ld.schema.adapter.LdValueAdapter; +import jakarta.json.Json; +import jakarta.json.JsonValue; +import org.eclipse.edc.jsonld.spi.JsonLdKeywords; + +class ByteArrayAdapter implements LdValueAdapter { + @Override + public byte[] read(JsonValue value) { + if (value.getValueType().equals(JsonValue.ValueType.OBJECT)) { + var obj = value.asJsonObject(); + return obj.getString(JsonLdKeywords.VALUE).getBytes(); + } + return value.toString().getBytes(); + } + + @Override + public JsonValue write(byte[] value) { + return Json.createObjectBuilder() + .add(Keywords.VALUE, new String(value)) + .build(); + } + +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/IssuerCompat.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/IssuerCompat.java new file mode 100644 index 000000000..ab99e8081 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/IssuerCompat.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.jsonld.JsonLd; +import com.apicatalog.jsonld.JsonLdError; +import com.apicatalog.jsonld.document.Document; +import com.apicatalog.jsonld.document.JsonDocument; +import com.apicatalog.jsonld.loader.DocumentLoader; +import com.apicatalog.ld.DocumentError; +import com.apicatalog.ld.signature.SigningError; +import com.apicatalog.vc.processor.Issuer; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import org.eclipse.edc.util.reflection.ReflectionUtil; + +import java.net.URI; +import java.util.Arrays; + +/** + * The {@link Issuer} adds the context, but currently that adds hard-coded {@code "https://w3id.org/security/suites/ed25519-2020/v1"}. + * For the Jwk2020 suite we need that to be {@code "https://w3id.org/security/suites/jws-2020/v1"}, so as a temporary workaround we do not + * use {@link Issuer#getCompacted()}, but rather use {@link IssuerCompat#compact(Issuer, String...)}. + */ +public class IssuerCompat { + /** + * Compacts the JSON structure represented by the {@link Issuer} by delegating to {@link JsonLd#compact(Document, URI)}. Note that before compacting, the JSON-LD is expanded, signed, all additional contexts are added + * and then compacted. + *

+ * By default, the following contexts are added automatically: + *

    + *
  • https://www.w3.org/2018/credentials/v1
  • + *
  • https://w3id.org/security/suites/jws-2020/v1
  • + *
+ * + * @param issuer The {@link Issuer} + * @param additionalContexts Any additional context URIs that should be used for compaction. For Jws2020 it is highly likely that + * @return a JSON-LD structure in compacted format that contains the signed content (e.g. a VC). + */ + public static JsonObject compact(Issuer issuer, String... additionalContexts) { + try { + var expanded = issuer.getExpanded(); + var arrayBuilder = Json.createArrayBuilder(); + Arrays.stream(additionalContexts).forEach(arrayBuilder::add); + var context = arrayBuilder + .add("https://www.w3.org/2018/credentials/v1") + .add("https://w3id.org/security/suites/jws-2020/v1") + .add("https://www.w3.org/ns/did/v1") + .build(); + return JsonLd.compact(JsonDocument.of(expanded), JsonDocument.of(context)).loader(getLoader(issuer)) + .get(); + + } catch (JsonLdError | SigningError | DocumentError e) { + throw new RuntimeException(e); + } + } + + /** + * rather crude hack to obtain the {@link Issuer}'s loader. The EDC util we're using here basically fetches the declared field recursively. + * + * @see ReflectionUtil#getFieldValue(String, Object) + */ + private static DocumentLoader getLoader(Issuer issuer) { + return ReflectionUtil.getFieldValue("loader", issuer); + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JsonAdapter.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JsonAdapter.java new file mode 100644 index 000000000..364967a4a --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JsonAdapter.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.schema.adapter.LdValueAdapter; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonValue; +import org.eclipse.edc.jsonld.spi.JsonLdKeywords; + +import java.util.Map; + +class JsonAdapter implements LdValueAdapter { + private final ObjectMapper mapper; + + JsonAdapter(ObjectMapper mapper) { + this.mapper = mapper; + } + + @Override + public Object read(JsonValue value) { + var input = value; + if (value instanceof JsonObject) { + var jo = value.asJsonObject(); + input = jo.get(JsonLdKeywords.VALUE); + } + return mapper.convertValue(input, Object.class); + } + + @Override + public JsonValue write(Object value) { + if (value instanceof Map) { + var jo = Json.createObjectBuilder(); + jo.add(JsonLdKeywords.VALUE, Json.createObjectBuilder((Map) value)); + jo.add(JsonLdKeywords.TYPE, JsonLdKeywords.JSON); + return mapper.convertValue(jo.build(), JsonValue.class); + } + return mapper.convertValue(value, JsonValue.class); + } + +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwkAdapter.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwkAdapter.java new file mode 100644 index 000000000..9a86657d6 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwkAdapter.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.schema.LdObject; +import com.apicatalog.ld.schema.LdTerm; +import com.apicatalog.ld.schema.adapter.LdValueAdapter; +import com.apicatalog.ld.signature.method.VerificationMethod; +import com.apicatalog.vc.integrity.DataIntegrity; + +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import static org.eclipse.edc.security.signature.jws2020.Jws2020Schema.JWK_PRIVATE_KEY; +import static org.eclipse.edc.security.signature.jws2020.Jws2020Schema.JWK_PUBLIC_KEY; + +/** + * Adapter that converts between {@link LdObject} and {@link VerificationMethod} + */ +class JwkAdapter implements LdValueAdapter { + + @Override + public VerificationMethod read(LdObject value) { + URI id = value.value(LdTerm.ID); + URI type = value.value(LdTerm.TYPE); + URI controller = value.value(DataIntegrity.CONTROLLER); + var keyProperty = getKeyProperty(value); + var jwk = KeyFactory.create(keyProperty); + return new JwkMethod(id, type, controller, jwk); + } + + + @Override + public LdObject write(VerificationMethod method) { + var result = new HashMap(); + Objects.requireNonNull(method, "VerificationMethod cannot be null!"); + + if (method.id() != null) { + result.put(LdTerm.ID.uri(), method.id()); + } + if (method.type() != null) { + result.put(LdTerm.TYPE.uri(), method.type()); + } + if (method.controller() != null) { + result.put(DataIntegrity.CONTROLLER.uri(), method.controller()); + } + + if (method instanceof JwkMethod ecKeyPair) { + if (ecKeyPair.keyPair() != null) { + result.put(JWK_PUBLIC_KEY.uri(), ecKeyPair.keyPair().toPublicJWK().toJSONObject()); + } + } + + return new LdObject(result); + } + + private Map getKeyProperty(LdObject value) { + if (value.contains(JWK_PRIVATE_KEY)) { + return value.value(JWK_PRIVATE_KEY); + } + return value.value(JWK_PUBLIC_KEY); + } + +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwkMethod.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwkMethod.java new file mode 100644 index 000000000..9d94317eb --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwkMethod.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.signature.key.KeyPair; +import com.nimbusds.jose.jwk.JWK; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.net.URI; + +record JwkMethod(URI id, URI type, URI controller, JWK keyPair) implements KeyPair { + + @Override + public byte[] privateKey() { + return keyPair != null ? serializeKeyPair(keyPair) : null; + } + + + @Override + public byte[] publicKey() { + return keyPair != null ? serializeKeyPair(keyPair.toPublicJWK()) : null; + } + + private byte[] serializeKeyPair(JWK keyPair) { + try { + var bos = new ByteArrayOutputStream(); + var out = new ObjectOutputStream(bos); + out.writeObject(keyPair); + return bos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020CryptoSuite.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020CryptoSuite.java new file mode 100644 index 000000000..09de46660 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020CryptoSuite.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.schema.LdTerm; +import com.apicatalog.ld.signature.CryptoSuite; +import com.apicatalog.ld.signature.primitive.MessageDigest; +import com.apicatalog.ld.signature.primitive.Urdna2015; + +class Jws2020CryptoSuite extends CryptoSuite { + Jws2020CryptoSuite(LdTerm id) { + super(id, new Urdna2015(), new MessageDigest("SHA-256"), new Jws2020SignatureProvider()); + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020Schema.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020Schema.java new file mode 100644 index 000000000..83915b078 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020Schema.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.schema.LdProperty; +import com.apicatalog.ld.schema.LdSchema; +import com.apicatalog.ld.schema.LdTerm; +import com.apicatalog.vc.VcTag; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.time.Instant; + +import static com.apicatalog.ld.schema.LdSchema.id; +import static com.apicatalog.ld.schema.LdSchema.link; +import static com.apicatalog.ld.schema.LdSchema.object; +import static com.apicatalog.ld.schema.LdSchema.property; +import static com.apicatalog.ld.schema.LdSchema.string; +import static com.apicatalog.ld.schema.LdSchema.type; +import static com.apicatalog.ld.schema.LdSchema.xsdDateTime; +import static com.apicatalog.vc.VcSchema.proof; +import static com.apicatalog.vc.VcSchema.verificationMethod; +import static com.apicatalog.vc.VcVocab.SECURITY_VOCAB; +import static com.apicatalog.vc.integrity.DataIntegrity.CHALLENGE; +import static com.apicatalog.vc.integrity.DataIntegrity.CREATED; +import static com.apicatalog.vc.integrity.DataIntegrity.DOMAIN; +import static com.apicatalog.vc.integrity.DataIntegrity.PURPOSE; +import static com.apicatalog.vc.integrity.DataIntegrity.VERIFICATION_METHOD; + +/** + * Internal class that encapsulates all JSON schemas that are relevant for JWS2020, such as the structure of the verification method + */ +class Jws2020Schema { + public static final LdTerm JSON_WEB_KEY_TYPE = LdTerm.create("JsonWebKey2020", SECURITY_VOCAB); + public static final LdTerm JSON_WEB_SIGNATURE_TYPE = LdTerm.create("JsonWebSignature2020", SECURITY_VOCAB); + public static final LdTerm JWS = LdTerm.create("jws", SECURITY_VOCAB); + public static final LdTerm CONTROLLER = LdTerm.create("controller", SECURITY_VOCAB); + public static final LdTerm JWK_PRIVATE_KEY = LdTerm.create("privateKeyJwk", SECURITY_VOCAB); + public static final LdTerm JWK_PUBLIC_KEY = LdTerm.create("publicKeyJwk", SECURITY_VOCAB); + + + /** + * Creates an {@link LdSchema} for the verification method object of JWS2020, which looks roughly like this: + *
+     *     "verificationMethod": [
+     *       {
+     *         "id": "#ovsDKYBjFemIy8DVhc-w2LSi8CvXMw2AYDzHj04yxkc",
+     *         "type": "JsonWebKey2020",
+     *         "controller": "https://example.com/issuer/123",
+     *         "publicKeyJwk": {
+     *           "kty": "OKP",
+     *           "crv": "Ed25519",
+     *           "x": "CV-aGlld3nVdgnhoZK0D36Wk-9aIMlZjZOK2XhPMnkQ"
+     *         }
+     *       }
+     *     ],
+     * 
+ * + * @param mapper The object mapper that is used to deserialize the {@code publicKeyJwk} part. + * @return The {@link LdSchema} that represents the above structure. Never null. + */ + public static LdSchema create(ObjectMapper mapper) { + return proof( + type(JSON_WEB_SIGNATURE_TYPE).required(), + property(CREATED, xsdDateTime()) + .test(created -> Instant.now().isAfter(created)) + .required(), + property(CONTROLLER, link()), + property(PURPOSE, link()).required(), + verificationMethod(VERIFICATION_METHOD, getVerificationMethod(mapper).map(new JwkAdapter())).required(), + property(DOMAIN, string()) + .test((domain, params) -> !params.containsKey(DOMAIN.name()) || params.get(DOMAIN.name()).equals(domain)), + property(CHALLENGE, string()), + property(JWS, new ByteArrayAdapter(), VcTag.ProofValue.name()) + ); + } + + private static LdSchema getVerificationMethod(ObjectMapper mapper) { + return jsonWebKeySchema(mapper); + } + + private static LdSchema jsonWebKeySchema(ObjectMapper mapper) { + return new LdSchema( + object( + id().required(), + type(JSON_WEB_KEY_TYPE), + property(CONTROLLER, link()), + jwkPublicKey(mapper) + )); + } + + private static LdProperty jwkPublicKey(ObjectMapper mapper) { + return property(JWK_PUBLIC_KEY, new JsonAdapter(mapper)); + } + + private static LdProperty jwkPrivateKey(ObjectMapper mapper) { + return property(JWK_PRIVATE_KEY, new JsonAdapter(mapper)); + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020SignatureProvider.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020SignatureProvider.java new file mode 100644 index 000000000..b1bc11800 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/Jws2020SignatureProvider.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.signature.KeyGenError; +import com.apicatalog.ld.signature.SigningError; +import com.apicatalog.ld.signature.VerificationError; +import com.apicatalog.ld.signature.algorithm.SignatureAlgorithm; +import com.apicatalog.ld.signature.key.KeyPair; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.JWSObject; +import com.nimbusds.jose.Payload; +import com.nimbusds.jose.jwk.Curve; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.OctetKeyPair; +import com.nimbusds.jose.jwk.RSAKey; +import org.eclipse.edc.spi.EdcException; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.text.ParseException; +import java.util.Collections; + +class Jws2020SignatureProvider implements SignatureAlgorithm { + + @Override + public void verify(byte[] publicKey, byte[] signature, byte[] data) throws VerificationError { + + try { + var jwk = deserialize(publicKey); + if (jwk == null) { + throw new UnsupportedOperationException("Cannot deserialize public key, expected JWK format"); + } + var verifier = KeyFactory.createVerifier(jwk); + + var detachedPayload = new Payload(data); + var jws = new String(signature); + + var parsedJwsObject = JWSObject.parse(jws, detachedPayload); + var isValid = parsedJwsObject.verify(verifier); + + if (!isValid) { + throw new VerificationError(VerificationError.Code.InvalidSignature); + } + + } catch (JOSEException | ParseException e) { + throw new VerificationError(VerificationError.Code.InvalidSignature, e); + } + } + + @Override + public byte[] sign(byte[] privateKey, byte[] data) throws SigningError { + + try { + var keyPair = deserialize(privateKey); + if (keyPair == null) { + throw new UnsupportedOperationException("Cannot deserialize key pair, expected JWK format"); + } + // Create and sign JWS + JWSHeader header = new JWSHeader.Builder(from(keyPair)) + .base64URLEncodePayload(false) + .criticalParams(Collections.singleton("b64")) + .build(); + + var detachedPayload = new Payload(data); + var jwsObject = new JWSObject(header, detachedPayload); + jwsObject.sign(KeyFactory.createSigner(keyPair)); + + boolean isDetached = true; + String jws = jwsObject.serialize(isDetached); + return jws.getBytes(); + + } catch (JOSEException e) { + throw new SigningError(SigningError.Code.UnsupportedCryptoSuite, e); + } + } + + @Override + public KeyPair keygen(int length) throws KeyGenError { + return null; + } + + /** + * Attempt to determine the {@link JWSAlgorithm} from the curve that is being used in the ECKey pair + */ + private JWSAlgorithm from(JWK keyPair) { + if (keyPair instanceof ECKey eckey) { + var jwsAlgorithm = JWSAlgorithm.Family.EC.stream() + .filter(algo -> Curve.forJWSAlgorithm(algo).contains(eckey.getCurve())) + .findFirst(); + return jwsAlgorithm.orElseThrow(() -> new EdcException("Could not determine JWSAlgorithm for Curve " + eckey.getCurve())); + } else if (keyPair instanceof OctetKeyPair okp) { + var jwsAlgorithm = JWSAlgorithm.Family.ED.stream() + .filter(algo -> Curve.forJWSAlgorithm(algo).contains(okp.getCurve())) + .findFirst(); + return jwsAlgorithm.orElseThrow(() -> new EdcException("Could not determine JWSAlgorithm for Curve " + okp.getCurve())); + } else if (keyPair instanceof RSAKey) { + return JWSAlgorithm.RS512; + } + return null; + } + + private JWK deserialize(byte[] privateKey) { + ByteArrayInputStream bis = new ByteArrayInputStream(privateKey); + try { + ObjectInputStream in = new ObjectInputStream(bis); + return (JWK) in.readObject(); + } catch (IOException | ClassNotFoundException e) { + return null; + } + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwsSignature2020Suite.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwsSignature2020Suite.java new file mode 100644 index 000000000..fd515dd3b --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwsSignature2020Suite.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.schema.LdSchema; +import com.apicatalog.ld.schema.LdTerm; +import com.apicatalog.ld.signature.CryptoSuite; +import com.apicatalog.ld.signature.SignatureSuite; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; + +import java.net.URI; + +/** + * {@link SignatureSuite} that provides cryptographic facilities and a key schema for Json Web Signature 2020. + */ +public final class JwsSignature2020Suite implements SignatureSuite { + static final URI CONTEXT = URI.create("https://w3id.org/security/suites/jws-2020/v1"); + private final Jws2020CryptoSuite cryptoSuite; + private final ObjectMapper mapper; + + /** + * Creates a new {@link JwsSignature2020Suite} using an object mapper. That mapper is needed because parts of the schema are plain JSON. + * + * @param mapper a JSON-aware {@link ObjectMapper}, e.g. using {@link JacksonJsonLd#createObjectMapper()} + * @see Jws2020Schema + */ + public JwsSignature2020Suite(ObjectMapper mapper) { + this.mapper = mapper; + cryptoSuite = new Jws2020CryptoSuite(LdTerm.ID); + } + + @Override + public LdTerm getId() { + return Jws2020Schema.JSON_WEB_SIGNATURE_TYPE; + } + + @Override + public URI getContext() { + return CONTEXT; + } + + @Override + public LdSchema getSchema() { + return Jws2020Schema.create(mapper); + } + + @Override + public CryptoSuite getCryptoSuite() { + return cryptoSuite; + } + + @Override + public JwsSignatureProofOptions createOptions() { + return new JwsSignatureProofOptions(this); + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwsSignatureProofOptions.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwsSignatureProofOptions.java new file mode 100644 index 000000000..70c006b92 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/JwsSignatureProofOptions.java @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.vc.integrity.DataIntegrityProofOptions; + +/** + * Proof options for Jws2020 + */ +public class JwsSignatureProofOptions extends DataIntegrityProofOptions { + /** + * Create a new proof options instance + * + * @param suite The {@link JwsSignature2020Suite} for which the options are created. + */ + public JwsSignatureProofOptions(JwsSignature2020Suite suite) { + super(suite); + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/KeyFactory.java b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/KeyFactory.java new file mode 100644 index 000000000..f66cfa7f5 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/main/java/org/eclipse/edc/security/signature/jws2020/KeyFactory.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSSigner; +import com.nimbusds.jose.JWSVerifier; +import com.nimbusds.jose.crypto.ECDSASigner; +import com.nimbusds.jose.crypto.ECDSAVerifier; +import com.nimbusds.jose.crypto.Ed25519Signer; +import com.nimbusds.jose.crypto.Ed25519Verifier; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.crypto.RSASSAVerifier; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.OctetKeyPair; +import com.nimbusds.jose.jwk.RSAKey; + +import java.text.ParseException; +import java.util.Map; +import java.util.Objects; + +import static java.lang.String.format; + +/** + * Utility class that has two basic duties: + *
    + *
  • Create cryptographic keys represented in JWK format ({@link JWK}) out of JSON or JSON-like objects
  • + *
  • Create {@link JWSSigner}s and {@link JWSVerifier}s for any given key represented in {@link JWK} format.
  • + *
+ *

+ * For this, the well-known Nimbus JOSE+JWT library is used. + */ +public class KeyFactory { + + /** + * Creates a {@link JWK} out of a map that represents a JSON structure. + * + * @param jsonObject The map containing the JSON + * @return the corresponding key. + * @throws RuntimeException if the JSON was malformed, or the JWK type was unknown. Typically, this wraps a {@link ParseException} + */ + public static JWK create(Map jsonObject) { + if (jsonObject == null) return null; + try { + return JWK.parse(jsonObject); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * Creates a {@link JWK} out of a JSON string containing the key properties + * + * @param json The string containing plain JSON + * @return the corresponding key. + * @throws RuntimeException if the JSON was malformed, or the JWK type was unknown. Typically, this wraps a {@link ParseException} + */ + public static JWK create(String json) { + if (json == null) return null; + try { + return JWK.parse(json); + } catch (ParseException e) { + throw new RuntimeException(e); + } + } + + /** + * Creates a {@link JWSVerifier} from the base class {@link JWK}. Currently only supports EC, OKP and RSA keys. + * + * @param jwk The {@link JWK} for which the {@link JWSVerifier} is to be created. + * @return the {@link JWSVerifier} + * @throws UnsupportedOperationException if the verifier could not be created, in which case the root cause would be {@link JOSEException} + */ + public static JWSVerifier createVerifier(JWK jwk) { + Objects.requireNonNull(jwk, "jwk cannot be null"); + var value = jwk.getKeyType().getValue(); + try { + return switch (value) { + case "EC" -> new ECDSAVerifier((ECKey) jwk); + case "OKP" -> new Ed25519Verifier((OctetKeyPair) jwk); + case "RSA" -> new RSASSAVerifier((RSAKey) jwk); + default -> + throw new UnsupportedOperationException(format("Cannot create JWSVerifier for JWK-type [%s], currently only supporting EC, OKP and RSA", value)); + }; + } catch (JOSEException ex) { + throw new UnsupportedOperationException(ex); + } + } + + /** + * Creates a {@link JWSSigner} from the base class {@link JWK}. Currently only supports EC, OKP and RSA keys. + * + * @param jwk The {@link JWK} for which the {@link JWSSigner} is to be created. + * @return the {@link JWSSigner} + * @throws UnsupportedOperationException if the signer could not be created, in which case the root cause would be {@link JOSEException} + */ + public static JWSSigner createSigner(JWK jwk) { + var value = jwk.getKeyType().getValue(); + try { + return switch (value) { + case "EC" -> new ECDSASigner((ECKey) jwk); + case "OKP" -> new Ed25519Signer((OctetKeyPair) jwk); + case "RSA" -> new RSASSASigner((RSAKey) jwk); + default -> + throw new UnsupportedOperationException(format("Cannot create JWSVerifier for JWK-type [%s], currently only supporting EC, OKP and RSA", value)); + }; + } catch (JOSEException ex) { + throw new UnsupportedOperationException(ex); + } + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/IssuerTests.java b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/IssuerTests.java new file mode 100644 index 000000000..2bdc15b8e --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/IssuerTests.java @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.jsonld.loader.SchemeRouter; +import com.apicatalog.ld.DocumentError; +import com.apicatalog.ld.signature.SigningError; +import com.apicatalog.vc.Vc; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.jwk.Curve; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.net.URI; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.time.Instant; +import java.util.Date; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.security.signature.jws2020.TestFunctions.createKeyPair; +import static org.eclipse.edc.security.signature.jws2020.TestFunctions.readResourceAsJson; +import static org.eclipse.edc.security.signature.jws2020.TestFunctions.readResourceAsString; + +class IssuerTests { + + private final JwsSignature2020Suite jws2020suite = new JwsSignature2020Suite(JacksonJsonLd.createObjectMapper()); + //used to load remote data from a local directory + private final TestResourcesLoader loader = new TestResourcesLoader("https://org.eclipse.tractusx/", "jws2020/issuing/", SchemeRouter.defaultInstance()); + + @DisplayName("t0001: a simple credential to sign (EC Key)") + @Test + void signSimpleCredential_ecKey() throws SigningError, DocumentError { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + var keypair = createKeyPair(KeyFactory.create(readResourceAsString("jws2020/issuing/private-key.json"))); + + var verificationMethodUrl = "https://org.eclipse.tractusx/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var issuer = Vc.sign(vc, keypair, proofOptions).loader(loader); + + // would throw an exception + var compacted = IssuerCompat.compact(issuer, "https://www.w3.org/ns/did/v1"); + var verificationMethod = compacted.getJsonObject("sec:proof").get("verificationMethod"); + + assertThat(verificationMethod).describedAs("Expected a String!").isInstanceOf(JsonString.class); + assertThat(((JsonString) verificationMethod).getString()).isEqualTo(verificationMethodUrl); + } + + @DisplayName("t0001: a simple credential to sign (RSA Key)") + @ParameterizedTest(name = "keySize = {0} bits") + @ValueSource(ints = {2048, 3072, 4096}) + void signSimpleCredential_rsaKey(int keysize) throws SigningError, DocumentError, NoSuchAlgorithmException { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + + KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); + gen.initialize(keysize); + var keyPair = gen.generateKeyPair(); + + var jwk = new RSAKey.Builder((RSAPublicKey) keyPair.getPublic()) + .privateKey((RSAPrivateKey) keyPair.getPrivate()) + .keyUse(KeyUse.SIGNATURE) + .keyID(UUID.randomUUID().toString()) + .issueTime(new Date()) + .build(); + var keypair = createKeyPair(jwk); + + var verificationMethodUrl = "https://org.eclipse.tractusx/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var issuer = Vc.sign(vc, keypair, proofOptions).loader(loader); + + // would throw an exception + var compacted = IssuerCompat.compact(issuer, "https://www.w3.org/ns/did/v1"); + var verificationMethod = compacted.getJsonObject("sec:proof").get("verificationMethod"); + + assertThat(verificationMethod).describedAs("Expected a String!").isInstanceOf(JsonString.class); + assertThat(((JsonString) verificationMethod).getString()).isEqualTo(verificationMethodUrl); + } + + @DisplayName("t0001: a simple credential to sign (OctetKeyPair)") + @Test + void signSimpleCredential_octetKeyPair() throws SigningError, DocumentError, JOSEException { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + + var jwk = new OctetKeyPairGenerator(Curve.Ed25519).generate(); + var keypair = createKeyPair(jwk); + + var verificationMethodUrl = "https://org.eclipse.tractusx/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var issuer = Vc.sign(vc, keypair, proofOptions).loader(loader); + + // would throw an exception + var compacted = IssuerCompat.compact(issuer, "https://www.w3.org/ns/did/v1"); + var verificationMethod = compacted.getJsonObject("sec:proof").get("verificationMethod"); + + assertThat(verificationMethod).describedAs("Expected a String!").isInstanceOf(JsonString.class); + assertThat(((JsonString) verificationMethod).getString()).isEqualTo(verificationMethodUrl); + } + + @DisplayName("t0002: compacted signed credential") + @Test + void signCompactedCredential() { + // nothing to do here, it's the same as above + } + + @DisplayName("t0003: signed embedded verificationMethod") + @Test + void signEmbeddedVerificationMethod() throws SigningError, DocumentError { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + var keypair = createKeyPair(KeyFactory.create(readResourceAsString("jws2020/issuing/private-key.json"))); + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(keypair) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var issuer = Vc.sign(vc, keypair, proofOptions).loader(loader); + + // would throw an exception + var compacted = IssuerCompat.compact(issuer, "https://www.w3.org/ns/did/v1"); + var verificationMethod = compacted.getJsonObject("sec:proof").get("verificationMethod"); + + assertThat(verificationMethod).describedAs("Expected an Object!").isInstanceOf(JsonObject.class); + assertThat(verificationMethod.asJsonObject().get("publicKeyJwk")) + .isInstanceOf(JsonObject.class) + .satisfies(jv -> { + assertThat(jv.asJsonObject().get("x")).isNotNull(); + assertThat(jv.asJsonObject().get("crv")).isNotNull(); + assertThat(jv.asJsonObject().get("kty")).isNotNull(); + }); + } + + @DisplayName("t0004: a credential with DID key as verification method") + @Test + void signVerificationDidKey() throws SigningError, DocumentError { + var vc = readResourceAsJson("jws2020/issuing/0001_vc.json"); + var eckey = (ECKey) KeyFactory.create(""" + { + "kty": "EC", + "d": "UEUJVbKZC3vR-y65gXx8NZVnE0QD5xe6qOk4eiObj-qVOg5zqt9zc0d6fdu4mUuu", + "use": "sig", + "crv": "P-384", + "x": "l6IS348kIFEANYl3CWueMYVXcZmK0eMI0vejkF1GHbl77dOZuZwi9L2IQmuA27ux", + "y": "m-8s5FM8Tn00OKVFxE-wfCs3J2keE2EBAYYZgAmfI1LCRD9iU2LBced-EBK18Da9", + "alg": "ES384" + } + """); + var keypair = createKeyPair(eckey); + + // check https://w3c-ccg.github.io/did-method-key/#create for details + var didKey = "did:key:zC2zU1wUHhYYX4CDwNwky9f5jtSvp5aQy5aNRQMHEdpK5xkJMy6TcMbWBP3scHbR6hhidR3RRjfAA7cuLxjydXgEiZUzRzguozYFeR3G6SzjAwswJ6hXKBWhFEHm2L6Rd6GRAw8r3kyPovxvcabdMF2gBy5TAioY1mVYFeT6"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(didKey), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var issuer = Vc.sign(vc, keypair, proofOptions).loader(loader); + + // would throw an exception + var compacted = IssuerCompat.compact(issuer, "https://www.w3.org/ns/did/v1"); + var verificationMethod = compacted.getJsonObject("sec:proof").get("verificationMethod"); + + assertThat(verificationMethod).describedAs("Expected a String!").isInstanceOf(JsonString.class); + assertThat(((JsonString) verificationMethod).getString()).isEqualTo(didKey); + + } + + @DisplayName("t0005: compacted signed presentation") + @Test + void signCompactedPresentation() throws SigningError, DocumentError { + var vp = readResourceAsJson("jws2020/issuing/0005_vp_compacted_signed.json"); + + var keypair = createKeyPair(KeyFactory.create(readResourceAsString("jws2020/issuing/private-key.json"))); + + var verificationMethodUrl = "https://org.eclipse.tractusx/verification-method"; + + var proofOptions = jws2020suite.createOptions() + .created(Instant.parse("2022-12-31T23:00:00Z")) + .verificationMethod(new JwkMethod(URI.create(verificationMethodUrl), null, null, null)) + .purpose(URI.create("https://w3id.org/security#assertionMethod")); + + + var issuer = Vc.sign(vp, keypair, proofOptions).loader(loader); + + // would throw an exception + var compacted = IssuerCompat.compact(issuer, "https://www.w3.org/ns/did/v1"); + var verificationMethod = compacted.getJsonObject("sec:proof").get("verificationMethod"); + + assertThat(verificationMethod).describedAs("Expected a String!").isInstanceOf(JsonString.class); + assertThat(((JsonString) verificationMethod).getString()).isEqualTo(verificationMethodUrl); + } + +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/JsonAdapterTest.java b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/JsonAdapterTest.java new file mode 100644 index 000000000..30ed59304 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/JsonAdapterTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import jakarta.json.Json; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; + +class JsonAdapterTest { + + private final JsonAdapter adapter = new JsonAdapter(JacksonJsonLd.createObjectMapper()); + + @Test + void read() { + var jo = Json.createValue("foobar"); + var result = adapter.read(jo); + assertThat(result).isEqualTo("foobar"); + } + + @Test + void read_jsonObjectWithValue() { + var jo = Json.createObjectBuilder() + .add("@type", "test-type") + .add("@value", "test-value") + .build(); + var result = adapter.read(jo); + assertThat(result).isEqualTo("test-value"); + } + + @Test + void write() { + var obj = "test-string"; + var result = adapter.write(obj); + assertThat(result).isInstanceOf(JsonString.class); + } + + @Test + void write_map() { + var map = Map.of("key1", "value1", "key2", "value2"); + var result = adapter.write(map); + assertThat(result).isInstanceOf(JsonObject.class).extracting(JsonValue::asJsonObject).matches(jo -> jo.size() == 2); + } +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/KeyFactoryTest.java b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/KeyFactoryTest.java new file mode 100644 index 000000000..2fa2468b0 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/KeyFactoryTest.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.jwk.Curve; +import com.nimbusds.jose.jwk.ECKey; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.OctetKeyPair; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtensionContext; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.ArgumentsProvider; +import org.junit.jupiter.params.provider.ArgumentsSource; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.text.ParseException; +import java.util.Date; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.eclipse.edc.security.signature.jws2020.TestFunctions.readResourceAsString; + +class KeyFactoryTest { + + @Test + void create_ecKey() throws JsonProcessingException { + var json = """ + { + "kty": "EC", + "crv": "P-384", + "x": "eQbMauiHc9HuiqXT894gW5XTCrOpeY8cjLXAckfRtdVBLzVHKaiXAAxBFeVrSB75", + "y": "YOjxhMkdH9QnNmGCGuGXJrjAtk8CQ1kTmEEi9cg2R9ge-zh8SFT1Xu6awoUjK5Bv", + "d": "dXghMAzYZmv46SNRuxmfDIuAlv7XIhvlkPzW3vXsopB1ihWp47tx0hqjZmYO6fJa" + } + """; + + assertThat(KeyFactory.create(json)).isInstanceOf(ECKey.class).extracting(JWK::isPrivate).isEqualTo(true); + var map = new ObjectMapper().readValue(json, Map.class); + assertThat(KeyFactory.create(map)).isInstanceOf(ECKey.class).extracting(JWK::isPrivate).isEqualTo(true); + } + + @Test + void create_rsa() throws JsonProcessingException { + // the RSA key would violate the Checkstyle line length constraint + var json = readResourceAsString("rsakey.json"); + + assertThat(KeyFactory.create(json)).isInstanceOf(RSAKey.class).extracting(JWK::isPrivate).isEqualTo(true); + var map = new ObjectMapper().readValue(json, Map.class); + assertThat(KeyFactory.create(map)).isInstanceOf(RSAKey.class).extracting(JWK::isPrivate).isEqualTo(true); + } + + @Test + void create_okp() throws JsonProcessingException { + var json = """ + { + "kty" : "OKP", + "crv" : "Ed25519", + "x" : "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo", + "d" : "nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", + "use" : "sig", + "kid" : "FdFYFzERwC2uCBB46pZQi4GG85LujR8obt-KWRBICVQ" + } + """; + + assertThat(KeyFactory.create(json)).isInstanceOf(OctetKeyPair.class).extracting(JWK::isPrivate).isEqualTo(true); + var map = new ObjectMapper().readValue(json, Map.class); + assertThat(KeyFactory.create(map)).isInstanceOf(OctetKeyPair.class).extracting(JWK::isPrivate).isEqualTo(true); + } + + @Test + void create_invalidJson() throws JsonProcessingException { + // JSON misses the "crv" property + var json = """ + { + "kty": "EC", + "x": "eQbMauiHc9HuiqXT894gW5XTCrOpeY8cjLXAckfRtdVBLzVHKaiXAAxBFeVrSB75", + "y": "YOjxhMkdH9QnNmGCGuGXJrjAtk8CQ1kTmEEi9cg2R9ge-zh8SFT1Xu6awoUjK5Bv" + } + """; + + assertThatThrownBy(() -> assertThat(KeyFactory.create(json))).isInstanceOf(RuntimeException.class).rootCause().isInstanceOf(ParseException.class); + + var map = new ObjectMapper().readValue(json, Map.class); + assertThatThrownBy(() -> assertThat(KeyFactory.create(map))).isInstanceOf(RuntimeException.class).rootCause().isInstanceOf(ParseException.class); + } + + @ParameterizedTest(name = "{1}") + @ArgumentsSource(ValidJwkProvider.class) + void createVerifier(JWK validJwk, String name) { + assertThat(KeyFactory.createVerifier(validJwk.toPublicJWK())).isNotNull(); + } + + @ParameterizedTest(name = "{1}") + @ArgumentsSource(ValidJwkProvider.class) + void createSigner(JWK validJwk, String name) { + assertThat(KeyFactory.createSigner(validJwk)).isNotNull(); + } + + private static class ValidJwkProvider implements ArgumentsProvider { + @Override + public Stream provideArguments(ExtensionContext extensionContext) { + return Stream.of( + Arguments.of(createEcKey(Curve.P_256), "EC Key with P256 Curve"), + Arguments.of(createEcKey(Curve.P_384), "EC Key with P384 Curve"), + Arguments.of(createEcKey(Curve.P_521), "EC Key with P512 Curve"), + Arguments.of(createOkp(), "Octet Key Pair"), + Arguments.of(createRsaKey(2048), "RSA Key, 2048 bit"), + Arguments.of(createRsaKey(4096), "RSA Key, 4096 bit") + ); + } + + private RSAKey createRsaKey(int keysize) { + try { + KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA"); + gen.initialize(keysize); + KeyPair keyPair = gen.generateKeyPair(); + + return new RSAKey.Builder((RSAPublicKey) keyPair.getPublic()) + .privateKey((RSAPrivateKey) keyPair.getPrivate()) + .keyUse(KeyUse.SIGNATURE) + .keyID(UUID.randomUUID().toString()) + .issueTime(new Date()) + .build(); + + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + + private OctetKeyPair createOkp() { + try { + return new OctetKeyPairGenerator(Curve.Ed25519) + .keyUse(KeyUse.SIGNATURE) // indicate the intended use of the key (optional) + .keyID(UUID.randomUUID().toString()) // give the key a unique ID (optional) + .issueTime(new Date()) // issued-at timestamp (optional) + .generate(); + } catch (JOSEException e) { + throw new RuntimeException(e); + } + + } + + private ECKey createEcKey(Curve curve) { + try { + KeyPairGenerator gen = KeyPairGenerator.getInstance("EC"); + gen.initialize(curve.toECParameterSpec()); + KeyPair keyPair = gen.generateKeyPair(); + + return new ECKey.Builder(curve, (ECPublicKey) keyPair.getPublic()) + .privateKey((ECPrivateKey) keyPair.getPrivate()) + .build(); + } catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + } + } +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/TestFunctions.java b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/TestFunctions.java new file mode 100644 index 000000000..6f403b4b6 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/TestFunctions.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.ld.signature.key.KeyPair; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.jwk.JWK; +import jakarta.json.JsonObject; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; + +import java.io.IOException; +import java.net.URI; +import java.util.Objects; +import java.util.UUID; + +class TestFunctions { + + private static final ObjectMapper MAPPER = JacksonJsonLd.createObjectMapper(); + + static KeyPair createKeyPair(JWK jwk) { + var id = URI.create("https://org.eclipse.tractusx/keys/" + UUID.randomUUID()); + var type = URI.create("https://w3id.org/security#JsonWebKey2020"); + return new JwkMethod(id, type, null, jwk); + } + + static JsonObject readResourceAsJson(String name) { + try { + return MAPPER.readValue(Thread.currentThread().getContextClassLoader().getResourceAsStream(name), JsonObject.class); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + static String readResourceAsString(String name) { + try (var stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(name)) { + return new String(Objects.requireNonNull(stream).readAllBytes()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/TestResourcesLoader.java b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/TestResourcesLoader.java new file mode 100644 index 000000000..5f3bfff5c --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/TestResourcesLoader.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.jsonld.JsonLdError; +import com.apicatalog.jsonld.document.Document; +import com.apicatalog.jsonld.document.JsonDocument; +import com.apicatalog.jsonld.loader.DocumentLoader; +import com.apicatalog.jsonld.loader.DocumentLoaderOptions; + +import java.io.IOException; +import java.net.URI; + +/** + * JSON-LD document loader that allows to "redirect" the loading of remote documents (contexts,...). + * For example, referencing a remote context, or a remote verificationMethod would fail, if that document doesn't exist, but we need it + * for testing, so we can "redirect" the pointer to the local test resources folder. + */ +class TestResourcesLoader implements DocumentLoader { + private final String base; + private final DocumentLoader baseLoader; + private final String resourcePath; + + TestResourcesLoader(String base, String resourcePath, DocumentLoader baseLoader) { + this.base = base; + this.resourcePath = resourcePath; + this.baseLoader = baseLoader; + } + + @Override + public Document loadDocument(URI uri, DocumentLoaderOptions options) throws JsonLdError { + Document document; + var url = uri.toString(); + if (url.startsWith(base)) { + try (var is = Thread.currentThread().getContextClassLoader().getResourceAsStream(rewrite(uri))) { + document = JsonDocument.of(is); + } catch (IOException e) { + throw new RuntimeException(e); + } + + } else { + document = baseLoader.loadDocument(uri, options); + } + return document; + } + + private String rewrite(URI url) { + var path = resourcePath + url.toString().replace(base, ""); + if (!path.endsWith(".json")) { + path += ".json"; + } + return path; + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/VerifierTests.java b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/VerifierTests.java new file mode 100644 index 000000000..8634342c6 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/java/org/eclipse/edc/security/signature/jws2020/VerifierTests.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023 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.security.signature.jws2020; + +import com.apicatalog.jsonld.loader.SchemeRouter; +import com.apicatalog.ld.DocumentError; +import com.apicatalog.ld.signature.VerificationError; +import com.apicatalog.vc.Vc; +import org.eclipse.edc.jsonld.util.JacksonJsonLd; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThatNoException; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.eclipse.edc.security.signature.jws2020.TestFunctions.readResourceAsJson; + +class VerifierTests { + + private final JwsSignature2020Suite jws2020suite = new JwsSignature2020Suite(JacksonJsonLd.createObjectMapper()); + //used to load remote data from a local directory + private final TestResourcesLoader loader = new TestResourcesLoader("https://org.eclipse.tractusx/", "jws2020/verifying/", SchemeRouter.defaultInstance()); + + @DisplayName("t0001: valid signed VC") + @Test + void verifyValidVc() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0001_vc.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatNoException().isThrownBy(result::isValid); + } + + @DisplayName("t0002: forged credentials subject") + @Test + void verify_forgedSubject() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0002_vc_forged.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatThrownBy(result::isValid).isInstanceOf(VerificationError.class); + } + + @DisplayName("t0003: valid VC with embedded verification method") + @Test + void verifyVc_withEmbeddedVerificationMethod() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0003_vc_embedded.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatNoException().isThrownBy(result::isValid); + } + + @DisplayName("t0004: proof set of two valid proofs") + @Test + void verify_multipleValidProofs() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0004_vc_two_valid_proofs.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatNoException().isThrownBy(result::isValid); + } + + @DisplayName("t0005: proof set having one forged proof") + @Test + void verify_oneForgedProof() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0005_vc_one_forged_proof.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatThrownBy(result::isValid).isInstanceOf(VerificationError.class); + } + + /** + * The did:key method is not yet supported, since it is only a community draft, and implementability in conjunction with JWS2020 is + * unclear. Furthermore, the "did:key" implementation relies + * on this Multibase library, which is not available from MavenCentral. + *

+ * The biggest challenge with Jws will be to reconstruct the key type/curve from just the public key. + */ + @Disabled("did:key is not supported") + @DisplayName("t0006: DID key as verification method (not yet supported)") + @Test + void verify_didKeyAsVerificationMethod() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0006_vc_did_key.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatThrownBy(result::isValid).isInstanceOf(UnsupportedOperationException.class) + .hasMessage("Cannot deserialize public key, expected JWK format"); + } + + @DisplayName("t0007: valid signed VP") + @Test + void verify_validSignedVp() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0006_vp_compacted.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatNoException().isThrownBy(result::isValid); + } + + @DisplayName("t0008: forged signed VP") + @Test + void verify_forgedSignedVp() throws VerificationError, DocumentError { + var vc = readResourceAsJson("jws2020/verifying/0007_vp_compacted_forged.json"); + var result = Vc.verify(vc, jws2020suite).loader(loader); + assertThatThrownBy(result::isValid).isInstanceOf(VerificationError.class); + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0001_vc.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0001_vc.json new file mode 100644 index 000000000..d46429d2f --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0001_vc.json @@ -0,0 +1,21 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "bpn": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0003_vc_embedded.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0003_vc_embedded.json new file mode 100644 index 000000000..d46429d2f --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0003_vc_embedded.json @@ -0,0 +1,21 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "bpn": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0004_vc_did_key.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0004_vc_did_key.json new file mode 100644 index 000000000..46d55fdd3 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0004_vc_did_key.json @@ -0,0 +1,21 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0005_vp_compacted_signed.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0005_vp_compacted_signed.json new file mode 100644 index 000000000..124db8952 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/0005_vp_compacted_signed.json @@ -0,0 +1,38 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://www.w3.org/2018/credentials/examples/v1" + ], + "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5", + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "bpn": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + }, + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] + } + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/businessPartnerData.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/businessPartnerData.json new file mode 100644 index 000000000..b36e7cd46 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/businessPartnerData.json @@ -0,0 +1,177 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "BpnCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "bpn": "http://schema.org/identifier" + } + }, + "MembershipCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#MembershipCredential", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "ex": "https://example.org/examples#", + "startTime": { + "@id": "https://schema.org/startTime", + "@type": "https://schema.org/DateTime" + }, + "memberOf": { + "@id": "https://schema.org/memberOf", + "@type": "https://schema.org/Text" + }, + "status": { + "@id": "ex:status", + "@type": "https://schema.org/Text" + } + } + }, + "NameCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#NameCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "uuid": "http://schema.org/identifier", + "value": { + "@id": "ex:value", + "@type": "https://schema.org/Text" + }, + "name": { + "@id": "ex:name", + "@type": "https://schema.org/Text" + }, + "shortName": { + "@id": "ex:shortName", + "@type": "https://schema.org/Text" + }, + "fipsCode": { + "@id": "ex:fipsCode", + "@type": "https://schema.org/Text" + }, + "number": { + "@id": "ex:number", + "@type": "https://schema.org/Text" + }, + "direction": { + "@id": "ex:direction", + "@type": "https://schema.org/Text" + }, + "nameType": { + "@id": "ex:nameType", + "@type": "https://schema.org/object" + }, + "language": { + "@id": "ex:language", + "@type": "https://schema.org/object" + } + } + }, + "BankAccountCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#BankAccountCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "uuid": "http://schema.org/identifier", + "trustScores": { + "@id": "ex:trustScores" + }, + "nationalBankIdentifier": { + "@id": "ex:nationalBankIdentifier", + "@type": "https://schema.org/Text" + }, + "nationalBankAccountIdentifier": { + "@id": "ex:nationalBankAccountIdentifier", + "@type": "https://schema.org/Text" + }, + "internationalBankIdentifier": { + "@id": "ex:internationalBankIdentifier", + "@type": "https://schema.org/Text" + }, + "internationalBankAccountIdentifier": { + "@id": "ex:internationalBankAccountIdentifier", + "@type": "https://schema.org/Text" + }, + "currency": { + "@id": "ex:typeOf", + "@type": "https://schema.org/object" + } + } + }, + "AddressCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#AddressCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "uuid": "http://schema.org/identifier", + "version": { + "@id": "ex:typeOf", + "@type": "https://schema.org/object" + }, + "careOf": { + "@id": "ex:careOf", + "@type": "https://schema.org/Text" + }, + "contexts": { + "@id": "ex:contexts" + }, + "bpn": { + "@id": "ex:bpn" + }, + "country": { + "@id": "ex:country", + "@type": "https://schema.org/object" + }, + "administrativeAreas": { + "@id": "ex:administrativeAreas" + }, + "postCodes": { + "@id": "ex:postCodes" + }, + "localities": { + "@id": "ex:localities" + }, + "thoroughfares": { + "@id": "ex:thoroughfares" + }, + "premises": { + "@id": "ex:premises" + }, + "postalDeliveryPoints": { + "@id": "ex:postalDeliveryPoints" + }, + "geographicCoordinates": { + "@id": "ex:geographicCoordinates", + "@type": "https://schema.org/object" + }, + "types": { + "@id": "ex:types" + } + } + }, + "LegalFormCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#LegalFormCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "technicalKey": {"@id": "ex:technicalKey", "@type":"https://schema.org/Text"}, + "name": {"@id": "ex:name", "@type":"https://schema.org/Text"}, + "url": {"@id": "ex:url", "@type":"https://schema.org/Text"}, + "mainAbbreviation": {"@id": "https://schema.org/Text#4", "@type":"https://schema.org/Text"}, + "language": {"@id": "https://schema.org/Text#5", "@type":"https://schema.org/object"}, + "categories": {"@id": "https://schema.org/Text#6", "@type":"https://schema.org/ItemList"} + } + } + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/private-key.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/private-key.json new file mode 100644 index 000000000..4b9aa1c24 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/issuing/private-key.json @@ -0,0 +1,7 @@ +{ + "kty": "EC", + "d": "RQenh0DD80AULwMqtTgYrihOft-kUGXGxL3prdtINDE9rp2ta3_CT1IcNUnDuG0F", + "crv": "P-384", + "x": "AqMfyYAh2SMf8bMoLbE6mOCbVyz8hukpBqrVheAFP4Anz2_cfzLEKKROD5EaAxSo", + "y": "P4KceKXv31JasLqvBPZWA9t1S2cMiHIQQ8ttAl5cFX3xBuzIPlgTRWPOVaNPWNFl" +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0001_vc.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0001_vc.json new file mode 100644 index 000000000..af27d5f5a --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0001_vc.json @@ -0,0 +1,27 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + }, + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0002_vc_forged.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0002_vc_forged.json new file mode 100644 index 000000000..82643a27e --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0002_vc_forged.json @@ -0,0 +1,36 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "bpn": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "BpnCredential" + }, + "id": "7f6c11b4-d2b9-43c3-8411-53f6089b5d2b", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": { + "type": "JsonWebKey2020", + "publicKeyJwk": { + "kty": "EC", + "crv": "P-384", + "x": "eQbMauiHc9HuiqXT894gW5XTCrOpeY8cjLXAckfRtdVBLzVHKaiXAAxBFeVrSB75", + "y": "YOjxhMkdH9QnNmGCGuGXJrjAtk8CQ1kTmEEi9cg2R9ge-zh8SFT1Xu6awoUjK5Bv" + }, + "id": "https://org.eclipse.tractusx/keys/68c7189c-b849-4f85-b27d-c796c7cf29ed" + }, + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..xJWgUGQLLeC6XqZKXfkboY49NJeKW7GCOvqvXsP2iCXijMQVwz3yjCEf_4Hs3xLJZqz7_ZVYOEGeg5k2UMctVQ_uwsrPZ6w72jq4pMaNAlUIEeRDLYVUSl6v2FoeZftt" + }, + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0003_vc_embedded.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0003_vc_embedded.json new file mode 100644 index 000000000..0475a48a1 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0003_vc_embedded.json @@ -0,0 +1,37 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "bpn": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "BpnCredential" + }, + "id": "7f6c11b4-d2b9-43c3-8411-53f6089b5d2b", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": { + "type": "JsonWebKey2020", + "publicKeyJwk": { + "kty": "EC", + "crv": "P-384", + "x": "eQbMauiHc9HuiqXT894gW5XTCrOpeY8cjLXAckfRtdVBLzVHKaiXAAxBFeVrSB75", + "y": "YOjxhMkdH9QnNmGCGuGXJrjAtk8CQ1kTmEEi9cg2R9ge-zh8SFT1Xu6awoUjK5Bv" + }, + "id": "https://org.eclipse.tractusx/keys/68c7189c-b849-4f85-b27d-c796c7cf29ed" + }, + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..0ueANOomarONwEL2Y0QnCFjgOdgPjI8kL2Wk4QWh8SJjvVTR80ASVh7bi8HlQp6dUigP3r509oMQkXB6TEddi0D8oQc2Lv0uWxl7yxPInBcfIsWmQrFBTb4mCSU_MJwE" + }, + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1", + "https://www.w3.org/ns/did/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0004_vc_two_valid_proofs.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0004_vc_two_valid_proofs.json new file mode 100644 index 000000000..c68077de3 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0004_vc_two_valid_proofs.json @@ -0,0 +1,45 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": [ + { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": { + "type": "JsonWebKey2020", + "publicKeyJwk": { + "kty": "OKP", + "crv": "Ed25519", + "x": "WNAhS5ptnuCCX0GAvlz_Ng0vLt72fddnn3kQTkQSYhU" + }, + "id": "https://org.eclipse.tractusx/keys/e4f14fcc-d607-487d-ac42-2f526eedc91a" + }, + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFZERTQSJ9..UsYPNpv_vwcjQliZ5n5ZZECzE9S7u_vLYf2pFQgqdXCVAPdMQ3IpbEdOxe4xgi-hzw7iqpE8lRRwBGDCPOqqDA" + }, + { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + } + ], + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1", + "https://www.w3.org/ns/did/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0005_vc_one_forged_proof.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0005_vc_one_forged_proof.json new file mode 100644 index 000000000..7df5f179a --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0005_vc_one_forged_proof.json @@ -0,0 +1,45 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": [ + { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": { + "type": "JsonWebKey2020", + "publicKeyJwk": { + "kty": "OKP", + "crv": "Ed25519", + "x": "11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo" + }, + "id": "https://org.eclipse.tractusx/keys/e4f14fcc-d607-487d-ac42-2f526eedc91a" + }, + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFZERTQSJ9..UsYPNpv_vwcjQliZ5n5ZZECzE9S7u_vLYf2pFQgqdXCVAPdMQ3IpbEdOxe4xgi-hzw7iqpE8lRRwBGDCPOqqDA" + }, + { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + } + ], + "@context": [ + "https://org.eclipse.tractusx/businessPartnerData", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1", + "https://www.w3.org/ns/did/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0006_vc_did_key.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0006_vc_did_key.json new file mode 100644 index 000000000..83394a24e --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0006_vc_did_key.json @@ -0,0 +1,28 @@ +{ + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:key:zC2zU1wUHhYYX4CDwNwky9f5jtSvp5aQy5aNRQMHEdpK5xkJMy6TcMbWBP3scHbR6hhidR3RRjfAA7cuLxjydXgEiZUzRzguozYFeR3G6SzjAwswJ6hXKBWhFEHm2L6Rd6GRAw8r3kyPovxvcabdMF2gBy5TAioY1mVYFeT6", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..Om6PnvxKvcHXUwT6mycHMf8aPQADAlJKCP4TgCBPgd4-Y67DwcIvZkMZrPxcNPskUIKKFXr_1Ecv5mE016xBtS03itgUsZY7BjD44oMAYgyfw1t2Gdpcph-GvuB_9U0Q" + }, + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1", + "https://www.w3.org/ns/did/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0006_vp_compacted.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0006_vp_compacted.json new file mode 100644 index 000000000..ec42acc49 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0006_vp_compacted.json @@ -0,0 +1,39 @@ +{ + "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5", + "type": "VerifiablePresentation", + "verifiableCredential": { + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + } + }, + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..qVCNVL_jxQdqa509KPTjRERopJiRtW1CqctVD_uGtUlCNF9oM2eB1L821YvjW0VjZjP6XdS5bLfQpG3azg9Hm8-L4vFBiH8HgEdVllHVcmO1odG-2GQAnhdP6Kdg42Wh" + }, + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1", + "https://www.w3.org/ns/did/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0007_vp_compacted_forged.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0007_vp_compacted_forged.json new file mode 100644 index 000000000..30b8c8400 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/0007_vp_compacted_forged.json @@ -0,0 +1,39 @@ +{ + "id": "urn:uuid:3978344f-8596-4c3a-a978-8fcaba3903c5", + "type": "VerifiablePresentation", + "verifiableCredential": { + "issuanceDate": "2023-06-12T13:13:30Z", + "credentialSubject": { + "http://schema.org/identifier": "BPNL000000000000", + "id": "did:web:localhost:BPNL000000000000", + "type": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential" + }, + "id": "https://org.eclipse.tractusx/testcases/t0001", + "type": [ + "VerifiableCredential", + "BpnCredentialCX" + ], + "issuer": "did:web:localhost:BPNL000000000000", + "expirationDate": "2024-12-31T23:00:00Z", + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + } + }, + "sec:proof": { + "type": "JsonWebSignature2020", + "created": "2022-12-31T23:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "https://org.eclipse.tractusx/verification-method", + "jws": "eyJiNjQiOmZhbHNlLCJjcml0IjpbImI2NCJdLCJhbGciOiJFUzM4NCJ9..dbi6LFkdeBeCz3sHaxRRFVJC2_rF8Z_oYqaoNOpYtzQh61WP78pK7nKT53WsE-7uiBUMamLA8vEGJpFQ3h4MXDi2OKh1YDpphS_pwyDkqYbsguMs2KYqPxe8t1OC2G1o" + }, + "@context": [ + "https://www.w3.org/ns/did/v1", + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/security/suites/jws-2020/v1", + "https://www.w3.org/ns/did/v1" + ] +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/businessPartnerData.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/businessPartnerData.json new file mode 100644 index 000000000..b36e7cd46 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/businessPartnerData.json @@ -0,0 +1,177 @@ +{ + "@context": { + "@version": 1.1, + "@protected": true, + "BpnCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#BpnCredential", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "bpn": "http://schema.org/identifier" + } + }, + "MembershipCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#MembershipCredential", + "@context": { + "@version": 1.1, + "@protected": true, + "id": "@id", + "type": "@type", + "ex": "https://example.org/examples#", + "startTime": { + "@id": "https://schema.org/startTime", + "@type": "https://schema.org/DateTime" + }, + "memberOf": { + "@id": "https://schema.org/memberOf", + "@type": "https://schema.org/Text" + }, + "status": { + "@id": "ex:status", + "@type": "https://schema.org/Text" + } + } + }, + "NameCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#NameCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "uuid": "http://schema.org/identifier", + "value": { + "@id": "ex:value", + "@type": "https://schema.org/Text" + }, + "name": { + "@id": "ex:name", + "@type": "https://schema.org/Text" + }, + "shortName": { + "@id": "ex:shortName", + "@type": "https://schema.org/Text" + }, + "fipsCode": { + "@id": "ex:fipsCode", + "@type": "https://schema.org/Text" + }, + "number": { + "@id": "ex:number", + "@type": "https://schema.org/Text" + }, + "direction": { + "@id": "ex:direction", + "@type": "https://schema.org/Text" + }, + "nameType": { + "@id": "ex:nameType", + "@type": "https://schema.org/object" + }, + "language": { + "@id": "ex:language", + "@type": "https://schema.org/object" + } + } + }, + "BankAccountCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#BankAccountCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "uuid": "http://schema.org/identifier", + "trustScores": { + "@id": "ex:trustScores" + }, + "nationalBankIdentifier": { + "@id": "ex:nationalBankIdentifier", + "@type": "https://schema.org/Text" + }, + "nationalBankAccountIdentifier": { + "@id": "ex:nationalBankAccountIdentifier", + "@type": "https://schema.org/Text" + }, + "internationalBankIdentifier": { + "@id": "ex:internationalBankIdentifier", + "@type": "https://schema.org/Text" + }, + "internationalBankAccountIdentifier": { + "@id": "ex:internationalBankAccountIdentifier", + "@type": "https://schema.org/Text" + }, + "currency": { + "@id": "ex:typeOf", + "@type": "https://schema.org/object" + } + } + }, + "AddressCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#AddressCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "uuid": "http://schema.org/identifier", + "version": { + "@id": "ex:typeOf", + "@type": "https://schema.org/object" + }, + "careOf": { + "@id": "ex:careOf", + "@type": "https://schema.org/Text" + }, + "contexts": { + "@id": "ex:contexts" + }, + "bpn": { + "@id": "ex:bpn" + }, + "country": { + "@id": "ex:country", + "@type": "https://schema.org/object" + }, + "administrativeAreas": { + "@id": "ex:administrativeAreas" + }, + "postCodes": { + "@id": "ex:postCodes" + }, + "localities": { + "@id": "ex:localities" + }, + "thoroughfares": { + "@id": "ex:thoroughfares" + }, + "premises": { + "@id": "ex:premises" + }, + "postalDeliveryPoints": { + "@id": "ex:postalDeliveryPoints" + }, + "geographicCoordinates": { + "@id": "ex:geographicCoordinates", + "@type": "https://schema.org/object" + }, + "types": { + "@id": "ex:types" + } + } + }, + "LegalFormCredential": { + "@id": "https://org.eclipse.tractusx/businessPartnerData#LegalFormCredential", + "@context": { + "@version": 1.1, + "id": "@id", + "type": "@type", + "technicalKey": {"@id": "ex:technicalKey", "@type":"https://schema.org/Text"}, + "name": {"@id": "ex:name", "@type":"https://schema.org/Text"}, + "url": {"@id": "ex:url", "@type":"https://schema.org/Text"}, + "mainAbbreviation": {"@id": "https://schema.org/Text#4", "@type":"https://schema.org/Text"}, + "language": {"@id": "https://schema.org/Text#5", "@type":"https://schema.org/object"}, + "categories": {"@id": "https://schema.org/Text#6", "@type":"https://schema.org/ItemList"} + } + } + } +} diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/verification-method.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/verification-method.json new file mode 100644 index 000000000..c541be484 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/jws2020/verifying/verification-method.json @@ -0,0 +1,11 @@ +{ + "@context": ["https://www.w3.org/ns/did/v1", "https://w3id.org/security/suites/jws-2020/v1"], + "type": "JsonWebKey2020", + "id": "https://org.eclipse.tractusx/verification-keys.json", + "publicKeyJwk": { + "kty": "EC", + "crv": "P-384", + "x": "AqMfyYAh2SMf8bMoLbE6mOCbVyz8hukpBqrVheAFP4Anz2_cfzLEKKROD5EaAxSo", + "y": "P4KceKXv31JasLqvBPZWA9t1S2cMiHIQQ8ttAl5cFX3xBuzIPlgTRWPOVaNPWNFl" + } +} \ No newline at end of file diff --git a/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/rsakey.json b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/rsakey.json new file mode 100644 index 000000000..aa8d9df69 --- /dev/null +++ b/edc-extensions/ssi/jws2020-crypto-suite/src/test/resources/rsakey.json @@ -0,0 +1,13 @@ +{ + "kty": "RSA", + "kid": "cc34c0a0-bd5a-4a3c-a50d-a2a7db7643df", + "use": "sig", + "n": "pjdss8ZaDfEH6K6U7GeW2nxDqR4IP049fk1fK0lndimbMMVBdPv_hSpm8T8EtBDxrUdi1OHZfMhUixGaut-3nQ4GG9nM249oxhCtxqqNvEXrmQRGqczyLxuh-fKn9Fg--hS9UpazHpfVAFnB5aCfXoNhPuI8oByyFKMKaOVgHNqP5NBEqabiLftZD3W_lsFCPGuzr4Vp0YS7zS2hDYScC2oOMu4rGU1LcMZf39p3153Cq7bS2Xh6Y-vw5pwzFYZdjQxDn8x8BG3fJ6j8TGLXQsbKH1218_HcUJRvMwdpbUQG5nvA2GXVqLqdwp054Lzk9_B_f1lVrmOKuHjTNHq48w", + "e": "AQAB", + "d": "ksDmucdMJXkFGZxiomNHnroOZxe8AmDLDGO1vhs-POa5PZM7mtUPonxwjVmthmpbZzla-kg55OFfO7YcXhg-Hm2OWTKwm73_rLh3JavaHjvBqsVKuorX3V3RYkSro6HyYIzFJ1Ek7sLxbjDRcDOj4ievSX0oN9l-JZhaDYlPlci5uJsoqro_YrE0PRRWVhtGynd-_aWgQv1YzkfZuMD-hJtDi1Im2humOWxA4eZrFs9eG-whXcOvaSwO4sSGbS99ecQZHM2TcdXeAs1PvjVgQ_dKnZlGN3lTWoWfQP55Z7Tgt8Nf1q4ZAKd-NlMe-7iqCFfsnFwXjSiaOa2CRGZn-Q", + "p": "4A5nU4ahEww7B65yuzmGeCUUi8ikWzv1C81pSyUKvKzu8CX41hp9J6oRaLGesKImYiuVQK47FhZ--wwfpRwHvSxtNU9qXb8ewo-BvadyO1eVrIk4tNV543QlSe7pQAoJGkxCia5rfznAE3InKF4JvIlchyqs0RQ8wx7lULqwnn0", + "q": "ven83GM6SfrmO-TBHbjTk6JhP_3CMsIvmSdo4KrbQNvp4vHO3w1_0zJ3URkmkYGhz2tgPlfd7v1l2I6QkIh4Bumdj6FyFZEBpxjE4MpfdNVcNINvVj87cLyTRmIcaGxmfylY7QErP8GFA-k4UoH_eQmGKGK44TRzYj5hZYGWIC8", + "dp": "lmmU_AG5SGxBhJqb8wxfNXDPJjf__i92BgJT2Vp4pskBbr5PGoyV0HbfUQVMnw977RONEurkR6O6gxZUeCclGt4kQlGZ-m0_XSWx13v9t9DIbheAtgVJ2mQyVDvK4m7aRYlEceFh0PsX8vYDS5o1txgPwb3oXkPTtrmbAGMUBpE", + "dq": "mxRTU3QDyR2EnCv0Nl0TCF90oliJGAHR9HJmBe__EjuCBbwHfcT8OG3hWOv8vpzokQPRl5cQt3NckzX3fs6xlJN4Ai2Hh2zduKFVQ2p-AF2p6Yfahscjtq-GY9cB85NxLy2IXCC0PF--Sq9LOrTE9QV988SJy_yUrAjcZ5MmECk", + "qi": "ldHXIrEmMZVaNwGzDF9WG8sHj2mOZmQpw9yrjLK9hAsmsNr5LTyqWAqJIYZSwPTYWhY4nu2O0EY9G9uYiqewXfCKw_UngrJt8Xwfq1Zruz0YY869zPN4GiE9-9rzdZB33RBw8kIOquY3MK74FMwCihYx_LiU2YTHkaoJ3ncvtvg" +} \ No newline at end of file diff --git a/edc-extensions/ssi/ssi-identity-core/README.md b/edc-extensions/ssi/ssi-identity-core/README.md new file mode 100644 index 000000000..59cc63bfe --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/README.md @@ -0,0 +1,25 @@ +# SSI Core Identity Service Module + +This module contains an implementation of the EDC identity service for SSI. +The SsiIdentityService contains a `SsiTokenValidationService` for validating the `JWT` token, +that uses an implementation of `SsiCredentialClient` for validating the JWT token and then check custom rules registered in the `SsiValidationRuleRegistry` + +For obtaining the `JWT` token, the identity service also delegate to the `SsiCredentialClient` . + +The default implementation according to the first milestone [here](https://github.com/eclipse-tractusx/ssi-docu/tree/main/docs/architecture/cx-3-2) +will rely on an MIW and the implementations in available in the module `:edc-extensions:ssi:ssi-miw-credential-client`. + +The implementation also provide a rule registry `SsiValidationRuleRegistry` where custom rule can be registered for validating the `ClaimToken` extracted from the `JWT` token. + +Custom rule could be like: + +- Audience validation +- VP/VC validation +- Expiration +- ..etc + +## Configuration + +| Key | Required | Example | Description | +|-----------------------------------------|----------|----------------|---------------------------------------| +| tx.ssi.endpoint.audience | X | | Endpoint URL for audience check (DSP) | diff --git a/edc-extensions/ssi/ssi-identity-core/build.gradle.kts b/edc-extensions/ssi/ssi-identity-core/build.gradle.kts new file mode 100644 index 000000000..4a7a3da37 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 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` + `maven-publish` +} + +dependencies { + implementation(project(":spi:ssi-spi")) + implementation(libs.edc.spi.core) + implementation(libs.edc.spi.jwt) + implementation(libs.edc.jwt.core) + implementation(libs.nimbus.jwt) + testImplementation(testFixtures(libs.edc.junit)) +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityService.java b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityService.java new file mode 100644 index 000000000..199600929 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityService.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity; + +import org.eclipse.edc.jwt.spi.TokenValidationService; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.iam.IdentityService; +import org.eclipse.edc.spi.iam.TokenParameters; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; + +public class SsiIdentityService implements IdentityService { + + private final TokenValidationService tokenValidationService; + + private final SsiCredentialClient client; + + public SsiIdentityService(TokenValidationService tokenValidationService, SsiCredentialClient client) { + this.tokenValidationService = tokenValidationService; + this.client = client; + } + + @Override + public Result obtainClientCredentials(TokenParameters parameters) { + return client.obtainClientCredentials(parameters); + } + + @Override + public Result verifyJwtToken(TokenRepresentation tokenRepresentation, String audience) { + return tokenValidationService.validate(tokenRepresentation); + } +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceExtension.java b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceExtension.java new file mode 100644 index 000000000..ca69eb878 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceExtension.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity; + +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Provides; +import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.spi.iam.IdentityService; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.tractusx.edc.iam.ssi.identity.rule.SsiAudienceValidationRule; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiValidationRuleRegistry; + +@Provides({ IdentityService.class, SsiValidationRuleRegistry.class }) +@Extension(SsiIdentityServiceExtension.EXTENSION_NAME) +public class SsiIdentityServiceExtension implements ServiceExtension { + + public static final String EXTENSION_NAME = "SSI Identity Service"; + + @Setting(value = "SSI Endpoint audience of this connector") + public static final String ENDPOINT_AUDIENCE = "tx.ssi.endpoint.audience"; + + @Inject + private SsiCredentialClient credentialClient; + + @Override + public String name() { + return EXTENSION_NAME; + } + + @Override + public void initialize(ServiceExtensionContext context) { + var validationRulesRegistry = new SsiValidationRulesRegistryImpl(); + configureRules(context, validationRulesRegistry); + context.registerService(SsiValidationRuleRegistry.class, validationRulesRegistry); + + var identityService = new SsiIdentityService(new SsiTokenValidationService(validationRulesRegistry, credentialClient), credentialClient); + + context.registerService(IdentityService.class, identityService); + } + + + private void configureRules(ServiceExtensionContext context, SsiValidationRuleRegistry registry) { + var endpointAudience = context.getConfig().getString(ENDPOINT_AUDIENCE); + registry.addRule(new SsiAudienceValidationRule(endpointAudience)); + } +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiTokenValidationService.java b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiTokenValidationService.java new file mode 100644 index 000000000..80a99d915 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiTokenValidationService.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity; + +import org.eclipse.edc.jwt.spi.TokenValidationRulesRegistry; +import org.eclipse.edc.jwt.spi.TokenValidationService; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Map; +import java.util.stream.Collectors; + +public class SsiTokenValidationService implements TokenValidationService { + + private final TokenValidationRulesRegistry rulesRegistry; + private final SsiCredentialClient credentialClient; + + public SsiTokenValidationService(TokenValidationRulesRegistry rulesRegistry, SsiCredentialClient credentialClient) { + this.rulesRegistry = rulesRegistry; + this.credentialClient = credentialClient; + } + + @Override + public Result validate(TokenRepresentation tokenRepresentation) { + return credentialClient.validate(tokenRepresentation) + .compose(claimToken -> checkRules(claimToken, tokenRepresentation.getAdditional())); + } + + private Result checkRules(ClaimToken claimToken, @Nullable Map additional) { + var errors = rulesRegistry.getRules().stream() + .map(r -> r.checkRule(claimToken, additional)) + .filter(Result::failed) + .map(Result::getFailureMessages) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + + if (!errors.isEmpty()) { + return Result.failure(errors); + } + return Result.success(claimToken); + } +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiValidationRulesRegistryImpl.java b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiValidationRulesRegistryImpl.java new file mode 100644 index 000000000..077c35862 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiValidationRulesRegistryImpl.java @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity; + +import org.eclipse.edc.jwt.TokenValidationRulesRegistryImpl; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiValidationRuleRegistry; + +public class SsiValidationRulesRegistryImpl extends TokenValidationRulesRegistryImpl implements SsiValidationRuleRegistry { +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/rule/SsiAudienceValidationRule.java b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/rule/SsiAudienceValidationRule.java new file mode 100644 index 000000000..dc3c7eae9 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/rule/SsiAudienceValidationRule.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity.rule; + +import org.eclipse.edc.jwt.spi.TokenValidationRule; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.result.Result; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; + +public class SsiAudienceValidationRule implements TokenValidationRule { + + private final String endpointAudience; + + public SsiAudienceValidationRule(String endpointAudience) { + this.endpointAudience = endpointAudience; + } + + @Override + public Result checkRule(@NotNull ClaimToken toVerify, @Nullable Map additional) { + var audiences = toVerify.getListClaim(AUDIENCE); + if (audiences.isEmpty()) { + return Result.failure("Required audience (aud) claim is missing in token"); + } else if (!audiences.contains(endpointAudience)) { + return Result.failure("Token audience (aud) claim did not contain audience: " + endpointAudience); + } + return Result.success(); + } +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-extensions/ssi/ssi-identity-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..28d3cef1c --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 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 +# +# + +org.eclipse.tractusx.edc.iam.ssi.identity.SsiIdentityServiceExtension \ No newline at end of file diff --git a/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceExtensionTest.java b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceExtensionTest.java new file mode 100644 index 000000000..42a88786c --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceExtensionTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity; + +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.iam.IdentityService; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.edc.spi.system.injection.ObjectFactory; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiValidationRuleRegistry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.identity.SsiIdentityServiceExtension.ENDPOINT_AUDIENCE; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(DependencyInjectionExtension.class) +public class SsiIdentityServiceExtensionTest { + + SsiIdentityServiceExtension extension; + + ServiceExtensionContext context; + + @BeforeEach + void setup(ObjectFactory factory, ServiceExtensionContext context) { + this.context = spy(context); + context.registerService(SsiCredentialClient.class, mock(SsiCredentialClient.class)); + extension = factory.constructInstance(SsiIdentityServiceExtension.class); + } + + @Test + void initialize() { + var cfg = mock(Config.class); + when(context.getConfig()).thenReturn(cfg); + when(cfg.getString(ENDPOINT_AUDIENCE)).thenReturn("test"); + + extension.initialize(context); + + assertThat(context.getService(IdentityService.class)).isNotNull().isInstanceOf(SsiIdentityService.class); + assertThat(context.getService(SsiValidationRuleRegistry.class)).isNotNull().isInstanceOf(SsiValidationRulesRegistryImpl.class); + + verify(cfg).getString(ENDPOINT_AUDIENCE); + + } +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceTest.java b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceTest.java new file mode 100644 index 000000000..8a776f475 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiIdentityServiceTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity; + +import org.eclipse.edc.jwt.spi.TokenValidationService; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.iam.TokenParameters; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class SsiIdentityServiceTest { + + SsiCredentialClient credentialClient = mock(SsiCredentialClient.class); + TokenValidationService tokenValidationService = mock(TokenValidationService.class); + + SsiIdentityService identityService; + + @BeforeEach + void setup() { + identityService = new SsiIdentityService(tokenValidationService, credentialClient); + } + + @Test + void verifyJwtToken_success() { + var token = TokenRepresentation.Builder.newInstance().token("test").build(); + var claim = ClaimToken.Builder.newInstance().build(); + + when(tokenValidationService.validate(token)).thenReturn(Result.success(claim)); + + var result = identityService.verifyJwtToken(token, "audience"); + + assertThat(result).isNotNull().extracting(Result::getContent).isEqualTo(claim); + } + + @Test + void verifyJwtToken_failed() { + var token = TokenRepresentation.Builder.newInstance().token("test").build(); + + when(tokenValidationService.validate(token)).thenReturn(Result.failure("fail")); + + var result = identityService.verifyJwtToken(token, "audience"); + + assertThat(result).isNotNull().matches(Result::failed); + } + + + @Test + void obtainClientCredentials_success() { + var tokenParameters = TokenParameters.Builder.newInstance().audience("audience").build(); + var tokenRepresentation = TokenRepresentation.Builder.newInstance().token("test").build(); + + when(credentialClient.obtainClientCredentials(tokenParameters)).thenReturn(Result.success(tokenRepresentation)); + + var result = identityService.obtainClientCredentials(tokenParameters); + + assertThat(result).isNotNull().extracting(Result::getContent).isEqualTo(tokenRepresentation); + } + + @Test + void obtainClientCredentials_fail() { + var tokenParameters = TokenParameters.Builder.newInstance().audience("audience").build(); + + when(credentialClient.obtainClientCredentials(tokenParameters)).thenReturn(Result.failure("fail")); + + var result = identityService.obtainClientCredentials(tokenParameters); + + assertThat(result).isNotNull().matches(Result::failed); + } +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiTokenValidationServiceTest.java b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiTokenValidationServiceTest.java new file mode 100644 index 000000000..56f30c3eb --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/SsiTokenValidationServiceTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity; + +import org.eclipse.edc.jwt.spi.TokenValidationRule; +import org.eclipse.edc.jwt.spi.TokenValidationRulesRegistry; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +public class SsiTokenValidationServiceTest { + + SsiCredentialClient credentialClient = mock(SsiCredentialClient.class); + TokenValidationRulesRegistry validationRulesRegistry = mock(TokenValidationRulesRegistry.class); + + SsiTokenValidationService validationService; + + @BeforeEach + void setup() { + validationService = new SsiTokenValidationService(validationRulesRegistry, credentialClient); + } + + @Test + void validate_success() { + var token = TokenRepresentation.Builder.newInstance().token("test").build(); + var rule = mock(TokenValidationRule.class); + var claim = ClaimToken.Builder.newInstance().build(); + + when(validationRulesRegistry.getRules()).thenReturn(List.of(rule)); + when(credentialClient.validate(token)).thenReturn(Result.success(claim)); + when(rule.checkRule(any(), any())).thenReturn(Result.success()); + + var result = validationService.validate(token); + + assertThat(result).isNotNull().extracting(Result::getContent).isEqualTo(claim); + + verify(credentialClient).validate(token); + verify(rule).checkRule(eq(claim), any()); + } + + @Test + void validate_fail_whenClientFails() { + var token = TokenRepresentation.Builder.newInstance().token("test").build(); + var rule = mock(TokenValidationRule.class); + + when(validationRulesRegistry.getRules()).thenReturn(List.of(rule)); + when(credentialClient.validate(token)).thenReturn(Result.failure("failure")); + when(rule.checkRule(any(), any())).thenReturn(Result.success()); + + var result = validationService.validate(token); + + assertThat(result).isNotNull().matches(Result::failed); + + verify(credentialClient).validate(token); + verifyNoInteractions(rule); + } + + @Test + void validate_fail_whenRuleFails() { + var token = TokenRepresentation.Builder.newInstance().token("test").build(); + var rule = mock(TokenValidationRule.class); + var claim = ClaimToken.Builder.newInstance().build(); + + + when(validationRulesRegistry.getRules()).thenReturn(List.of(rule)); + when(credentialClient.validate(token)).thenReturn(Result.success(claim)); + when(rule.checkRule(any(), any())).thenReturn(Result.failure("failure")); + + var result = validationService.validate(token); + + assertThat(result).isNotNull().matches(Result::failed); + + verify(credentialClient).validate(token); + verify(rule).checkRule(eq(claim), any()); + } +} diff --git a/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/rule/SsiAudienceValidationRuleTest.java b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/rule/SsiAudienceValidationRuleTest.java new file mode 100644 index 000000000..d6a1567e7 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-core/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/rule/SsiAudienceValidationRuleTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity.rule; + +import org.eclipse.edc.jwt.spi.TokenValidationRule; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static java.util.Collections.emptyMap; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; + +public class SsiAudienceValidationRuleTest { + + private final String endpointAudience = "test-audience"; + private final TokenValidationRule rule = new SsiAudienceValidationRule(endpointAudience); + + @Test + void validAudience() { + var token = ClaimToken.Builder.newInstance() + .claim(AUDIENCE, List.of(endpointAudience)) + .build(); + + var result = rule.checkRule(token, emptyMap()); + + assertThat(result.succeeded()).isTrue(); + } + + @Test + void validationKoBecauseAudienceNotRespected() { + var token = ClaimToken.Builder.newInstance() + .claim(AUDIENCE, List.of("fake-audience")) + .build(); + + var result = rule.checkRule(token, emptyMap()); + + assertThat(result.succeeded()).isFalse(); + assertThat(result.getFailureMessages()).hasSize(1) + .contains("Token audience (aud) claim did not contain audience: test-audience"); + } + + @Test + void validationKoBecauseAudienceNotProvided() { + var token = ClaimToken.Builder.newInstance() + .build(); + + var result = rule.checkRule(token, emptyMap()); + + assertThat(result.succeeded()).isFalse(); + assertThat(result.getFailureMessages()).hasSize(1) + .contains("Required audience (aud) claim is missing in token"); + } +} diff --git a/edc-extensions/ssi/ssi-identity-extractor/build.gradle.kts b/edc-extensions/ssi/ssi-identity-extractor/build.gradle.kts new file mode 100644 index 000000000..9cbc7a854 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-extractor/build.gradle.kts @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2023 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` + `maven-publish` +} + +dependencies { + implementation(project(":spi:ssi-spi")) + implementation(libs.edc.spi.core) + implementation(libs.jakartaJson) + testImplementation(testFixtures(libs.edc.junit)) + testImplementation(testFixtures(project(":spi:ssi-spi"))) +} diff --git a/edc-extensions/ssi/ssi-identity-extractor/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/CredentialIdentityExtractor.java b/edc-extensions/ssi/ssi-identity-extractor/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/CredentialIdentityExtractor.java new file mode 100644 index 000000000..7390223cb --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-extractor/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/CredentialIdentityExtractor.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity.extractor; + +import jakarta.json.JsonObject; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.agent.ParticipantAgentServiceExtension; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdFieldExtractor; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.Optional; +import java.util.stream.Stream; + +import static org.eclipse.edc.spi.agent.ParticipantAgent.PARTICIPANT_IDENTITY; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CREDENTIAL_SUBJECT; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.HOLDER_IDENTIFIER; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.SUMMARY_CREDENTIAL_TYPE; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.VP_PROPERTY; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTypeFunctions.extractObjectsOfType; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdValueFunctions.extractStringValue; + +public class CredentialIdentityExtractor implements ParticipantAgentServiceExtension { + + private static final String IDENTITY_EXTRACTOR_PREFIX = "Identity extractor:"; + + private final JsonLdFieldExtractor holderIdentifierExtractor = JsonLdFieldExtractor.Builder.newInstance() + .field(HOLDER_IDENTIFIER) + .fieldAlias("holderIdentifier") + .errorPrefix(IDENTITY_EXTRACTOR_PREFIX) + .build(); + private final JsonLdFieldExtractor credentialSubjectExtractor = JsonLdFieldExtractor.Builder.newInstance() + .field(CREDENTIAL_SUBJECT) + .fieldAlias("credentialSubject") + .errorPrefix(IDENTITY_EXTRACTOR_PREFIX) + .build(); + + @Override + public @NotNull Map attributesFor(ClaimToken token) { + var vp = (JsonObject) token.getClaim(VP_PROPERTY); + + var extractionResult = Optional.ofNullable(vp) + .map(v -> extractObjectsOfType(SUMMARY_CREDENTIAL_TYPE, v)) + .orElse(Stream.empty()) + .map(this::extractHolderIdentifier) + .findFirst() + .orElseThrow(() -> new EdcException("Failed to extract identity from the membership credential")); + + var bpn = extractionResult.orElseThrow((failure) -> new EdcException(failure.getFailureDetail())); + return Map.of(PARTICIPANT_IDENTITY, bpn); + + } + + private Result extractHolderIdentifier(JsonObject credential) { + return this.credentialSubjectExtractor.extract(credential) + .compose(holderIdentifierExtractor::extract) + .compose(this::extractHolderIdentifierValue); + } + + private Result extractHolderIdentifierValue(JsonObject identifier) { + var bpn = extractStringValue(identifier); + if (bpn == null) { + return Result.failure("Failed to find the holder identifier"); + } else { + return Result.success(bpn); + } + } +} diff --git a/edc-extensions/ssi/ssi-identity-extractor/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/SsiIdentityExtractorExtension.java b/edc-extensions/ssi/ssi-identity-extractor/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/SsiIdentityExtractorExtension.java new file mode 100644 index 000000000..b570a3895 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-extractor/src/main/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/SsiIdentityExtractorExtension.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity.extractor; + +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.spi.agent.ParticipantAgentService; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; + +@Extension(SsiIdentityExtractorExtension.EXTENSION_NAME) +public class SsiIdentityExtractorExtension implements ServiceExtension { + + public static final String EXTENSION_NAME = "SSI Identity extractor"; + + @Inject + private ParticipantAgentService participantAgentService; + + @Override + public String name() { + return EXTENSION_NAME; + } + + @Override + public void initialize(ServiceExtensionContext context) { + participantAgentService.register(new CredentialIdentityExtractor()); + } +} diff --git a/edc-extensions/ssi/ssi-identity-extractor/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-extensions/ssi/ssi-identity-extractor/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..845bc7fc6 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-extractor/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,15 @@ +# +# Copyright (c) 2023 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 +# +# + +org.eclipse.tractusx.edc.iam.ssi.identity.extractor.SsiIdentityExtractorExtension \ No newline at end of file diff --git a/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/CredentialIdentityExtractorTest.java b/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/CredentialIdentityExtractorTest.java new file mode 100644 index 000000000..fcbb900ae --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/CredentialIdentityExtractorTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity.extractor; + +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.json.JsonObject; +import org.eclipse.edc.spi.EdcException; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.SummaryContext; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.eclipse.edc.spi.agent.ParticipantAgent.PARTICIPANT_IDENTITY; +import static org.eclipse.tractusx.edc.iam.ssi.identity.extractor.fixtures.Credentials.SIMPLE_VP; +import static org.eclipse.tractusx.edc.iam.ssi.identity.extractor.fixtures.Credentials.SUMMARY_VP_NO_HOLDER; +import static org.eclipse.tractusx.edc.iam.ssi.identity.extractor.fixtures.Credentials.SUMMARY_VP_NO_SUBJECT; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CX_SUMMARY_NS_V1; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.VP_PROPERTY; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.createObjectMapper; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.expand; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.SummaryCredential.SUMMARY_VP; + +public class CredentialIdentityExtractorTest { + + static final Map CONTEXT_CACHE = Map.of(CX_SUMMARY_NS_V1, SummaryContext.SUMMARY_CONTEXT); + + CredentialIdentityExtractor extractor = new CredentialIdentityExtractor(); + + @Test + void attributeFor() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(SUMMARY_VP, JsonObject.class), CONTEXT_CACHE); + var attributes = extractor.attributesFor(ClaimToken.Builder.newInstance().claim(VP_PROPERTY, vp).build()); + + assertThat(attributes).contains(Map.entry(PARTICIPANT_IDENTITY, "BPN of holder")); + } + + @Test + void attributeFor_exception_whenVpNotPresent() { + assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().build())) + .isInstanceOf(EdcException.class) + .hasMessage("Failed to extract identity from the membership credential"); + } + + @Test + void attributeFor_exception_whenCredentialTypeNotMatch() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(SIMPLE_VP, JsonObject.class), CONTEXT_CACHE); + assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().claim(VP_PROPERTY, vp).build())) + .isInstanceOf(EdcException.class) + .hasMessage("Failed to extract identity from the membership credential"); + } + + @Test + void attributeFor_exception_whenHolderIdentifierNotFound() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(SUMMARY_VP_NO_HOLDER, JsonObject.class), CONTEXT_CACHE); + assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().claim(VP_PROPERTY, vp).build())) + .isInstanceOf(EdcException.class) + .hasMessage("Identity extractor: no holderIdentifier found"); + } + + @Test + void attributeFor_exception_whenCredentialSubjectNotFound() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(SUMMARY_VP_NO_SUBJECT, JsonObject.class), CONTEXT_CACHE); + assertThatThrownBy(() -> extractor.attributesFor(ClaimToken.Builder.newInstance().claim(VP_PROPERTY, vp).build())) + .isInstanceOf(EdcException.class) + .hasMessage("Identity extractor: no credentialSubject found"); + } +} diff --git a/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/SsiIdentityExtractorExtensionTest.java b/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/SsiIdentityExtractorExtensionTest.java new file mode 100644 index 000000000..83abe72b6 --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/SsiIdentityExtractorExtensionTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity.extractor; + +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.agent.ParticipantAgentService; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.injection.ObjectFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +@ExtendWith(DependencyInjectionExtension.class) +public class SsiIdentityExtractorExtensionTest { + + SsiIdentityExtractorExtension extension; + + ParticipantAgentService participantAgentService = mock(ParticipantAgentService.class); + + @BeforeEach + void setup(ObjectFactory factory, ServiceExtensionContext context) { + context.registerService(ParticipantAgentService.class, participantAgentService); + extension = factory.constructInstance(SsiIdentityExtractorExtension.class); + } + + @Test + void initialize(ServiceExtensionContext context) { + extension.initialize(context); + verify(participantAgentService).register(isA(CredentialIdentityExtractor.class)); + } +} diff --git a/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/fixtures/Credentials.java b/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/fixtures/Credentials.java new file mode 100644 index 000000000..fd14612eb --- /dev/null +++ b/edc-extensions/ssi/ssi-identity-extractor/src/test/java/org/eclipse/tractusx/edc/iam/ssi/identity/extractor/fixtures/Credentials.java @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.identity.extractor.fixtures; + +public interface Credentials { + + String SIMPLE_VP = """ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential" + ], + "issuer": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "issuanceDate": "2023-06-02T12:00:00Z", + "expirationDate": "2022-06-16T18:56:59Z", + "credentialSubject": { + "id": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000" + } + } + ] + } + """; + + String SUMMARY_VP_NO_HOLDER = """ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/2023/catenax/credentials/summary/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "SummaryCredential" + ], + "issuer": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "issuanceDate": "2023-06-02T12:00:00Z", + "expirationDate": "2022-06-16T18:56:59Z", + "credentialSubject": { + "id": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000" + } + } + ] + } + """; + + String SUMMARY_VP_NO_SUBJECT = """ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/2023/catenax/credentials/summary/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "SummaryCredential" + ], + "issuer": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "issuanceDate": "2023-06-02T12:00:00Z", + "expirationDate": "2022-06-16T18:56:59Z" + } + ] + } + """; +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/README.md b/edc-extensions/ssi/ssi-miw-credential-client/README.md new file mode 100644 index 000000000..80bb2d27d --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/README.md @@ -0,0 +1,22 @@ +# MIW Client Credential Module + +This module contains an implementation of the `SsiCredentialClient` interface for SSI. +It basically narrow down to two operations: + +- obtaining a token for protocol communication +- validating the token + +For validating the token accordingly to the first milestone [here](https://github.com/eclipse-tractusx/ssi-docu/tree/main/docs/architecture/cx-3-2), the implemetation +just call the MIW for checking that the token and the VP claim inside are correct. Then extract the `JWT` claims into the `ClaimToken` for further checks. + +For obtaining a `JWT` token also it reaches the MIW, that will create a token with the `VP` claim inside. + +## Configuration + +| Key | Required | Example | Description | +|-----------------------------------------|----------|----------------|-----------------------------------| +| tx.ssi.miw.url | X | | MIW URL | +| tx.ssi.miw.authority.id | X | | BPN number of the authority | +| tx.ssi.oauth.token.url | X | | Token URL (Keycloak) | +| tx.ssi.oauth.client.id | X | | Client id | +| tx.ssi.oauth.client.secret.alias | X | | Vault alias for the client secret | diff --git a/edc-extensions/ssi/ssi-miw-credential-client/build.gradle.kts b/edc-extensions/ssi/ssi-miw-credential-client/build.gradle.kts new file mode 100644 index 000000000..e06e947e6 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/build.gradle.kts @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2023 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` + `maven-publish` +} + +dependencies { + implementation(project(":spi:ssi-spi")) + implementation(libs.edc.spi.core) + implementation(libs.edc.spi.http) + implementation(libs.edc.spi.jsonld) + implementation(libs.edc.auth.oauth2.client) + implementation(libs.edc.spi.jwt) + implementation(libs.jakartaJson) + implementation(libs.nimbus.jwt) + + testImplementation(testFixtures(libs.edc.junit)) +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwApiClientExtension.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwApiClientExtension.java new file mode 100644 index 000000000..9108d9c05 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwApiClientExtension.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw; + +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Provider; +import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.spi.http.EdcHttpClient; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl; +import org.eclipse.tractusx.edc.iam.ssi.miw.oauth2.MiwOauth2Client; + + +@Extension(SsiMiwApiClientExtension.EXTENSION_NAME) +public class SsiMiwApiClientExtension implements ServiceExtension { + + public static final String EXTENSION_NAME = "SSI MIW Api Client"; + + @Setting(value = "MIW API base url") + public static final String MIW_BASE_URL = "tx.ssi.miw.url"; + + @Setting(value = "MIW Authority ID") + public static final String MIW_AUTHORITY_ID = "tx.ssi.miw.authority.id"; + + @Inject + private MiwOauth2Client oauth2Client; + + @Inject + private EdcHttpClient httpClient; + + @Inject + private TypeManager typeManager; + + @Inject + private Monitor monitor; + + @Override + public String name() { + return EXTENSION_NAME; + } + + @Provider + public MiwApiClient apiClient(ServiceExtensionContext context) { + var baseUrl = context.getConfig().getString(MIW_BASE_URL); + var authorityId = context.getConfig().getString(MIW_AUTHORITY_ID); + + + return new MiwApiClientImpl(httpClient, baseUrl, oauth2Client, context.getParticipantId(), authorityId, typeManager.getMapper(), monitor); + } + +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwCredentialClientExtension.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwCredentialClientExtension.java new file mode 100644 index 000000000..f4503e1b6 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwCredentialClientExtension.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw; + +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Provider; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient; +import org.eclipse.tractusx.edc.iam.ssi.miw.credentials.SsiMiwCredentialClient; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; + +@Extension(SsiMiwCredentialClientExtension.EXTENSION_NAME) +public class SsiMiwCredentialClientExtension implements ServiceExtension { + + public static final String EXTENSION_NAME = "SSI MIW Credential Client"; + + @Inject + private MiwApiClient apiClient; + + @Inject + private JsonLd jsonLdService; + + @Inject + private Monitor monitor; + + @Override + public String name() { + return EXTENSION_NAME; + } + + + @Provider + public SsiCredentialClient credentialVerifier() { + return new SsiMiwCredentialClient(apiClient, jsonLdService, monitor); + } + + +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwOauth2ClientExtension.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwOauth2ClientExtension.java new file mode 100644 index 000000000..84e6630ee --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwOauth2ClientExtension.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw; + +import org.eclipse.edc.iam.oauth2.spi.client.Oauth2Client; +import org.eclipse.edc.runtime.metamodel.annotation.Extension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Provider; +import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.spi.security.Vault; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.tractusx.edc.iam.ssi.miw.oauth2.MiwOauth2Client; +import org.eclipse.tractusx.edc.iam.ssi.miw.oauth2.MiwOauth2ClientConfiguration; +import org.eclipse.tractusx.edc.iam.ssi.miw.oauth2.MiwOauth2ClientImpl; + +import java.util.Objects; + + +@Extension(SsiMiwOauth2ClientExtension.EXTENSION_NAME) +public class SsiMiwOauth2ClientExtension implements ServiceExtension { + + public static final String EXTENSION_NAME = "SSI MIW OAuth2 Client"; + + @Setting(value = "OAuth2 endpoint for requesting a token") + public static final String TOKEN_URL = "tx.ssi.oauth.token.url"; + + + @Setting(value = "OAuth2 client id") + public static final String CLIENT_ID = "tx.ssi.oauth.client.id"; + + @Setting(value = "Vault alias of OAuth2 client secret") + public static final String CLIENT_SECRET_ALIAS = "tx.ssi.oauth.client.secret.alias"; + + @Inject + private Oauth2Client oauth2Client; + + @Inject + private Vault vault; + + @Override + public String name() { + return EXTENSION_NAME; + } + + @Provider + public MiwOauth2Client oauth2Client(ServiceExtensionContext context) { + return new MiwOauth2ClientImpl(oauth2Client, createConfiguration(context)); + } + + private MiwOauth2ClientConfiguration createConfiguration(ServiceExtensionContext context) { + var tokenUrl = context.getConfig().getString(TOKEN_URL); + var clientId = context.getConfig().getString(CLIENT_ID); + var clientSecretAlias = context.getConfig().getString(CLIENT_SECRET_ALIAS); + var clientSecret = vault.resolveSecret(clientSecretAlias); + Objects.requireNonNull(clientSecret, "Client secret not found in the vault"); + + return MiwOauth2ClientConfiguration.Builder.newInstance() + .tokenUrl(tokenUrl) + .clientId(clientId) + .clientSecret(clientSecret) + .build(); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClient.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClient.java new file mode 100644 index 000000000..123c49f60 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClient.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.api; + +import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint; +import org.eclipse.edc.spi.result.Result; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +@ExtensionPoint +public interface MiwApiClient { + String VP = "vp"; + + Result>> getCredentials(Set types); + + Result> createPresentation(List> credentials, String audience); + + Result verifyPresentation(String jwtPresentation, String audience); + +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClientImpl.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClientImpl.java new file mode 100644 index 000000000..ce37d7e8b --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClientImpl.java @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.MediaType; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.eclipse.edc.spi.http.EdcHttpClient; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.miw.oauth2.MiwOauth2Client; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; + +import static java.lang.String.format; + +public class MiwApiClientImpl implements MiwApiClient { + + public static final MediaType TYPE_JSON = MediaType.parse("application/json"); + public static final String CREDENTIAL_PATH = "/api/credentials"; + public static final String PRESENTATIONS_PATH = "/api/presentations"; + public static final String PRESENTATIONS_VALIDATION_PATH = "/api/presentations/validation"; + public static final String HOLDER_IDENTIFIER = "holderIdentifier"; + + public static final String ISSUER_IDENTIFIER = "issuerIdentifier"; + public static final String VERIFIABLE_CREDENTIALS = "verifiableCredentials"; + public static final String VP_FIELD = "vp"; + public static final String CONTENT_FIELD = "content"; + private static final String PRESENTATIONS_QUERY_PARAMS = "?asJwt=true&audience=%s"; + private final EdcHttpClient httpClient; + private final String baseUrl; + private final MiwOauth2Client oauth2Client; + private final ObjectMapper mapper; + private final Monitor monitor; + + private final String authorityId; + + private final String participantId; + + public MiwApiClientImpl(EdcHttpClient httpClient, String baseUrl, MiwOauth2Client oauth2Client, String participantId, String authorityId, ObjectMapper mapper, Monitor monitor) { + this.httpClient = httpClient; + this.baseUrl = baseUrl; + this.oauth2Client = oauth2Client; + this.participantId = participantId; + this.authorityId = authorityId; + this.mapper = mapper; + this.monitor = monitor; + } + + @Override + public Result>> getCredentials(Set types) { + + var params = new ArrayList(); + params.add(format("%s=%s", ISSUER_IDENTIFIER, authorityId)); + + if (!types.isEmpty()) { + params.add(format("type=%s", String.join(",", types))); + } + + var queryParams = "?" + String.join("&", params); + var url = baseUrl + CREDENTIAL_PATH + queryParams; + + return baseRequestWithToken().map(builder -> builder.get().url(url).build()) + .compose(request -> executeRequest(request, new TypeReference>() { + })) + .compose(this::handleGetCredentialResponse); + } + + @Override + public Result> createPresentation(List> credentials, String audience) { + try { + var body = Map.of(HOLDER_IDENTIFIER, participantId, VERIFIABLE_CREDENTIALS, credentials); + var url = baseUrl + PRESENTATIONS_PATH + format(PRESENTATIONS_QUERY_PARAMS, audience); + var requestBody = RequestBody.create(mapper.writeValueAsString(body), TYPE_JSON); + + return baseRequestWithToken().map(builder -> builder.post(requestBody).url(url).build()) + .compose(request -> executeRequest(request, new TypeReference<>() { + })); + } catch (JsonProcessingException e) { + return Result.failure(e.getMessage()); + } + } + + @Override + public Result verifyPresentation(String jwtPresentation, String audience) { + try { + var body = Map.of(VP_FIELD, jwtPresentation); + var url = baseUrl + PRESENTATIONS_VALIDATION_PATH + format(PRESENTATIONS_QUERY_PARAMS, audience); + var requestBody = RequestBody.create(mapper.writeValueAsString(body), TYPE_JSON); + + return baseRequestWithToken().map(builder -> builder.post(requestBody).url(url).build()) + .compose(request -> executeRequest(request, new TypeReference>() { + })) + .compose(this::handleVerifyResult); + } catch (JsonProcessingException e) { + return Result.failure(e.getMessage()); + } + } + + private Result>> handleGetCredentialResponse(Map response) { + var content = response.get(CONTENT_FIELD); + + if (content == null) { + return Result.failure("Missing content field in the credentials response"); + } + return Result.success((List>) content); + } + + private Result handleVerifyResult(Map response) { + var valid = Optional.ofNullable(response.get("valid")) + .map(Boolean.TRUE::equals) + .orElse(false); + + if (valid) { + return Result.success(); + } else { + return Result.failure(format("Verification failed with response: %s", response)); + } + } + + private Result executeRequest(Request request, TypeReference typeReference) { + try (var response = httpClient.execute(request)) { + return handleResponse(response, typeReference); + } catch (IOException e) { + return Result.failure(e.getMessage()); + } + } + + private Result handleResponse(Response response, TypeReference tr) { + if (response.isSuccessful()) { + return handleSuccess(response, tr); + } else { + return handleError(response); + } + } + + private Result handleSuccess(Response response, TypeReference tr) { + try { + var body = Objects.requireNonNull(response.body()).string(); + return Result.success(mapper.readValue(body, tr)); + } catch (IOException e) { + monitor.debug("Failed to parse response from MIW"); + return Result.failure(e.getMessage()); + } + } + + private Result handleError(Response response) { + var msg = format("MIW API returned %s", response.code()); + monitor.debug(msg); + return Result.failure(msg); + } + + + private Result baseRequestWithToken() { + return oauth2Client.obtainRequestToken() + .map(this::baseRequestWithToken); + } + + private Request.Builder baseRequestWithToken(TokenRepresentation tokenRepresentation) { + return new Request.Builder() + .addHeader("Authorization", format("Bearer %s", tokenRepresentation.getToken())); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/credentials/SsiMiwCredentialClient.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/credentials/SsiMiwCredentialClient.java new file mode 100644 index 000000000..13c4f88cd --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/credentials/SsiMiwCredentialClient.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.credentials; + +import com.nimbusds.jwt.SignedJWT; +import jakarta.json.Json; +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.iam.TokenParameters; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient; +import org.eclipse.tractusx.edc.iam.ssi.spi.SsiCredentialClient; + +import java.text.ParseException; +import java.util.List; +import java.util.Map; + +import static org.eclipse.edc.jwt.spi.JwtRegisteredClaimNames.AUDIENCE; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient.VP; + +public class SsiMiwCredentialClient implements SsiCredentialClient { + + private final MiwApiClient apiClient; + + private final JsonLd jsonLdService; + private final Monitor monitor; + + public SsiMiwCredentialClient(MiwApiClient apiClient, JsonLd jsonLdService, Monitor monitor) { + this.apiClient = apiClient; + this.jsonLdService = jsonLdService; + this.monitor = monitor; + } + + @Override + public Result obtainClientCredentials(TokenParameters parameters) { + return apiClient.getCredentials(parameters.getAdditional().keySet()) + .compose(credentials -> createPresentation(credentials, parameters)) + .compose(this::createToken); + } + + @Override + public Result validate(TokenRepresentation tokenRepresentation) { + return extractClaims(tokenRepresentation) + .compose(claimToken -> validatePresentation(claimToken, tokenRepresentation)); + } + + private Result createToken(Map presentationResponse) { + var vp = presentationResponse.get(VP); + if (vp instanceof String) { + return Result.success(TokenRepresentation.Builder.newInstance().token((String) vp).build()); + } else { + return Result.failure("Missing or invalid format for Verifiable Presentation"); + } + } + + private Result> createPresentation(List> credentials, TokenParameters tokenParameters) { + if (!credentials.isEmpty()) { + return apiClient.createPresentation(credentials, tokenParameters.getAudience()); + } else { + return Result.failure("Cannot create a presentation from an empty credentials list"); + } + } + + private Result validatePresentation(ClaimToken claimToken, TokenRepresentation tokenRepresentation) { + return claimToken.getListClaim(AUDIENCE).stream().map(String.class::cast).findFirst() + .map(audience -> apiClient.verifyPresentation(tokenRepresentation.getToken(), audience) + .compose(v -> Result.success(claimToken))) + .orElseGet(() -> Result.failure("Required audience (aud) claim is missing in token")); + } + + private Result extractClaims(TokenRepresentation tokenRepresentation) { + try { + var jwt = SignedJWT.parse(tokenRepresentation.getToken()); + + var tokenBuilder = ClaimToken.Builder.newInstance(); + jwt.getJWTClaimsSet().getClaims().entrySet().stream() + .filter(entry -> entry.getValue() != null) + .map(this::mapClaim) + .peek(this::logIfError) + .filter(Result::succeeded) + .map(Result::getContent) + .forEach(entry -> tokenBuilder.claim(entry.getKey(), entry.getValue())); + + return Result.success(tokenBuilder.build()); + } catch (ParseException e) { + return Result.failure(e.getMessage()); + } + } + + private Result> mapClaim(Map.Entry entry) { + if (entry.getKey().equals(VP)) { + var json = Json.createObjectBuilder((Map) entry.getValue()).build(); + return jsonLdService.expand(json) + .map((expanded) -> Map.entry(entry.getKey(), expanded)); + } else { + return Result.success(entry); + } + } + + private void logIfError(Result result) { + result.onFailure(f -> monitor.warning(f.getFailureDetail())); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2Client.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2Client.java new file mode 100644 index 000000000..904fab187 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2Client.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.oauth2; + +import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; + +/** + * OAuth2 client for fetching an access token to be added when using the MIW APIs + */ +@ExtensionPoint +public interface MiwOauth2Client { + Result obtainRequestToken(); +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientConfiguration.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientConfiguration.java new file mode 100644 index 000000000..7db40126c --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientConfiguration.java @@ -0,0 +1,78 @@ + +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.oauth2; + +/** + * Configuration of the OAuth2 client + */ +public class MiwOauth2ClientConfiguration { + private String tokenUrl; + private String clientId; + + private String clientSecret; + private String scope; + + public String getScope() { + return scope; + } + + public String getClientId() { + return clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public String getTokenUrl() { + return tokenUrl; + } + + public static class Builder { + private final MiwOauth2ClientConfiguration configuration = new MiwOauth2ClientConfiguration(); + + private Builder() { + } + + public static Builder newInstance() { + return new Builder(); + } + + public Builder tokenUrl(String url) { + configuration.tokenUrl = url; + return this; + } + + public Builder clientId(String clientId) { + configuration.clientId = clientId; + return this; + } + + public Builder scope(String scope) { + configuration.scope = scope; + return this; + } + + public Builder clientSecret(String clientSecret) { + configuration.clientSecret = clientSecret; + return this; + } + + public MiwOauth2ClientConfiguration build() { + return configuration; + } + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientImpl.java b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientImpl.java new file mode 100644 index 000000000..8e14cfb05 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientImpl.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.oauth2; + +import org.eclipse.edc.iam.oauth2.spi.client.Oauth2Client; +import org.eclipse.edc.iam.oauth2.spi.client.Oauth2CredentialsRequest; +import org.eclipse.edc.iam.oauth2.spi.client.SharedSecretOauth2CredentialsRequest; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; +import org.jetbrains.annotations.NotNull; + +public class MiwOauth2ClientImpl implements MiwOauth2Client { + + private static final String GRANT_TYPE = "client_credentials"; + private final Oauth2Client oauth2Client; + + private final MiwOauth2ClientConfiguration configuration; + + public MiwOauth2ClientImpl(Oauth2Client oauth2Client, MiwOauth2ClientConfiguration configuration) { + this.oauth2Client = oauth2Client; + this.configuration = configuration; + } + + @Override + public Result obtainRequestToken() { + return oauth2Client.requestToken(createRequest()); + } + + @NotNull + private Oauth2CredentialsRequest createRequest() { + var builder = SharedSecretOauth2CredentialsRequest.Builder.newInstance() + .url(configuration.getTokenUrl()) + .clientId(configuration.getClientId()) + .clientSecret(configuration.getClientSecret()) + .grantType(GRANT_TYPE); + + if (configuration.getScope() != null) { + builder.scope(configuration.getScope()); + } + return builder.build(); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-extensions/ssi/ssi-miw-credential-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension new file mode 100644 index 000000000..36fdd24f4 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -0,0 +1,17 @@ +# +# Copyright (c) 2023 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 +# +# + +org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwCredentialClientExtension +org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwApiClientExtension +org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwOauth2ClientExtension \ No newline at end of file diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwApiClientExtensionTest.java b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwApiClientExtensionTest.java new file mode 100644 index 000000000..dbc11d343 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwApiClientExtensionTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw; + +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.edc.spi.system.injection.ObjectFactory; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwApiClientExtension.MIW_AUTHORITY_ID; +import static org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwApiClientExtension.MIW_BASE_URL; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(DependencyInjectionExtension.class) +public class SsiMiwApiClientExtensionTest { + + SsiMiwApiClientExtension extension; + + ServiceExtensionContext context; + + @BeforeEach + void setup(ObjectFactory factory, ServiceExtensionContext context) { + this.context = spy(context); + context.registerService(MiwApiClient.class, mock(MiwApiClient.class)); + context.registerService(TypeManager.class, new TypeManager()); + extension = factory.constructInstance(SsiMiwApiClientExtension.class); + } + + @Test + void initialize() { + var config = mock(Config.class); + when(context.getConfig()).thenReturn(config); + when(config.getString(MIW_BASE_URL)).thenReturn("url"); + when(config.getString(MIW_AUTHORITY_ID)).thenReturn("authorityId"); + + + assertThat(extension.apiClient(context)).isInstanceOf(MiwApiClientImpl.class); + verify(config).getString(MIW_BASE_URL); + verify(config).getString(MIW_AUTHORITY_ID); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwCredentialClientExtensionTest.java b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwCredentialClientExtensionTest.java new file mode 100644 index 000000000..f156ae0f1 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwCredentialClientExtensionTest.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw; + +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.injection.ObjectFactory; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient; +import org.eclipse.tractusx.edc.iam.ssi.miw.credentials.SsiMiwCredentialClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +@ExtendWith(DependencyInjectionExtension.class) +public class SsiMiwCredentialClientExtensionTest { + + SsiMiwCredentialClientExtension extension; + + @BeforeEach + void setup(ObjectFactory factory, ServiceExtensionContext context) { + context.registerService(MiwApiClient.class, mock(MiwApiClient.class)); + extension = factory.constructInstance(SsiMiwCredentialClientExtension.class); + } + + @Test + void initialize() { + assertThat(extension.credentialVerifier()).isInstanceOf(SsiMiwCredentialClient.class); + } + +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwOauth2ClientExtensionTest.java b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwOauth2ClientExtensionTest.java new file mode 100644 index 000000000..f91b708f4 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/SsiMiwOauth2ClientExtensionTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw; + +import org.eclipse.edc.junit.extensions.DependencyInjectionExtension; +import org.eclipse.edc.spi.security.Vault; +import org.eclipse.edc.spi.system.ServiceExtensionContext; +import org.eclipse.edc.spi.system.configuration.Config; +import org.eclipse.edc.spi.system.injection.ObjectFactory; +import org.eclipse.edc.spi.types.TypeManager; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient; +import org.eclipse.tractusx.edc.iam.ssi.miw.oauth2.MiwOauth2ClientImpl; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwOauth2ClientExtension.CLIENT_ID; +import static org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwOauth2ClientExtension.CLIENT_SECRET_ALIAS; +import static org.eclipse.tractusx.edc.iam.ssi.miw.SsiMiwOauth2ClientExtension.TOKEN_URL; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(DependencyInjectionExtension.class) +public class SsiMiwOauth2ClientExtensionTest { + + SsiMiwOauth2ClientExtension extension; + + ServiceExtensionContext context; + + Vault vault = mock(Vault.class); + + @BeforeEach + void setup(ObjectFactory factory, ServiceExtensionContext context) { + this.context = spy(context); + context.registerService(MiwApiClient.class, mock(MiwApiClient.class)); + context.registerService(TypeManager.class, new TypeManager()); + context.registerService(Vault.class, vault); + extension = factory.constructInstance(SsiMiwOauth2ClientExtension.class); + } + + @Test + void initialize() { + var config = mock(Config.class); + when(context.getConfig()).thenReturn(config); + when(config.getString(TOKEN_URL)).thenReturn("url"); + when(config.getString(CLIENT_ID)).thenReturn("clientId"); + when(config.getString(CLIENT_SECRET_ALIAS)).thenReturn("clientSecretAlias"); + when(vault.resolveSecret("clientSecretAlias")).thenReturn("clientSecret"); + + assertThat(extension.oauth2Client(context)).isInstanceOf(MiwOauth2ClientImpl.class); + verify(config).getString(TOKEN_URL); + verify(config).getString(CLIENT_ID); + verify(config).getString(CLIENT_SECRET_ALIAS); + verify(vault).resolveSecret("clientSecretAlias"); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClientImplTest.java b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClientImplTest.java new file mode 100644 index 000000000..753893be5 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/api/MiwApiClientImplTest.java @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import okhttp3.Interceptor; +import okhttp3.MediaType; +import okhttp3.Protocol; +import okhttp3.Request; +import okhttp3.Response; +import okhttp3.ResponseBody; +import okio.Buffer; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.miw.oauth2.MiwOauth2Client; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.invocation.InvocationOnMock; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.function.Consumer; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.edc.junit.testfixtures.TestUtils.testHttpClient; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl.CREDENTIAL_PATH; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl.HOLDER_IDENTIFIER; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl.PRESENTATIONS_PATH; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl.PRESENTATIONS_VALIDATION_PATH; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl.VERIFIABLE_CREDENTIALS; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClientImpl.VP_FIELD; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class MiwApiClientImplTest { + + static final String BASE_URL = "http://localhost:8080"; + Interceptor interceptor = mock(Interceptor.class); + MiwApiClientImpl client; + Monitor monitor = mock(Monitor.class); + MiwOauth2Client oauth2Client = mock(MiwOauth2Client.class); + ObjectMapper mapper = new ObjectMapper(); + + String participantId = "participantId"; + + String authorityId = "authorityId"; + + @BeforeEach + void setup() { + client = new MiwApiClientImpl(testHttpClient(interceptor), BASE_URL, oauth2Client, participantId, authorityId, mapper, monitor); + } + + @Test + void getCredentials() throws IOException { + + var credentialType = "test"; + + var response = Map.of("content", List.of(Map.of("id", "test"))); + var expectedUrl = format(BASE_URL + CREDENTIAL_PATH + "?issuerIdentifier=%s&type=%s", authorityId, credentialType); + + Consumer requestAcceptor = (request) -> { + assertThat(request.url().url().toString()).isEqualTo(expectedUrl); + }; + + when(interceptor.intercept(isA(Interceptor.Chain.class))) + .thenAnswer(invocation -> createResponse(200, invocation, requestAcceptor, response)); + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("testToken").build())); + + var result = client.getCredentials(Set.of("test")); + + assertThat(result).isNotNull().matches(Result::succeeded) + .extracting(Result::getContent) + .asList().hasSize(1); + } + + @Test + void getCredentials_fails_whenMiwFails() throws IOException { + + when(interceptor.intercept(isA(Interceptor.Chain.class))) + .thenAnswer(invocation -> createResponse(500, invocation)); + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("testToken").build())); + + var result = client.getCredentials(Set.of("test")); + + assertThat(result).isNotNull().matches(Result::failed); + } + + @Test + void getCredentials_fails_whenTokenRequestFails() { + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.failure("Token fetch failure")); + + var result = client.getCredentials(Set.of("test")); + + assertThat(result).isNotNull().matches(Result::failed); + } + + @Test + void createPresentation() throws IOException { + var audience = "audience"; + var response = Map.of("vp", Map.of()); + var expectedUrl = format(BASE_URL + PRESENTATIONS_PATH + "?asJwt=true&audience=%s", audience); + + Consumer requestAcceptor = (request) -> { + var expectedBody = Map.of(HOLDER_IDENTIFIER, participantId, VERIFIABLE_CREDENTIALS, List.of()); + var body = getBody(request, new TypeReference>() { + }); + + assertThat(body).containsAllEntriesOf(expectedBody); + + assertThat(request.url().url().toString()).isEqualTo(expectedUrl); + }; + + when(interceptor.intercept(isA(Interceptor.Chain.class))) + .thenAnswer(invocation -> createResponse(200, invocation, requestAcceptor, response)); + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("testToken").build())); + + var result = client.createPresentation(List.of(), audience); + + assertThat(result).isNotNull().matches(Result::succeeded); + } + + @Test + void createPresentation_fails_whenMiwFails() throws IOException { + + when(interceptor.intercept(isA(Interceptor.Chain.class))) + .thenAnswer(invocation -> createResponse(500, invocation)); + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("testToken").build())); + + var result = client.createPresentation(List.of(), "audience"); + + assertThat(result).isNotNull().matches(Result::failed); + } + + @Test + void createPresentation_fails_whenTokenRequestFails() { + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.failure("Token fetch failure")); + + var result = client.createPresentation(List.of(), "audience"); + + assertThat(result).isNotNull().matches(Result::failed); + } + + @Test + void verifyPresentation() throws IOException { + var jwt = "jwt"; + var verifyRequest = Map.of(VP_FIELD, jwt); + var audience = "audience"; + var expectedUrl = format(BASE_URL + PRESENTATIONS_VALIDATION_PATH + "?asJwt=true&audience=%s", audience); + + Consumer requestAcceptor = (request) -> { + + var body = getBody(request, new TypeReference>() { + }); + + assertThat(body).containsAllEntriesOf(verifyRequest); + assertThat(request.url().url().toString()).isEqualTo(expectedUrl); + }; + var verifyResponse = Map.of("valid", true); + + when(interceptor.intercept(isA(Interceptor.Chain.class))) + .thenAnswer(invocation -> createResponse(200, invocation, requestAcceptor, verifyResponse)); + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("testToken").build())); + + var result = client.verifyPresentation(jwt, "audience"); + + assertThat(result).isNotNull().matches(Result::succeeded); + } + + @Test + void verifyPresentation_fails_whenNotVerified() throws IOException { + var jwt = "jwt"; + var verifyRequest = Map.of(VP_FIELD, jwt); + var audience = "audience"; + var expectedUrl = format(BASE_URL + PRESENTATIONS_VALIDATION_PATH + "?asJwt=true&audience=%s", audience); + + Consumer requestAcceptor = (request) -> { + + var body = getBody(request, new TypeReference>() { + }); + + assertThat(body).containsAllEntriesOf(verifyRequest); + assertThat(request.url().url().toString()).isEqualTo(expectedUrl); + }; + var verifyResponse = Map.of("valid", false); + + when(interceptor.intercept(isA(Interceptor.Chain.class))) + .thenAnswer(invocation -> createResponse(200, invocation, requestAcceptor, verifyResponse)); + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("testToken").build())); + + var result = client.verifyPresentation(jwt, "audience"); + + assertThat(result).isNotNull().matches(Result::failed); + } + + @Test + void verifyPresentation_fails_whenMiwFails() throws IOException { + + when(interceptor.intercept(isA(Interceptor.Chain.class))) + .thenAnswer(invocation -> createResponse(500, invocation)); + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.success(TokenRepresentation.Builder.newInstance().token("testToken").build())); + + var result = client.verifyPresentation("jwt", "audience"); + + assertThat(result).isNotNull().matches(Result::failed); + } + + @Test + void verifyPresentation_fails_whenTokenRequestFails() throws IOException { + + when(oauth2Client.obtainRequestToken()).thenReturn(Result.failure("Token fetch failure")); + + var result = client.verifyPresentation("jwt", "audience"); + + assertThat(result).isNotNull().matches(Result::failed); + } + + + private Response createResponse(int code, InvocationOnMock invocation) { + return createResponse(code, invocation, (req) -> { + }, null); + } + + private Response createResponse(int code, InvocationOnMock invocation, Object body) { + return createResponse(code, invocation, (req) -> { + }, body); + } + + + private Response createResponse(int code, InvocationOnMock invocation, Consumer consumer, Object body) { + var bodyString = Optional.ofNullable(body).map(this::toJson).orElse(""); + var request = getRequest(invocation); + consumer.accept(request); + return new Response.Builder() + .protocol(Protocol.HTTP_1_1) + .request(request) + .code(code) + .message("") + .body(ResponseBody.create(bodyString, MediaType.parse("application/json"))) + .build(); + } + + private String toJson(Object body) { + try { + return mapper.writeValueAsString(body); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + private T getBody(Request request, TypeReference typeReference) { + try (var buffer = new Buffer()) { + Objects.requireNonNull(request.body()).writeTo(buffer); + return mapper.readValue(buffer.inputStream(), typeReference); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private Request getRequest(InvocationOnMock invocation) { + return invocation.getArgument(0, Interceptor.Chain.class).request(); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/credentials/SsiMiwCredentialClientTest.java b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/credentials/SsiMiwCredentialClientTest.java new file mode 100644 index 000000000..0164302d4 --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/credentials/SsiMiwCredentialClientTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.credentials; + +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import jakarta.json.Json; +import org.eclipse.edc.jsonld.spi.JsonLd; +import org.eclipse.edc.spi.iam.TokenParameters; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.monitor.Monitor; +import org.eclipse.edc.spi.result.Result; +import org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.security.PrivateKey; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.miw.api.MiwApiClient.VP; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +public class SsiMiwCredentialClientTest { + + private final String audience = "audience"; + SsiMiwCredentialClient credentialClient; + MiwApiClient apiClient = mock(MiwApiClient.class); + JsonLd jsonLdService = mock(JsonLd.class); + + Monitor monitor = mock(Monitor.class); + private RSAKey key; + + @BeforeEach + void setup() throws JOSEException { + credentialClient = new SsiMiwCredentialClient(apiClient, jsonLdService, monitor); + key = testKey(); + } + + @Test + void validate_success() throws JOSEException { + var claims = createClaims(Instant.now()); + var jwt = createJwt(UUID.randomUUID().toString(), claims, key.toPrivateKey()); + when(apiClient.verifyPresentation(jwt, audience)).thenReturn(Result.success()); + when(jsonLdService.expand(any())).thenReturn(Result.success(Json.createObjectBuilder().build())); + + var result = credentialClient.validate(TokenRepresentation.Builder.newInstance().token(jwt).build()); + + assertThat(result).isNotNull().matches(Result::succeeded); + verify(apiClient).verifyPresentation(jwt, audience); + } + + @Test + void validate_success_whenClientFails() throws JOSEException { + var claims = createClaims(Instant.now()); + var jwt = createJwt(UUID.randomUUID().toString(), claims, key.toPrivateKey()); + when(apiClient.verifyPresentation(jwt, audience)).thenReturn(Result.failure("fail")); + when(jsonLdService.expand(any())).thenReturn(Result.success(Json.createObjectBuilder().build())); + + var result = credentialClient.validate(TokenRepresentation.Builder.newInstance().token(jwt).build()); + + assertThat(result).isNotNull().matches(Result::failed); + verify(apiClient).verifyPresentation(jwt, audience); + } + + @Test + void validate_fail_whenInvalidToken() throws JOSEException { + + var result = credentialClient.validate(TokenRepresentation.Builder.newInstance().token("invalid").build()); + + assertThat(result).isNotNull().matches(Result::failed); + verifyNoInteractions(apiClient); + } + + @Test + void obtainCredentials_success() { + + var jwt = "serialized"; + Map credential = Map.of(); + Map presentation = Map.of(VP, jwt); + + var credentials = List.of(credential); + + when(apiClient.getCredentials(Set.of())).thenReturn(Result.success(credentials)); + when(apiClient.createPresentation(credentials, audience)).thenReturn(Result.success(presentation)); + var result = credentialClient.obtainClientCredentials(TokenParameters.Builder.newInstance().audience(audience).build()); + + assertThat(result).isNotNull() + .extracting(Result::getContent) + .extracting(TokenRepresentation::getToken) + .isEqualTo(jwt); + + verify(apiClient).getCredentials(Set.of()); + } + + private JWTClaimsSet createClaims(Instant exp) { + return new JWTClaimsSet.Builder() + .claim("foo", "bar") + .claim(VP, Map.of()) + .audience(audience) + .expirationTime(Date.from(exp)) + .build(); + } + + private String createJwt(String publicKeyId, JWTClaimsSet claimsSet, PrivateKey pk) { + var header = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(publicKeyId).build(); + try { + SignedJWT jwt = new SignedJWT(header, claimsSet); + jwt.sign(new RSASSASigner(pk)); + return jwt.serialize(); + } catch (JOSEException e) { + throw new AssertionError(e); + } + } + + private RSAKey testKey() throws JOSEException { + return new RSAKeyGenerator(2048) + .keyUse(KeyUse.SIGNATURE) // indicate the intended use of the key + .keyID(UUID.randomUUID().toString()) // give the key a unique ID + .generate(); + } +} diff --git a/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientImplTest.java b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientImplTest.java new file mode 100644 index 000000000..a92667cca --- /dev/null +++ b/edc-extensions/ssi/ssi-miw-credential-client/src/test/java/org/eclipse/tractusx/edc/iam/ssi/miw/oauth2/MiwOauth2ClientImplTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.miw.oauth2; + +import org.eclipse.edc.iam.oauth2.spi.client.Oauth2Client; +import org.eclipse.edc.iam.oauth2.spi.client.SharedSecretOauth2CredentialsRequest; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +public class MiwOauth2ClientImplTest { + + Oauth2Client oauth2Client = mock(Oauth2Client.class); + + @Test + void obtainRequestToken() { + var config = MiwOauth2ClientConfiguration.Builder.newInstance() + .tokenUrl("http://localhost:8081/token") + .clientId("client_id") + .scope("scope") + .clientSecret("client_secret") + .build(); + + var tokenRepresentation = TokenRepresentation.Builder.newInstance().token("token").build(); + when(oauth2Client.requestToken(any())).thenReturn(Result.success(tokenRepresentation)); + var client = new MiwOauth2ClientImpl(oauth2Client, config); + + var response = client.obtainRequestToken(); + assertThat(response).isNotNull().extracting(Result::getContent).isEqualTo(tokenRepresentation); + + var captor = ArgumentCaptor.forClass(SharedSecretOauth2CredentialsRequest.class); + verify(oauth2Client).requestToken(captor.capture()); + + var request = captor.getValue(); + + assertThat(request.getClientId()).isEqualTo(config.getClientId()); + assertThat(request.getClientSecret()).isEqualTo(config.getClientSecret()); + assertThat(request.getScope()).isEqualTo(config.getScope()); + assertThat(request.getUrl()).isEqualTo(config.getTokenUrl()); + + } + + @Test + void obtainRequestToken_failed() { + var config = MiwOauth2ClientConfiguration.Builder.newInstance() + .tokenUrl("http://localhost:8081/token") + .clientId("client_id") + .scope("scope") + .clientSecret("client_secret") + .build(); + + when(oauth2Client.requestToken(any())).thenReturn(Result.failure("failure")); + var client = new MiwOauth2ClientImpl(oauth2Client, config); + + var response = client.obtainRequestToken(); + assertThat(response).isNotNull().matches(Result::failed); + } +} diff --git a/edc-extensions/transferprocess-sftp-common/src/main/java/org/eclipse/tractusx/edc/transferprocess/sftp/common/SftpDataAddress.java b/edc-extensions/transferprocess-sftp-common/src/main/java/org/eclipse/tractusx/edc/transferprocess/sftp/common/SftpDataAddress.java index a9ae68638..f3cf35b18 100644 --- a/edc-extensions/transferprocess-sftp-common/src/main/java/org/eclipse/tractusx/edc/transferprocess/sftp/common/SftpDataAddress.java +++ b/edc-extensions/transferprocess-sftp-common/src/main/java/org/eclipse/tractusx/edc/transferprocess/sftp/common/SftpDataAddress.java @@ -101,7 +101,7 @@ public Builder sftpUser(SftpUser user) { this.address.getProperties().put(USER_PASSWORD, user.getPassword()); if (user.getKeyPair() != null) { this.address.getProperties().put(USER_PRIVATE_KEY, Base64.getEncoder().encodeToString(user.getKeyPair().getPrivate().getEncoded())); - this.address.getProperties().put(KEY_NAME, user.getName()); + this.address.getProperties().put(EDC_DATA_ADDRESS_KEY_NAME, user.getName()); } return this; } diff --git a/edc-tests/deployment/src/main/resources/helm/tractusx-connector-azure-vault-test.yaml b/edc-tests/deployment/src/main/resources/helm/tractusx-connector-azure-vault-test.yaml index b2c0c3db9..fe6821871 100644 --- a/edc-tests/deployment/src/main/resources/helm/tractusx-connector-azure-vault-test.yaml +++ b/edc-tests/deployment/src/main/resources/helm/tractusx-connector-azure-vault-test.yaml @@ -34,13 +34,11 @@ ## --set vault.azure.secret= fullnameOverride: tx-prod - ################################ # EDC ControlPlane + DataPlane # ################################ participant: id: "test-participant" - controlplane: service: type: NodePort @@ -54,27 +52,23 @@ controlplane: securityContext: # avoids some errors in the log: cannot write temp files of large multipart requests when R/O readOnlyRootFilesystem: false - dataplane: image: pullPolicy: Never tag: "latest" repository: "edc-dataplane-azure-vault" - securityContext: # avoids some errors in the log: cannot write temp files of large multipart requests when R/O readOnlyRootFilesystem: false - aws: endpointOverride: http://minio:9000 secretAccessKey: qwerty123 accessKeyId: qwerty123 - postgresql: - username: user - password: password - jdbcUrl: jdbc:postgresql://postgresql:5432/edc - + jdbcUrl: jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc + auth: + username: user + password: password vault: azure: name: '' @@ -82,22 +76,14 @@ vault: tenant: '' secret: certificate: - secretNames: - transferProxyTokenSignerPublicKey: daps-crt - transferProxyTokenSignerPrivateKey: daps-key transferProxyTokenEncryptionAesKey: aes-keys - dapsPrivateKey: daps-key - dapsPublicKey: daps-crt - # this must be set through CLI args: --set vault.secrets=$YOUR_VAULT_SECRETS where YOUR_VAULT_SECRETS should # be a string in the format "key1:secret1;key2:secret2;..." secrets: - -daps: - url: "http://daps:4567" - clientId: "E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65" - + server: + postStart: backendService: httpProxyTokenReceiverUrl: "http://backend:8080" - +tests: + hookDeletePolicy: before-hook-creation diff --git a/charts/tractusx-connector-memory/example.yaml b/edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml similarity index 82% rename from charts/tractusx-connector-memory/example.yaml rename to edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml index 5c2c60ca8..bf44b46f1 100644 --- a/charts/tractusx-connector-memory/example.yaml +++ b/edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml @@ -28,14 +28,12 @@ ## export DAPSKEY="" ## export DAPSCRT="" ## export YOUR_VAULT_SECRETS="daps-key:$DAPSKEY;daps-crt:$DAPSCRT" -## helm install trudy charts/tractusx-connector-memory -f charts/tractusx-connector-memory/example.yaml --set vault.secrets=$YOUR_VAULT_SECRETS +## helm install trudy charts/tractusx-connector-memory -f edc-tests/deployment/src/main/resources/helm/tractusx-connector-memory-test.yaml --set vault.secrets=$YOUR_VAULT_SECRETS --- fullnameOverride: tx-inmem - participant: id: "test-participant" - runtime: service: type: NodePort @@ -49,22 +47,25 @@ runtime: securityContext: # avoids some errors in the log: cannot write temp files of large multipart requests when R/O readOnlyRootFilesystem: false - vault: secretNames: - transferProxyTokenSignerPublicKey: daps-crt - transferProxyTokenSignerPrivateKey: daps-key transferProxyTokenEncryptionAesKey: aes-keys - dapsPrivateKey: daps-key - dapsPublicKey: daps-crt - # this must be set through CLI args: --set vault.secrets=$YOUR_VAULT_SECRETS where YOUR_VAULT_SECRETS should # be a string in the format "key1:secret1;key2:secret2;..." secrets: + server: + postStart: + - sh + - -c + - |- + { + sleep 5 -daps: - url: "http://daps:4567" - clientId: "99:83:A7:17:86:FF:98:93:CE:A0:DD:A1:F1:36:FA:F6:0F:75:0A:23:keyid:99:83:A7:17:86:FF:98:93:CE:A0:DD:A1:F1:36:FA:F6:0F:75:0A:23" + /bin/vault kv put secret/client-secret content=4bDC8/uXB6o517zqqCdrPA== + /bin/vault kv put secret/aes-keys content=YWVzX2VuY2tleV90ZXN0Cg== + } backendService: httpProxyTokenReceiverUrl: "http://backend:8080" +tests: + hookDeletePolicy: before-hook-creation diff --git a/edc-tests/deployment/src/main/resources/helm/tractusx-connector-test.yaml b/edc-tests/deployment/src/main/resources/helm/tractusx-connector-test.yaml index 5f2300a53..e622036d9 100644 --- a/edc-tests/deployment/src/main/resources/helm/tractusx-connector-test.yaml +++ b/edc-tests/deployment/src/main/resources/helm/tractusx-connector-test.yaml @@ -18,14 +18,11 @@ # fullnameOverride: tx-prod - ################################ # EDC ControlPlane + DataPlane # ################################ - participant: id: "test-participant" - controlplane: service: type: NodePort @@ -37,49 +34,39 @@ controlplane: tag: "latest" repository: "edc-controlplane-postgresql-hashicorp-vault" securityContext: - # avoids some errors in the log: cannot write temp files of large multipart requests when R/O - readOnlyRootFilesystem: false - + # avoids some errors in the log: cannot write temp files of large multipart requests when R/O + readOnlyRootFilesystem: false + ssi: + oauth: + client: + secretAlias: "client-secret" dataplane: image: pullPolicy: Never tag: "latest" repository: "edc-dataplane-hashicorp-vault" - securityContext: # avoids some errors in the log: cannot write temp files of large multipart requests when R/O readOnlyRootFilesystem: false - aws: - endpointOverride: http://minio:9000 - secretAccessKey: qwerty123 - accessKeyId: qwerty123 - + endpointOverride: http://minio:9000 + secretAccessKey: qwerty123 + accessKeyId: qwerty123 postgresql: - username: user - password: password - jdbcUrl: jdbc:postgresql://postgresql:5432/edc - + jdbcUrl: jdbc:postgresql://{{ .Release.Name }}-postgresql:5432/edc + auth: + username: user + password: password vault: hashicorp: - url: http://vault:8200 + url: http://{{ .Release.Name }}-vault:8200 token: root - secretNames: - transferProxyTokenSignerPublicKey: daps-crt - transferProxyTokenSignerPrivateKey: daps-key transferProxyTokenEncryptionAesKey: aes-keys - dapsPrivateKey: daps-key - dapsPublicKey: daps-crt - # this must be set through CLI args: --set vault.secrets=$YOUR_VAULT_SECRETS where YOUR_VAULT_SECRETS should # be a string in the format "key1:secret1;key2:secret2;..." secrets: - -daps: - url: "http://daps:4567" - clientId: "E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65:keyid:E7:07:2D:74:56:66:31:F0:7B:10:EA:B6:03:06:4C:23:7F:ED:A6:65" - backendService: httpProxyTokenReceiverUrl: "http://backend:8080" - +tests: + hookDeletePolicy: before-hook-creation diff --git a/edc-tests/deployment/src/main/resources/prepare-test.sh b/edc-tests/deployment/src/main/resources/prepare-test.sh index 51306abc8..ba3848a6b 100755 --- a/edc-tests/deployment/src/main/resources/prepare-test.sh +++ b/edc-tests/deployment/src/main/resources/prepare-test.sh @@ -25,21 +25,13 @@ if [ "$#" -lt 1 ]; then fi VALUES_FILE=$1 -KEY_FILE=daps.key -CERT_FILE=daps.cert -# generate a new short-lived certificate and export the private key -openssl req -newkey rsa:2048 -new -nodes -x509 -days 1 -keyout $KEY_FILE -out $CERT_FILE -subj "/CN=test" +CLIENT_SECRET=$(openssl rand -base64 16) +AES_KEY=$(echo aes_enckey_test | base64) +echo "$AES_KEY" > aes.key +echo "$CLIENT_SECRET" > client.secret -DAPSCRT=$(cat $CERT_FILE) -DAPSKEY=$(cat $KEY_FILE) -AES_KEY=$( echo aes_enckey_test | base64) -echo $AES_KEY > aes.key - -# replace the cert for DAPS -yq -i ".idsdaps.connectors[0].certificate=\"$DAPSCRT\"" "$VALUES_FILE" - -# add a "postStart" command to the vault config, that creates a daps-key, daps-cert and an aes-keys secret -yq -i ".vault.server.postStart |= [\"sh\",\"-c\",\"{\nsleep 5\n\ncat << EOF | /bin/vault kv put secret/daps-crt content=-\n$DAPSCRT\nEOF\n\n -cat << EOF | /bin/vault kv put secret/daps-key content=-\n$DAPSKEY\nEOF\n\n -/bin/vault kv put secret/aes-keys content=$AES_KEY\n\n}\"]" "$VALUES_FILE" \ No newline at end of file +# add a "postStart" command to the vault config, that creates a oauth client secret and an aes-keys secret +yq -i ".vault.server.postStart |= [\"sh\",\"-c\",\"{\nsleep 5\n +/bin/vault kv put secret/client-secret content=$CLIENT_SECRET\n +/bin/vault kv put secret/aes-keys content=$AES_KEY\n}\"]" "$VALUES_FILE" \ No newline at end of file diff --git a/edc-tests/e2e-tests/build.gradle.kts b/edc-tests/e2e-tests/build.gradle.kts index 63181a7ca..4b4c9deea 100644 --- a/edc-tests/e2e-tests/build.gradle.kts +++ b/edc-tests/e2e-tests/build.gradle.kts @@ -21,6 +21,7 @@ dependencies { testImplementation(project(":edc-extensions:control-plane-adapter-api")) testImplementation(libs.okhttp.mockwebserver) testImplementation(libs.restAssured) + testImplementation(libs.nimbus.jwt) testImplementation(libs.postgres) testImplementation(libs.awaitility) testImplementation(libs.aws.s3) @@ -38,8 +39,10 @@ dependencies { testImplementation(libs.edc.dsp) testImplementation(testFixtures(libs.edc.sql.core)) + testCompileOnly(project(":edc-tests:runtime:extensions")) testCompileOnly(project(":edc-tests:runtime:runtime-memory")) + testCompileOnly(project(":edc-tests:runtime:runtime-memory-ssi")) testCompileOnly(project(":edc-tests:runtime:runtime-postgresql")) } diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java index 180900841..ee7bb0689 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/helpers/PolicyHelperFunctions.java @@ -21,21 +21,15 @@ import jakarta.json.JsonObjectBuilder; import org.eclipse.edc.connector.policy.spi.PolicyDefinition; import org.eclipse.edc.policy.model.AtomicConstraint; -import org.eclipse.edc.policy.model.Operator; +import java.util.Map; import java.util.stream.Stream; +import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.CONTEXT; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.ID; import static org.eclipse.edc.jsonld.spi.JsonLdKeywords.TYPE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_ACTION_ATTRIBUTE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_CONSTRAINT_ATTRIBUTE; import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_CONSTRAINT_TYPE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_LEFT_OPERAND_ATTRIBUTE; import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_LOGICAL_CONSTRAINT_TYPE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_OPERATOR_ATTRIBUTE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_OR_CONSTRAINT_ATTRIBUTE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_PERMISSION_ATTRIBUTE; -import static org.eclipse.edc.jsonld.spi.PropertyAndTypeNames.ODRL_RIGHT_OPERAND_ATTRIBUTE; import static org.eclipse.edc.spi.CoreConstants.EDC_NAMESPACE; public class PolicyHelperFunctions { @@ -52,6 +46,16 @@ public static JsonObject businessPartnerNumberPolicy(String id, String... bpns) .build(); } + /** + * Creates a {@link PolicyDefinition} using the given ID, that contains equality constraints for each of the given BusinessPartnerNumbers: + * each BPN is converted into an {@link AtomicConstraint} {@code BusinessPartnerNumber EQ [BPN]}. + */ + public static JsonObject frameworkPolicy(String id, Map permissions) { + return policyDefinitionBuilder(frameworkPolicy(permissions)) + .add(ID, id) + .build(); + } + public static JsonObjectBuilder policyDefinitionBuilder() { return Json.createObjectBuilder() .add(TYPE, EDC_NAMESPACE + "PolicyDefinitionDto"); @@ -76,7 +80,8 @@ private static JsonObject noConstraintPolicy() { private static JsonObject bnpPolicy(String... bnps) { return Json.createObjectBuilder() - .add(ODRL_PERMISSION_ATTRIBUTE, Json.createArrayBuilder() + .add(CONTEXT, "http://www.w3.org/ns/odrl.jsonld") + .add("permission", Json.createArrayBuilder() .add(permission(bnps))) .build(); } @@ -84,26 +89,47 @@ private static JsonObject bnpPolicy(String... bnps) { private static JsonObject permission(String... bpns) { var bpnConstraints = Stream.of(bpns) - .map(bpn -> atomicConstraint(BUSINESS_PARTNER_EVALUATION_KEY, Operator.EQ, bpn)) + .map(bpn -> atomicConstraint(BUSINESS_PARTNER_EVALUATION_KEY, "eq", bpn)) .collect(Json::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::add); return Json.createObjectBuilder() - .add(ODRL_ACTION_ATTRIBUTE, "USE") - .add(ODRL_CONSTRAINT_ATTRIBUTE, Json.createObjectBuilder() + .add("action", "USE") + .add("constraint", Json.createObjectBuilder() .add(TYPE, ODRL_LOGICAL_CONSTRAINT_TYPE) - .add(ODRL_OR_CONSTRAINT_ATTRIBUTE, bpnConstraints) + .add("or", bpnConstraints) .build()) .build(); } - private static JsonObject atomicConstraint(String leftOperand, Operator operator, Object rightOperand) { + private static JsonObject frameworkPolicy(Map permissions) { return Json.createObjectBuilder() - .add(TYPE, ODRL_CONSTRAINT_TYPE) - .add(ODRL_LEFT_OPERAND_ATTRIBUTE, leftOperand) - .add(ODRL_OPERATOR_ATTRIBUTE, operator.toString()) - .add(ODRL_RIGHT_OPERAND_ATTRIBUTE, rightOperand.toString()) + .add(CONTEXT, "http://www.w3.org/ns/odrl.jsonld") + .add("permission", Json.createArrayBuilder() + .add(frameworkPermission(permissions))) .build(); } + private static JsonObject frameworkPermission(Map permissions) { + + var constraints = permissions.entrySet().stream() + .map(permission -> atomicConstraint(permission.getKey(), "eq", permission.getValue())) + .collect(Json::createArrayBuilder, JsonArrayBuilder::add, JsonArrayBuilder::add); + return Json.createObjectBuilder() + .add("action", "USE") + .add("constraint", Json.createObjectBuilder() + .add(TYPE, ODRL_LOGICAL_CONSTRAINT_TYPE) + .add("or", constraints) + .build()) + .build(); + } + + private static JsonObject atomicConstraint(String leftOperand, String operator, Object rightOperand) { + return Json.createObjectBuilder() + .add(TYPE, ODRL_CONSTRAINT_TYPE) + .add("leftOperand", leftOperand) + .add("operator", operator) + .add("rightOperand", rightOperand.toString()) + .build(); + } } diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java index 7f77f1726..5767bc2dc 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/Participant.java @@ -193,14 +193,8 @@ public String getContractAgreementId(String negotiationId) { return getContractNegotiationField(negotiationId, "contractAgreementId"); } - private String getContractNegotiationField(String negotiationId, String fieldName) { - return baseRequest() - .when() - .get("/v2/contractnegotiations/{id}", negotiationId) - .then() - .statusCode(200) - .extract().body().jsonPath() - .getString(format("'edc:%s'", fieldName)); + public String getContractNegotiationError(String negotiationId) { + return getContractNegotiationField(negotiationId, "errorDetail"); } public JsonObject getEdr(String transferProcessId) { @@ -236,7 +230,6 @@ public JsonArray getEdrEntriesByAgreementId(String agreementId) { .as(JsonArray.class); } - /** * Returns this participant's BusinessPartnerNumber (=BPN). This is constructed of the runtime name plus "-BPN" */ @@ -345,6 +338,25 @@ public String pullProxyDataByTransferProcessId(Participant provider, String tran } + public JsonObject getDatasetForAsset(Participant provider, String assetId) { + var datasets = getCatalogDatasets(provider); + return datasets.stream() + .map(JsonValue::asJsonObject) + .filter(it -> assetId.equals(getDatasetAssetId(it))) + .findFirst() + .orElseThrow(() -> new EdcException(format("No dataset for asset %s in the catalog", assetId))); + } + + private String getContractNegotiationField(String negotiationId, String fieldName) { + return baseRequest() + .when() + .get("/v2/contractnegotiations/{id}", negotiationId) + .then() + .statusCode(200) + .extract().body().jsonPath() + .getString(format("'edc:%s'", fieldName)); + } + private String getProxyData(Map body) { return proxyRequest(body) .then() @@ -360,15 +372,6 @@ private Response proxyRequest(Map body) { .post(PROXY_SUBPATH); } - public JsonObject getDatasetForAsset(Participant provider, String assetId) { - var datasets = getCatalogDatasets(provider); - return datasets.stream() - .map(JsonValue::asJsonObject) - .filter(it -> assetId.equals(getDatasetAssetId(it))) - .findFirst() - .orElseThrow(() -> new EdcException(format("No dataset for asset %s in the catalog", assetId))); - } - private RequestSpecification baseRequest() { return given() .baseUri(managementUrl) diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/ParticipantRuntime.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/ParticipantRuntime.java index 4f6c9f0ff..9feae6c68 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/ParticipantRuntime.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/ParticipantRuntime.java @@ -34,7 +34,9 @@ public class ParticipantRuntime extends EdcRuntimeExtension implements BeforeAll public ParticipantRuntime(String moduleName, String runtimeName, String bpn, Map properties) { super(moduleName, runtimeName, properties); - this.registerServiceMock(IdentityService.class, new MockDapsService(bpn)); + if (!properties.containsKey("tx.ssi.miw.url")) { + this.registerServiceMock(IdentityService.class, new MockDapsService(bpn)); + } } @Override diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java index ba0a1b20a..4fc4f4f36 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/lifecycle/TestRuntimeConfiguration.java @@ -31,27 +31,38 @@ public class TestRuntimeConfiguration { public static final String PLATO_NAME = "PLATO"; public static final String PLATO_BPN = PLATO_NAME + BPN_SUFFIX; public static final Integer PLATO_PROXIED_AAS_BACKEND_PORT = getFreePort(); + public static final int MIW_PLATO_PORT = getFreePort(); + + public static final int MIW_SOKRATES_PORT = getFreePort(); + + public static final int OAUTH_PORT = getFreePort(); + static final String DSP_PATH = "/api/v1/dsp"; static final int PLATO_CONNECTOR_PORT = getFreePort(); static final int PLATO_MANAGEMENT_PORT = getFreePort(); static final String PLATO_CONNECTOR_PATH = "/api"; static final String PLATO_MANAGEMENT_PATH = "/api/v1/management"; static final int PLATO_DSP_API_PORT = getFreePort(); - static final String PLATO_DSP_CALLBACK = "http://localhost:" + PLATO_DSP_API_PORT + DSP_PATH; + public static final String PLATO_DSP_CALLBACK = "http://localhost:" + PLATO_DSP_API_PORT + DSP_PATH; static final int SOKRATES_CONNECTOR_PORT = getFreePort(); static final int SOKRATES_MANAGEMENT_PORT = getFreePort(); static final String SOKRATES_CONNECTOR_PATH = "/api"; static final String SOKRATES_MANAGEMENT_PATH = "/api/v1/management"; static final int SOKRATES_DSP_API_PORT = getFreePort(); - static final String SOKRATES_DSP_CALLBACK = "http://localhost:" + SOKRATES_DSP_API_PORT + DSP_PATH; + public static final String SOKRATES_DSP_CALLBACK = "http://localhost:" + SOKRATES_DSP_API_PORT + DSP_PATH; static final String SOKRATES_PUBLIC_API_PORT = String.valueOf(getFreePort()); static final String PLATO_PUBLIC_API_PORT = String.valueOf(getFreePort()); static final String PLATO_DATAPLANE_CONTROL_PORT = String.valueOf(getFreePort()); static final String PLATO_DATAPLANE_PROXY_PORT = String.valueOf(getFreePort()); static final String SOKRATES_DATAPLANE_CONTROL_PORT = String.valueOf(getFreePort()); - static final String SOKRATES_DATAPLANE_PROXY_PORT = String.valueOf(getFreePort()); - + static final String DB_SCHEMA_NAME = "testschema"; + static final String MIW_SOKRATES_URL = "http://localhost:" + MIW_SOKRATES_PORT; + + static final String MIW_PLATO_URL = "http://localhost:" + MIW_PLATO_PORT; + + static final String OAUTH_TOKEN_URL = "http://localhost:" + OAUTH_PORT; + public static Map sokratesPostgresqlConfiguration() { var baseConfiguration = sokratesConfiguration(); var postgresConfiguration = postgresqlConfiguration(SOKRATES_NAME.toLowerCase()); @@ -94,10 +105,29 @@ public static Map postgresqlConfiguration(String name) { put("edc.datasource.edr.url", jdbcUrl); put("edc.datasource.edr.user", PostgresqlLocalInstance.USER); put("edc.datasource.edr.password", PostgresqlLocalInstance.PASSWORD); + // use non-default schema name to test usage of non-default schema + put("org.eclipse.tractusx.edc.postgresql.migration.schema", DB_SCHEMA_NAME); } }; } + public static Map sokratesSsiConfiguration() { + var ssiConfiguration = new HashMap() { + { + put("tx.ssi.miw.url", MIW_SOKRATES_URL); + put("tx.ssi.oauth.token.url", OAUTH_TOKEN_URL); + put("tx.ssi.oauth.client.id", "client_id"); + put("tx.ssi.oauth.client.secret.alias", "client_secret_alias"); + put("tx.ssi.miw.authority.id", "authorityId"); + put("tx.vault.seed.secrets", "client_secret_alias:client_secret"); + put("tx.ssi.endpoint.audience", SOKRATES_DSP_CALLBACK); + } + }; + var baseConfiguration = sokratesConfiguration(); + ssiConfiguration.putAll(baseConfiguration); + return ssiConfiguration; + } + public static Map sokratesConfiguration() { return new HashMap<>() { { @@ -162,8 +192,25 @@ public static Map platoConfiguration() { }; } + public static Map platoSsiConfiguration() { + var ssiConfiguration = new HashMap() { + { + put("tx.ssi.miw.url", MIW_PLATO_URL); + put("tx.ssi.oauth.token.url", OAUTH_TOKEN_URL); + put("tx.ssi.oauth.client.id", "client_id"); + put("tx.ssi.oauth.client.secret.alias", "client_secret_alias"); + put("tx.ssi.miw.authority.id", "authorityId"); + put("tx.vault.seed.secrets", "client_secret_alias:client_secret"); + put("tx.ssi.endpoint.audience", PLATO_DSP_CALLBACK); + } + }; + var baseConfiguration = platoConfiguration(); + ssiConfiguration.putAll(baseConfiguration); + return ssiConfiguration; + } + @NotNull public static String jdbcUrl(String name) { - return PostgresqlLocalInstance.JDBC_URL_PREFIX + name; + return PostgresqlLocalInstance.JDBC_URL_PREFIX + name + "?currentSchema=" + DB_SCHEMA_NAME; } } diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/AbstractDataPlaneProxyTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/AbstractDataPlaneProxyTest.java index 176662720..c5eac1e49 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/AbstractDataPlaneProxyTest.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/proxy/AbstractDataPlaneProxyTest.java @@ -47,10 +47,8 @@ public abstract class AbstractDataPlaneProxyTest { protected static final Participant SOKRATES = new Participant(SOKRATES_NAME, SOKRATES_BPN, sokratesConfiguration()); protected static final Participant PLATO = new Participant(PLATO_NAME, PLATO_BPN, platoConfiguration()); - - MockWebServer server = new MockWebServer(); - - ObjectMapper mapper = new ObjectMapper(); + private final ObjectMapper mapper = new ObjectMapper(); + private MockWebServer server; @Test @DisplayName("Verify E2E flow with Data Plane proxies and EDR") @@ -175,6 +173,7 @@ void httpPullDataTransfer_shouldFailForAsset_withTwoEdrAndProxy() throws IOExcep @BeforeEach void setup() throws IOException { + server = new MockWebServer(); server.start(PLATO_PROXIED_AAS_BACKEND_PORT); } @@ -183,7 +182,7 @@ void teardown() throws IOException { server.shutdown(); } - EventEnvelope waitForTransferCompletion() { + private EventEnvelope waitForTransferCompletion() { try { var request = server.takeRequest(20, TimeUnit.SECONDS); if (request != null) { diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/AbstractHttpConsumerPullWithProxyTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/AbstractHttpConsumerPullWithProxyTest.java index ac229c08e..73b6abaf3 100644 --- a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/AbstractHttpConsumerPullWithProxyTest.java +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/AbstractHttpConsumerPullWithProxyTest.java @@ -15,6 +15,7 @@ package org.eclipse.tractusx.edc.tests.transfer; import jakarta.json.Json; +import jakarta.json.JsonObject; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; import org.eclipse.edc.connector.contract.spi.types.negotiation.ContractNegotiationStates; @@ -71,8 +72,8 @@ void transferData_privateBackend() throws IOException, InterruptedException { PLATO.createAsset(assetId, Json.createObjectBuilder().build(), dataAddress); - PLATO.createPolicy(businessPartnerNumberPolicy("policy-1", SOKRATES.getBpn())); - PLATO.createPolicy(businessPartnerNumberPolicy("policy-2", SOKRATES.getBpn())); + PLATO.createPolicy(createTestPolicy("policy-1", SOKRATES.getBpn())); + PLATO.createPolicy(createTestPolicy("policy-2", SOKRATES.getBpn())); PLATO.createContractDefinition(assetId, "def-1", "policy-1", "policy-2"); var negotiationId = SOKRATES.negotiateContract(PLATO, assetId); @@ -128,4 +129,8 @@ void transferData_privateBackend() throws IOException, InterruptedException { void teardown() throws IOException { server.shutdown(); } + + protected JsonObject createTestPolicy(String policyId, String bpn) { + return businessPartnerNumberPolicy(policyId, bpn); + } } diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/SsiHttpConsumerPullWithProxyInMemoryTest.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/SsiHttpConsumerPullWithProxyInMemoryTest.java new file mode 100644 index 000000000..fd72a75e4 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/tests/transfer/SsiHttpConsumerPullWithProxyInMemoryTest.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.tests.transfer; + +import jakarta.json.JsonObject; +import okhttp3.mockwebserver.MockWebServer; +import org.eclipse.edc.junit.annotations.EndToEndTest; +import org.eclipse.tractusx.edc.lifecycle.ParticipantRuntime; +import org.eclipse.tractusx.edc.token.KeycloakDispatcher; +import org.eclipse.tractusx.edc.token.MiwDispatcher; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; + +import java.io.IOException; +import java.util.Map; + +import static org.eclipse.tractusx.edc.helpers.PolicyHelperFunctions.frameworkPolicy; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.MIW_PLATO_PORT; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.MIW_SOKRATES_PORT; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.OAUTH_PORT; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_DSP_CALLBACK; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.PLATO_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_BPN; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_DSP_CALLBACK; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.SOKRATES_NAME; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.platoSsiConfiguration; +import static org.eclipse.tractusx.edc.lifecycle.TestRuntimeConfiguration.sokratesSsiConfiguration; + +@EndToEndTest +public class SsiHttpConsumerPullWithProxyInMemoryTest extends AbstractHttpConsumerPullWithProxyTest { + + public static final String SUMMARY_VC_TEMPLATE = "summary-vc.json"; + @RegisterExtension + protected static final ParticipantRuntime SOKRATES_RUNTIME = new ParticipantRuntime( + ":edc-tests:runtime:runtime-memory-ssi", + SOKRATES_NAME, + SOKRATES_BPN, + sokratesSsiConfiguration() + ); + @RegisterExtension + protected static final ParticipantRuntime PLATO_RUNTIME = new ParticipantRuntime( + ":edc-tests:runtime:runtime-memory-ssi", + PLATO_NAME, + PLATO_BPN, + platoSsiConfiguration() + ); + MockWebServer miwSokratesServer = new MockWebServer(); + + MockWebServer miwPlatoServer = new MockWebServer(); + + MockWebServer oauthServer = new MockWebServer(); + + @BeforeEach + void setup() throws IOException { + miwSokratesServer.start(MIW_SOKRATES_PORT); + miwSokratesServer.setDispatcher(new MiwDispatcher(SOKRATES_BPN, SUMMARY_VC_TEMPLATE, PLATO_DSP_CALLBACK)); + + miwPlatoServer.start(MIW_PLATO_PORT); + miwPlatoServer.setDispatcher(new MiwDispatcher(PLATO_BPN, SUMMARY_VC_TEMPLATE, SOKRATES_DSP_CALLBACK)); + + oauthServer.start(OAUTH_PORT); + oauthServer.setDispatcher(new KeycloakDispatcher()); + } + + @AfterEach + void teardown() throws IOException { + miwSokratesServer.shutdown(); + miwPlatoServer.shutdown(); + oauthServer.shutdown(); + } + + @Override + protected JsonObject createTestPolicy(String policyId, String bpn) { + return frameworkPolicy(policyId, Map.of("Dismantler", "active")); + } +} diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/token/KeycloakDispatcher.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/token/KeycloakDispatcher.java new file mode 100644 index 000000000..645f934a1 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/token/KeycloakDispatcher.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.token; + +import okhttp3.mockwebserver.Dispatcher; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.RecordedRequest; +import org.eclipse.edc.spi.types.TypeManager; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +public class KeycloakDispatcher extends Dispatcher { + + private static final TypeManager MAPPER = new TypeManager(); + + public KeycloakDispatcher() { + + } + + @NotNull + @Override + public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) throws InterruptedException { + if (recordedRequest.getPath().split("\\?")[0].equals("/")) { + return createTokenResponse(); + } + return new MockResponse().setResponseCode(404); + } + + private MockResponse createTokenResponse() { + return new MockResponse().setBody(MAPPER.writeValueAsString(Map.of("access_token", "token"))); + } + +} diff --git a/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/token/MiwDispatcher.java b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/token/MiwDispatcher.java new file mode 100644 index 000000000..c0c70f9b7 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/java/org/eclipse/tractusx/edc/token/MiwDispatcher.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.token; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.nimbusds.jose.JOSEException; +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.RSAKey; +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import okhttp3.mockwebserver.Dispatcher; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.RecordedRequest; +import org.eclipse.edc.spi.types.TypeManager; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.PrivateKey; +import java.time.Instant; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + +import static java.lang.String.format; + +public class MiwDispatcher extends Dispatcher { + + private static final TypeManager MAPPER = new TypeManager(); + + private final String audience; + + private final Map summaryVc; + + public MiwDispatcher(String bpn, String vcFile, String audience) { + this.audience = audience; + var json = format(readVcContent(vcFile), bpn); + summaryVc = MAPPER.readValue(json, new TypeReference<>() { + }); + } + + @NotNull + @Override + public MockResponse dispatch(@NotNull RecordedRequest recordedRequest) throws InterruptedException { + return switch (recordedRequest.getPath().split("\\?")[0]) { + case "/api/credentials" -> credentialResponse(); + case "/api/presentations" -> presentationResponse(); + case "/api/presentations/validation" -> presentationValidationResponse(); + default -> new MockResponse().setResponseCode(404); + }; + } + + private String readVcContent(String vcFile) { + var classloader = Thread.currentThread().getContextClassLoader(); + + try (var jsonStream = classloader.getResourceAsStream(vcFile)) { + Objects.requireNonNull(jsonStream); + return new String(jsonStream.readAllBytes(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private MockResponse credentialResponse() { + return new MockResponse().setBody(MAPPER.writeValueAsString(Map.of("content", List.of(summaryVc)))); + } + + private MockResponse presentationResponse() { + try { + var jwt = createJwt(UUID.randomUUID().toString(), createClaims(Instant.now(), createVerifiablePresentationClaim()), testKey().toPrivateKey()); + return new MockResponse().setBody(MAPPER.writeValueAsString(Map.of("vp", jwt))); + } catch (JOSEException e) { + throw new RuntimeException(e); + } + } + + private Map createVerifiablePresentationClaim() { + var ctx = List.of("https://www.w3.org/2018/credentials/v1"); + var type = List.of("VerifiablePresentation"); + return Map.of( + "@context", ctx, + "type", type, + "verifiableCredential", List.of(summaryVc)); + } + + private MockResponse presentationValidationResponse() { + return new MockResponse().setBody(MAPPER.writeValueAsString(Map.of("valid", true))); + } + + private JWTClaimsSet createClaims(Instant exp, Map presentation) { + return new JWTClaimsSet.Builder() + .claim("vp", presentation) + .audience(audience) + .expirationTime(Date.from(exp)) + .build(); + } + + private String createJwt(String publicKeyId, JWTClaimsSet claimsSet, PrivateKey pk) { + var header = new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(publicKeyId).build(); + try { + SignedJWT jwt = new SignedJWT(header, claimsSet); + jwt.sign(new RSASSASigner(pk)); + return jwt.serialize(); + } catch (JOSEException e) { + throw new AssertionError(e); + } + } + + private RSAKey testKey() throws JOSEException { + return new RSAKeyGenerator(2048) + .keyUse(KeyUse.SIGNATURE) // indicate the intended use of the key + .keyID(UUID.randomUUID().toString()) // give the key a unique ID + .generate(); + } +} diff --git a/edc-tests/e2e-tests/src/test/resources/summary-vc-no-dismantler.json b/edc-tests/e2e-tests/src/test/resources/summary-vc-no-dismantler.json new file mode 100644 index 000000000..89e89a518 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/resources/summary-vc-no-dismantler.json @@ -0,0 +1,37 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/2023/catenax/credentials/summary/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "SummaryCredential" + ], + "issuer": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "issuanceDate": "2023-06-02T12:00:00Z", + "expirationDate": "2022-06-16T18:56:59Z", + "credentialSubject": { + "id": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "holderIdentifier": "%s", + "type": "Summary-List", + "name": "CX-Credentials", + "items": [ + "MembershipCredential", + "PcfCredential", + "SustainabilityCredential", + "QualityCredential", + "TraceabilityCredential", + "BehaviorTwinCredential", + "BpnCredential" + ], + "contractTemplates": "https://public.catena-x.org/contracts/" + }, + "proof": { + "type": "Ed25519Signature2018", + "created": "2023-06-02T12:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:web:example.com#key-1", + "jws": "xxxx" + } +} \ No newline at end of file diff --git a/edc-tests/e2e-tests/src/test/resources/summary-vc.json b/edc-tests/e2e-tests/src/test/resources/summary-vc.json new file mode 100644 index 000000000..70fd26a47 --- /dev/null +++ b/edc-tests/e2e-tests/src/test/resources/summary-vc.json @@ -0,0 +1,38 @@ +{ + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/2023/catenax/credentials/summary/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "SummaryCredential" + ], + "issuer": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "issuanceDate": "2023-06-02T12:00:00Z", + "expirationDate": "2022-06-16T18:56:59Z", + "credentialSubject": { + "id": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "holderIdentifier": "%s", + "type": "Summary-List", + "name": "CX-Credentials", + "items": [ + "MembershipCredential", + "DismantlerCredential", + "PcfCredential", + "SustainabilityCredential", + "QualityCredential", + "TraceabilityCredential", + "BehaviorTwinCredential", + "BpnCredential" + ], + "contractTemplates": "https://public.catena-x.org/contracts/" + }, + "proof": { + "type": "Ed25519Signature2018", + "created": "2023-06-02T12:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:web:example.com#key-1", + "jws": "xxxx" + } +} \ No newline at end of file diff --git a/edc-tests/edc-dataplane-proxy-e2e/build.gradle.kts b/edc-tests/edc-dataplane-proxy-e2e/build.gradle.kts index 50bd6598d..41fd0f220 100644 --- a/edc-tests/edc-dataplane-proxy-e2e/build.gradle.kts +++ b/edc-tests/edc-dataplane-proxy-e2e/build.gradle.kts @@ -27,9 +27,9 @@ dependencies { testImplementation(libs.edc.dpf.http) testImplementation(project(":spi:edr-cache-spi")) testImplementation(project(":core:edr-cache-core")) - testImplementation(project(":edc-dataplane:edc-dataplane-proxy-consumer-api")) - testImplementation(project(":edc-dataplane:edc-dataplane-proxy-provider-api")) - testImplementation(project(":edc-dataplane:edc-dataplane-proxy-provider-core")) + testImplementation(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-consumer-api")) + testImplementation(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-api")) + testImplementation(project(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-core")) } diff --git a/edc-tests/runtime/extensions/build.gradle.kts b/edc-tests/runtime/extensions/build.gradle.kts index b9554f001..613db089b 100644 --- a/edc-tests/runtime/extensions/build.gradle.kts +++ b/edc-tests/runtime/extensions/build.gradle.kts @@ -18,8 +18,9 @@ plugins { dependencies { - + implementation(libs.edc.core.controlplane) + implementation(libs.edc.util) // for the controller implementation(libs.jakarta.rsApi) } diff --git a/edc-tests/runtime/extensions/src/main/java/org/eclipse/tractusx/edc/lifecycle/ConsumerServicesExtension.java b/edc-tests/runtime/extensions/src/main/java/org/eclipse/tractusx/edc/lifecycle/ConsumerServicesExtension.java index a1a2ab29c..401d54b7a 100644 --- a/edc-tests/runtime/extensions/src/main/java/org/eclipse/tractusx/edc/lifecycle/ConsumerServicesExtension.java +++ b/edc-tests/runtime/extensions/src/main/java/org/eclipse/tractusx/edc/lifecycle/ConsumerServicesExtension.java @@ -20,6 +20,8 @@ import org.eclipse.edc.web.spi.WebService; public class ConsumerServicesExtension implements ServiceExtension { + + @Inject private WebService webService; @@ -27,4 +29,5 @@ public class ConsumerServicesExtension implements ServiceExtension { public void initialize(ServiceExtensionContext context) { webService.registerResource("default", new ConsumerEdrHandlerController(context.getMonitor())); } + } diff --git a/edc-tests/runtime/extensions/src/main/java/org/eclipse/tractusx/edc/lifecycle/VaultSeedExtension.java b/edc-tests/runtime/extensions/src/main/java/org/eclipse/tractusx/edc/lifecycle/VaultSeedExtension.java new file mode 100644 index 000000000..72e4abe3e --- /dev/null +++ b/edc-tests/runtime/extensions/src/main/java/org/eclipse/tractusx/edc/lifecycle/VaultSeedExtension.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.lifecycle; + +import org.eclipse.edc.runtime.metamodel.annotation.BaseExtension; +import org.eclipse.edc.runtime.metamodel.annotation.Inject; +import org.eclipse.edc.runtime.metamodel.annotation.Setting; +import org.eclipse.edc.spi.security.Vault; +import org.eclipse.edc.spi.system.ServiceExtension; +import org.eclipse.edc.spi.system.ServiceExtensionContext; + +import java.util.stream.Stream; + +@BaseExtension +public class VaultSeedExtension implements ServiceExtension { + @Setting + private static final String TX_VAULT_SEED = "tx.vault.seed.secrets"; + + @Inject + private Vault vault; + + @Override + public void initialize(ServiceExtensionContext context) { + var seedSecrets = context.getSetting(TX_VAULT_SEED, null); + if (seedSecrets != null) { + Stream.of(seedSecrets.split(";")) + .filter(pair -> pair.contains(":")) + .map(kvp -> kvp.split(":", 2)) + .filter(kvp -> kvp.length >= 2) + .forEach(pair -> vault.storeSecret(pair[0], pair[1])); + } + } +} diff --git a/edc-tests/runtime/extensions/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension b/edc-tests/runtime/extensions/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension index 619665085..022080a86 100644 --- a/edc-tests/runtime/extensions/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension +++ b/edc-tests/runtime/extensions/src/main/resources/META-INF/services/org.eclipse.edc.spi.system.ServiceExtension @@ -13,3 +13,5 @@ # org.eclipse.tractusx.edc.lifecycle.ConsumerServicesExtension +org.eclipse.tractusx.edc.lifecycle.VaultSeedExtension + diff --git a/edc-tests/runtime/runtime-memory-ssi/README.md b/edc-tests/runtime/runtime-memory-ssi/README.md new file mode 100644 index 000000000..2f9593a75 --- /dev/null +++ b/edc-tests/runtime/runtime-memory-ssi/README.md @@ -0,0 +1,3 @@ +# In-Memory Runtime for Testing Purposes + +This module provides a very small, purely in-mem runtime to execute tests against. Not intended for anything other than testing! diff --git a/edc-tests/runtime/runtime-memory-ssi/build.gradle.kts b/edc-tests/runtime/runtime-memory-ssi/build.gradle.kts new file mode 100644 index 000000000..ffd3d0aaa --- /dev/null +++ b/edc-tests/runtime/runtime-memory-ssi/build.gradle.kts @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023 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") +} + + +dependencies { + + // use basic (all in-mem) control plane + implementation(project(":edc-controlplane:edc-controlplane-base")) { + exclude("org.eclipse.edc", "oauth2-core") + exclude("org.eclipse.edc", "oauth2-daps") + exclude(module = "data-encryption") + } + implementation(project(":core:json-ld-core")) + + + implementation(project(":edc-extensions:ssi:ssi-identity-core")) + implementation(project(":edc-extensions:ssi:ssi-miw-credential-client")); + implementation(project(":edc-extensions:ssi:ssi-identity-extractor")) + implementation(project(":edc-extensions:cx-policy")) + + implementation(project(":edc-tests:runtime:extensions")) + + // use basic (all in-mem) data plane + runtimeOnly(project(":edc-dataplane:edc-dataplane-base")) { + exclude("org.eclipse.edc", "api-observability") + } + + + implementation(libs.edc.core.controlplane) + // for the controller + implementation(libs.jakarta.rsApi) +} + +application { + mainClass.set("org.eclipse.edc.boot.system.runtime.BaseRuntime") +} + +// do not publish +edcBuild { + publish.set(false) +} diff --git a/edc-tests/runtime/runtime-memory/build.gradle.kts b/edc-tests/runtime/runtime-memory/build.gradle.kts index f339202e2..8c9eb38af 100644 --- a/edc-tests/runtime/runtime-memory/build.gradle.kts +++ b/edc-tests/runtime/runtime-memory/build.gradle.kts @@ -24,7 +24,18 @@ dependencies { implementation(project(":edc-controlplane:edc-controlplane-base")) { exclude("org.eclipse.edc", "oauth2-core") exclude("org.eclipse.edc", "oauth2-daps") + +// runtimeOnly(project(":core:json-ld-core")) +// runtimeOnly(project(":edc-extensions:ssi:ssi-identity-core")) +// runtimeOnly(project(":edc-extensions:ssi:ssi-miw-credential-client")) +// runtimeOnly(project(":edc-extensions:ssi:ssi-identity-extractor")) +// runtimeOnly(project(":edc-extensions:cx-policy")) exclude(module = "data-encryption") + exclude(module = "json-ld-core") + exclude(module = "ssi-identity-core") + exclude(module = "ssi-miw-credential-client") + exclude(module = "ssi-identity-extractor") + exclude(module = "cx-policy") } implementation(project(":edc-tests:runtime:extensions")) @@ -34,7 +45,7 @@ dependencies { exclude("org.eclipse.edc", "api-observability") } - + implementation(libs.edc.core.controlplane) // for the controller implementation(libs.jakarta.rsApi) diff --git a/edc-tests/runtime/runtime-postgresql/build.gradle.kts b/edc-tests/runtime/runtime-postgresql/build.gradle.kts index 74f8003ec..85a03d538 100644 --- a/edc-tests/runtime/runtime-postgresql/build.gradle.kts +++ b/edc-tests/runtime/runtime-postgresql/build.gradle.kts @@ -22,8 +22,12 @@ dependencies { // use basic (all in-mem) control plane implementation(project(":edc-controlplane:edc-controlplane-postgresql-hashicorp-vault")) { - exclude("org.eclipse.edc", "oauth2-core") - exclude("org.eclipse.edc", "oauth2-daps") + exclude(module = "data-encryption") + exclude(module = "json-ld-core") + exclude(module = "ssi-identity-core") + exclude(module = "ssi-miw-credential-client") + exclude(module = "ssi-identity-extractor") + exclude(module = "cx-policy") exclude(module = "data-encryption") exclude(module = "hashicorp-vault") } diff --git a/gradle.properties b/gradle.properties index 4c09ddaa6..ab286d55c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,9 +1,9 @@ group=org.eclipse.tractusx.edc -version=0.4.1 +version=0.5.0-rc1 # configure the build: -annotationProcessorVersion=0.1.0 -edcGradlePluginsVersion=0.1.0 -metaModelVersion=0.1.0 +annotationProcessorVersion=0.1.1 +edcGradlePluginsVersion=0.1.1 +metaModelVersion=0.1.1 txScmConnection=scm:git:git@github.com:eclipse-tractusx/tractusx-edc.git txWebsiteUrl=https://github.com/eclipse-tractusx/tractusx-edc.git txScmUrl=https://github.com/eclipse-tractusx/tractusx-edc.git diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6fd3c16d4..66f2b5781 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -2,23 +2,28 @@ format.version = "1.1" [versions] -edc = "0.1.0" +edc = "0.1.1" postgres = "42.6.0" awaitility = "4.2.0" nimbus = "9.31" -azure-identity = "1.9.0" +azure-identity = "1.9.1" slf4j = "2.0.7" okhttp = "4.11.0" mockwebserver = "5.0.0-alpha.11" -bouncyCastle-jdk18on = "1.73" +bouncyCastle-jdk18on = "1.74" mockito = "5.2.0" -restAssured = "5.3.0" +restAssured = "5.3.1" apache-sshd = "2.10.0" -testcontainers = "1.18.2" -aws = "2.20.75" +testcontainers = "1.18.3" +aws = "2.20.89" rsApi = "3.1.0" jupiter = "5.9.3" assertj = "3.24.2" +titanium = "1.3.2" +jackson = "2.15.2" +jakarta-json = "2.0.1" +tink = "1.9.0" +iron-vc = "0.8.1" [libraries] edc-spi-catalog = { module = "org.eclipse.edc:catalog-spi", version.ref = "edc" } @@ -34,12 +39,14 @@ edc-spi-aggregateservices = { module = "org.eclipse.edc:aggregate-service-spi", edc-spi-controlplane = { module = "org.eclipse.edc:control-plane-spi", version.ref = "edc" } edc-spi-web = { module = "org.eclipse.edc:web-spi", version.ref = "edc" } edc-spi-http = { module = "org.eclipse.edc:http-spi", version.ref = "edc" } +edc-spi-jsonld = { module = "org.eclipse.edc:json-ld-spi", version.ref = "edc" } edc-spi-jwt = { module = "org.eclipse.edc:jwt-spi", version.ref = "edc" } edc-jwt-core = { module = "org.eclipse.edc:jwt-core", version.ref = "edc" } edc-spi-oauth2 = { module = "org.eclipse.edc:oauth2-spi", version.ref = "edc" } edc-util = { module = "org.eclipse.edc:util", version.ref = "edc" } edc-boot = { module = "org.eclipse.edc:boot", version.ref = "edc" } edc-config-filesystem = { module = "org.eclipse.edc:configuration-filesystem", version.ref = "edc" } +edc-jsonld = { module = "org.eclipse.edc:json-ld", version.ref = "edc" } edc-vault-filesystem = { module = "org.eclipse.edc:vault-filesystem", version.ref = "edc" } edc-core-controlplane = { module = "org.eclipse.edc:control-plane-core", version.ref = "edc" } edc-core-connector = { module = "org.eclipse.edc:connector-core", version.ref = "edc" } @@ -61,6 +68,7 @@ edc-policy-engine = { module = "org.eclipse.edc:policy-engine", version.ref = "e edc-auth-tokenbased = { module = "org.eclipse.edc:auth-tokenbased", version.ref = "edc" } edc-auth-oauth2-core = { module = "org.eclipse.edc:oauth2-core", version.ref = "edc" } edc-auth-oauth2-daps = { module = "org.eclipse.edc:oauth2-daps", version.ref = "edc" } +edc-auth-oauth2-client = { module = "org.eclipse.edc:oauth2-client", version.ref = "edc" } edc-transaction-local = { module = "org.eclipse.edc:transaction-local", version.ref = "edc" } edc-ext-http = { module = "org.eclipse.edc:http", version.ref = "edc" } edc-ext-azure-cosmos-core = { module = "org.eclipse.edc:azure-cosmos-core", version.ref = "edc" } @@ -127,8 +135,13 @@ apache-sshd-sftp = { module = "org.apache.sshd:sshd-sftp", version.ref = "apache testcontainers-junit = { module = "org.testcontainers:junit-jupiter", version.ref = "testcontainers" } aws-s3 = { module = "software.amazon.awssdk:s3", version.ref = "aws" } jakarta-rsApi = { module = "jakarta.ws.rs:jakarta.ws.rs-api", version.ref = "rsApi" } +jakartaJson = { module = "org.glassfish:jakarta.json", version.ref = "jakarta-json" } +jacksonJsonP = { module = "com.fasterxml.jackson.datatype:jackson-datatype-jakarta-jsonp", version.ref = "jackson" } +titaniumJsonLd = { module = "com.apicatalog:titanium-json-ld", version.ref = "titanium" } junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "jupiter" } assertj = { module = "org.assertj:assertj-core", version.ref = "assertj" } +tink = { module = "com.google.crypto.tink:tink", version.ref = "tink" } +apicatalog-iron-vc = { module = "com.apicatalog:iron-verifiable-credentials", version.ref = "iron-vc" } [bundles] edc-connector = ["edc.boot", "edc.core-connector", "edc.core-controlplane", "edc.api-observability"] diff --git a/settings.gradle.kts b/settings.gradle.kts index 3cd6fd9e5..05e618e2a 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -23,9 +23,12 @@ rootProject.name = "tractusx-edc" include(":spi:control-plane-adapter-spi") include(":spi:edr-cache-spi") include(":spi:core-spi") +include(":spi:ssi-spi") + // core modules include(":core:edr-cache-core") +include(":core:json-ld-core") include(":edc-extensions:business-partner-validation") @@ -42,12 +45,17 @@ include(":edc-extensions:transferprocess-sftp-provisioner") include(":edc-extensions:control-plane-adapter-api") include(":edc-extensions:control-plane-adapter-callback") include(":edc-extensions:edr-cache-sql") - +include(":edc-extensions:cx-policy") +include("edc-extensions:ssi:ssi-identity-core") +include("edc-extensions:ssi:ssi-miw-credential-client") +include("edc-extensions:ssi:jws2020-crypto-suite") +include(":edc-extensions:ssi:ssi-identity-extractor") include(":edc-tests:e2e-tests") include(":edc-tests:runtime:extensions") include(":edc-tests:runtime:runtime-memory") +include(":edc-tests:runtime:runtime-memory-ssi") include(":edc-tests:runtime:runtime-postgresql") include(":edc-tests:cucumber") @@ -58,16 +66,17 @@ include(":edc-controlplane:edc-runtime-memory") include(":edc-controlplane:edc-controlplane-memory-hashicorp-vault") include(":edc-controlplane:edc-controlplane-postgresql-azure-vault") include(":edc-controlplane:edc-controlplane-postgresql-hashicorp-vault") +include(":edc-controlplane:edc-controlplane-postgresql-hashicorp-vault-legacy") // modules for dataplane artifacts include(":edc-dataplane") include(":edc-dataplane:edc-dataplane-azure-vault") include(":edc-dataplane:edc-dataplane-base") include(":edc-dataplane:edc-dataplane-hashicorp-vault") -include(":edc-dataplane:edc-dataplane-proxy-consumer-api") -include(":edc-dataplane:edc-dataplane-proxy-provider-spi") -include(":edc-dataplane:edc-dataplane-proxy-provider-core") -include(":edc-dataplane:edc-dataplane-proxy-provider-api") +include(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-consumer-api") +include(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-spi") +include(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-core") +include(":edc-extensions:dataplane-proxy:edc-dataplane-proxy-provider-api") include(":edc-tests:edc-dataplane-proxy-e2e") diff --git a/spi/ssi-spi/build.gradle.kts b/spi/ssi-spi/build.gradle.kts new file mode 100644 index 000000000..24289ef22 --- /dev/null +++ b/spi/ssi-spi/build.gradle.kts @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2023 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` + `java-test-fixtures` +} + +dependencies { + implementation(libs.edc.spi.core) + implementation(libs.edc.spi.jwt) + implementation(libs.jakartaJson) + + testFixturesImplementation(libs.jacksonJsonP) + testFixturesImplementation(libs.titaniumJsonLd) +} diff --git a/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/SsiCredentialClient.java b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/SsiCredentialClient.java new file mode 100644 index 000000000..44e8313de --- /dev/null +++ b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/SsiCredentialClient.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi; + +import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint; +import org.eclipse.edc.spi.iam.ClaimToken; +import org.eclipse.edc.spi.iam.TokenParameters; +import org.eclipse.edc.spi.iam.TokenRepresentation; +import org.eclipse.edc.spi.result.Result; + +/** + * Obtains client security tokens from an identity provider. + * Providers may implement different authorization protocols such as OAuth2. + */ + +@ExtensionPoint +public interface SsiCredentialClient { + + /** + * Obtains a client token encoded as a JWT. + * + * @param parameters parameter object defining the token properties. + * @return generated client token. + */ + + Result obtainClientCredentials(TokenParameters parameters); + + /** + * Verifies a JWT bearer token. + * + * @param tokenRepresentation A token representation including the token to verify. + * @return Result of the validation. + */ + + Result validate(TokenRepresentation tokenRepresentation); +} diff --git a/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/SsiValidationRuleRegistry.java b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/SsiValidationRuleRegistry.java new file mode 100644 index 000000000..95bff34e3 --- /dev/null +++ b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/SsiValidationRuleRegistry.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi; + +import org.eclipse.edc.jwt.spi.TokenValidationRulesRegistry; +import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint; + +@ExtensionPoint +public interface SsiValidationRuleRegistry extends TokenValidationRulesRegistry { +} diff --git a/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/CredentialsNamespaces.java b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/CredentialsNamespaces.java new file mode 100644 index 000000000..164511ef9 --- /dev/null +++ b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/CredentialsNamespaces.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +/** + * Defines policy namespaces. + */ +public interface CredentialsNamespaces { + + String W3C_VC_PREFIX = "https://www.w3.org/2018/credentials"; + String W3C_VC_NS = W3C_VC_PREFIX + "/v1"; + String VP_PROPERTY = "vp"; + String CX_NS = "https://w3id.org/2023/catenax/credentials/"; + String CX_SUMMARY_NS = CX_NS + "summary"; + String CX_SUMMARY_NS_V1 = CX_SUMMARY_NS + "/v1"; + String SUMMARY_CREDENTIAL_TYPE = CX_SUMMARY_NS + "/SummaryCredential"; + String HOLDER_IDENTIFIER = CX_SUMMARY_NS + "/holderIdentifier"; + String CX_USE_CASE_NS = CX_NS + "usecase"; + String CX_USE_CASE_NS_V1 = CX_USE_CASE_NS + "/v1"; + String CX_SUMMARY_CREDENTIAL = "SummaryCredential"; + String CREDENTIAL_SUBJECT = W3C_VC_PREFIX + "#credentialSubject"; +} diff --git a/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdFieldExtractor.java b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdFieldExtractor.java new file mode 100644 index 000000000..12cae7254 --- /dev/null +++ b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdFieldExtractor.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +import jakarta.json.JsonObject; +import org.eclipse.edc.spi.result.Result; + +import java.util.Objects; + +import static jakarta.json.JsonValue.ValueType.ARRAY; +import static jakarta.json.JsonValue.ValueType.OBJECT; +import static java.lang.String.format; + +/** + * Extractor for field from a {@link JsonObject} with a customizable error reporting + */ +public class JsonLdFieldExtractor { + + private String fieldAlias; + private String errorPrefix = ""; + private String field; + + private JsonLdFieldExtractor() { + } + + /** + * Extract a field by name. If not found return an error. + */ + public Result extract(JsonObject root) { + var subjectArray = root.get(field); + if (subjectArray == null || subjectArray.getValueType() != ARRAY) { + return Result.failure(errorPrefix + format(" no %s found", fieldAlias)); + } + if (subjectArray.asJsonArray().size() != 1) { + return Result.failure(errorPrefix + format(" empty %s", fieldAlias)); + } + + var subjectValue = subjectArray.asJsonArray().get(0); + if (subjectValue == null || subjectValue.getValueType() != OBJECT) { + return Result.failure(errorPrefix + format(" invalid %s format", fieldAlias)); + } + return Result.success(subjectValue.asJsonObject()); + } + + public static class Builder { + + private final JsonLdFieldExtractor extractor; + + private Builder(JsonLdFieldExtractor extractor) { + this.extractor = extractor; + } + + public static Builder newInstance() { + return new Builder(new JsonLdFieldExtractor()); + } + + public Builder field(String field) { + this.extractor.field = field; + return this; + } + + public Builder fieldAlias(String fieldAlias) { + this.extractor.fieldAlias = fieldAlias; + return this; + } + + public Builder errorPrefix(String errorPrefix) { + this.extractor.errorPrefix = errorPrefix; + return this; + } + + public JsonLdFieldExtractor build() { + Objects.requireNonNull(extractor.field); + Objects.requireNonNull(extractor.fieldAlias); + Objects.requireNonNull(extractor.errorPrefix); + return extractor; + } + + } + +} diff --git a/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTypeFunctions.java b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTypeFunctions.java new file mode 100644 index 000000000..a77f8eff1 --- /dev/null +++ b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTypeFunctions.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +import jakarta.json.JsonArray; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonStructure; +import jakarta.json.JsonValue; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; + +import static java.util.Collections.emptySet; +import static java.util.stream.Collectors.toSet; + +/** + * Provides functions for working with Json-Ld types. + */ +public class JsonLdTypeFunctions { + private static final String TYPE = "@type"; + private static final Stream EMPTY_STREAM = Stream.of(); + + private JsonLdTypeFunctions() { + } + + /** + * Returns a stream of objects that are of the given Json-Ld type starting at the root. + * + * @param typeValue the type to include + * @param root the root object to traverse + * @return the stream of types + */ + public static Stream extractObjectsOfType(String typeValue, JsonStructure root) { + if (root instanceof JsonObject rootObject) { + return matchTypeValue(typeValue, rootObject.get(TYPE)) ? Stream.of(rootObject) : + extractObjectsOfType(typeValue, rootObject.values().stream()); + } else if (root instanceof JsonArray rootArray) { + return extractObjectsOfType(typeValue, rootArray.stream()); + } + return EMPTY_STREAM; + } + + /** + * Returns a stream of objects that are of the given Json-Ld type in the stream. + * + * @param typeValue the type to include + * @param stream the stream of roots to traverse + * @return the stream of types + */ + public static Stream extractObjectsOfType(String typeValue, Stream stream) { + return stream.filter(v -> v instanceof JsonStructure) + .flatMap(v -> extractObjectsOfType(typeValue, (JsonStructure) v)).filter(Objects::nonNull); + } + + /** + * Partitions a stream of objects by their type, returning a type-to-collection mapping. + */ + public static Map> partitionByType(Stream stream) { + var partitions = new HashMap>(); + stream.forEach(object -> getTypes(object).forEach(type -> partitions.computeIfAbsent(type, k -> new ArrayList<>()).add(object))); + return partitions; + } + + /** + * Returns the types associated with the object + */ + private static Set getTypes(JsonObject object) { + var result = object.get(TYPE); + if (result instanceof JsonArray resultArray) { + return resultArray.stream().filter(e -> e instanceof JsonString).map(s -> ((JsonString) s).getString()).collect(toSet()); + } else if (result instanceof JsonString resultString) { + return Set.of(resultString.getString()); + } + return emptySet(); + } + + /** + * Returns true if the type value matches the Json value. + */ + private static boolean matchTypeValue(String typeValue, JsonValue jsonValue) { + if (jsonValue instanceof JsonString stringValue) { + return typeValue.equals(stringValue.getString()); + } else if (jsonValue instanceof JsonArray arrayValue) { + return arrayValue.stream().anyMatch(v -> v instanceof JsonString && typeValue.equals(((JsonString) v).getString())); + } + return false; + } +} diff --git a/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdValueFunctions.java b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdValueFunctions.java new file mode 100644 index 000000000..3d976ae07 --- /dev/null +++ b/spi/ssi-spi/src/main/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdValueFunctions.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +import jakarta.json.JsonArray; +import jakarta.json.JsonNumber; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import jakarta.json.JsonValue; +import org.jetbrains.annotations.Nullable; + +import static jakarta.json.JsonValue.ValueType; + +/** + * Functions for working with Json-ld values. + */ +public class JsonLdValueFunctions { + private static final String VALUE = "@value"; + + private JsonLdValueFunctions() { + } + + /** + * Extracts the value of a root node and converts it to a string representation. Note this method accepts null nodes as a convenience. + */ + @Nullable + public static String extractStringValue(@Nullable JsonValue root) { + if (root == null) { + return null; + } else if (root instanceof JsonArray rootArray) { + if (rootArray.isEmpty()) { + return null; + } + var jsonValue = rootArray.get(0); + return (jsonValue instanceof JsonObject elementObject) ? convertType(elementObject.get(VALUE)) : null; + } else if (root instanceof JsonObject rootObject) { + return convertType(rootObject.get(VALUE)); + } else { + return convertType(root); + } + } + + /** + * Converts the value to a string representation. + */ + @Nullable + private static String convertType(JsonValue value) { + if (value instanceof JsonString valueString) { + return valueString.getString(); + } else if (value instanceof JsonNumber valueNumber) { + return valueNumber.isIntegral() ? String.valueOf(valueNumber.longValue()) : String.valueOf(valueNumber.doubleValue()); + } else if (ValueType.TRUE == value.getValueType()) { + return "TRUE"; + } else if (ValueType.FALSE == value.getValueType()) { + return "FALSE"; + } + return null; + } +} diff --git a/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdFieldExtractorTest.java b/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdFieldExtractorTest.java new file mode 100644 index 000000000..b994057c2 --- /dev/null +++ b/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdFieldExtractorTest.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +import jakarta.json.JsonObject; +import org.eclipse.edc.spi.result.Result; +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CREDENTIAL_SUBJECT; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.CX_SUMMARY_NS_V1; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.HOLDER_IDENTIFIER; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.SUMMARY_CREDENTIAL_TYPE; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.createObjectMapper; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.expand; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTypeFunctions.extractObjectsOfType; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.SummaryCredential.SUMMARY_VP; + +public class JsonLdFieldExtractorTest { + + private static final Map CONTEXT_CACHE = Map.of(CX_SUMMARY_NS_V1, SummaryContext.SUMMARY_CONTEXT); + + @Test + void extract() throws Exception { + var vp = expand(createObjectMapper().readValue(SUMMARY_VP, JsonObject.class), CONTEXT_CACHE); + + var extractor = JsonLdFieldExtractor.Builder.newInstance() + .field(CREDENTIAL_SUBJECT) + .fieldAlias("credentialSubject") + .errorPrefix("prefix") + .build(); + + + var summaryCredential = extractObjectsOfType(SUMMARY_CREDENTIAL_TYPE, vp).findFirst().orElseThrow(); + + var subject = extractor.extract(summaryCredential); + assertThat(subject).matches(Result::succeeded).extracting(Result::getContent) + .satisfies(jsonObject -> assertThat(jsonObject.containsKey(HOLDER_IDENTIFIER)).isTrue()); + + } + + @Test + void extract_fail() throws Exception { + var vp = expand(createObjectMapper().readValue(SUMMARY_VP, JsonObject.class), CONTEXT_CACHE); + + var extractor = JsonLdFieldExtractor.Builder.newInstance() + .field(HOLDER_IDENTIFIER) + .fieldAlias("holderIdentifier") + .errorPrefix("prefix") + .build(); + + var summaryCredential = extractObjectsOfType(SUMMARY_CREDENTIAL_TYPE, vp).findFirst().orElseThrow(); + + var subject = extractor.extract(summaryCredential); + assertThat(subject).matches(Result::failed).extracting(Result::getFailureDetail) + .satisfies(errorMessage -> { + assertThat(errorMessage).isEqualTo("prefix no holderIdentifier found"); + }); + + } +} diff --git a/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTypeFunctionsTest.java b/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTypeFunctionsTest.java new file mode 100644 index 000000000..7aed90107 --- /dev/null +++ b/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTypeFunctionsTest.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +import com.fasterxml.jackson.core.JsonProcessingException; +import jakarta.json.JsonObject; +import jakarta.json.JsonString; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; + +import static java.lang.String.format; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.W3C_VC_PREFIX; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.createObjectMapper; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTextFixtures.expand; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTypeFunctions.extractObjectsOfType; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdTypeFunctions.partitionByType; + +class JsonLdTypeFunctionsTest { + private static final String TYPE = "@type"; + private static final String VC_TYPE = W3C_VC_PREFIX + "#VerifiableCredential"; + + private static final String BAR_CREDENTIAL_TYPE = "BarCredential"; + private static final String FOO_CREDENTIAL_TYPE = "FooCredential"; + private static final String FOO_CREDENTIAL = """ + { + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "FooCredential" + ] + } + ] + }"""; + private static final String BAR_CREDENTIAL = """ + { + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": [ + "VerifiableCredential", + "BarCredential" + ] + } + ] + }"""; + private static final String MULTIPLE_VCS_CLAIM = format(""" + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + { + "vp":"test:vp" + } + ], + "vp": [%s,%s] + }""", FOO_CREDENTIAL, BAR_CREDENTIAL); + private static final String SINGLE_VC_CLAIM = format(""" + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + { + "vp":"test:vp" + } + ], + "vp": %s + }""", FOO_CREDENTIAL); + + @Test + void verify_credential_extraction() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(SINGLE_VC_CLAIM, JsonObject.class), Map.of()); + + var credentials = extractObjectsOfType(VC_TYPE, vp).toList(); + + assertThat(credentials.size()).isEqualTo(1); + assertAllOfType(FOO_CREDENTIAL_TYPE, credentials); + } + + @Test + void verify_partitions_based_on_type() throws JsonProcessingException { + var vp = expand(createObjectMapper().readValue(MULTIPLE_VCS_CLAIM, JsonObject.class), Map.of()); + + var credentials = extractObjectsOfType(VC_TYPE, vp); + var partitions = partitionByType(credentials); + + assertThat(partitions.size()).isEqualTo(3); + + assertAllOfType(FOO_CREDENTIAL_TYPE, partitions.get(FOO_CREDENTIAL_TYPE)); + assertAllOfType(BAR_CREDENTIAL_TYPE, partitions.get(BAR_CREDENTIAL_TYPE)); + assertThat(partitions.get(VC_TYPE).size()).isEqualTo(2); + } + + /** + * Asserts that all objects in the collection are of a given type. + */ + private void assertAllOfType(String type, List objects) { + assertThat(objects.stream() + .flatMap(object -> object.get(TYPE).asJsonArray().stream()) + .filter(value -> value instanceof JsonString) + .filter(entryType -> type.equals(((JsonString) entryType).getString())) + .count()).isEqualTo(objects.size()); + } + + +} diff --git a/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdValueFunctionsTest.java b/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdValueFunctionsTest.java new file mode 100644 index 000000000..a79d59b06 --- /dev/null +++ b/spi/ssi-spi/src/test/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdValueFunctionsTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +import org.junit.jupiter.api.Test; + +import static jakarta.json.Json.createArrayBuilder; +import static jakarta.json.Json.createObjectBuilder; +import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.JsonLdValueFunctions.extractStringValue; + +class JsonLdValueFunctionsTest { + private static final String VALUE = "@value"; + + @Test + void validate_nested_array() { + var root = createArrayBuilder() + .add(createObjectBuilder().add(VALUE, "test").build()) + .build(); + + assertThat(extractStringValue(root)).isEqualTo("test"); + } + + @Test + void validate_empty_array() { + var root = createArrayBuilder().build(); + assertThat(extractStringValue(root)).isNull(); + } + + @Test + void validate_object() { + var root = createObjectBuilder().add(VALUE, "test").build(); + assertThat(extractStringValue(root)).isEqualTo("test"); + } + + @Test + void validate_object_int() { + var root = createObjectBuilder().add(VALUE, 1).build(); + assertThat(extractStringValue(root)).isEqualTo("1"); + } + + @Test + void validate_object_double() { + var root = createObjectBuilder().add(VALUE, 1.1d).build(); + assertThat(extractStringValue(root)).isEqualTo("1.1"); + } + + @Test + void validate_null() { + assertThat(extractStringValue(null)).isNull(); + } + +} diff --git a/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTextFixtures.java b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTextFixtures.java new file mode 100644 index 000000000..10b3ab552 --- /dev/null +++ b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/JsonLdTextFixtures.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +import com.apicatalog.jsonld.JsonLdError; +import com.apicatalog.jsonld.JsonLdOptions; +import com.apicatalog.jsonld.document.JsonDocument; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import com.fasterxml.jackson.datatype.jsonp.JSONPModule; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import jakarta.json.Json; +import jakarta.json.JsonObject; + +import java.io.StringReader; +import java.util.HashMap; +import java.util.Map; + +import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.CredentialsNamespaces.W3C_VC_NS; +import static org.eclipse.tractusx.edc.iam.ssi.spi.jsonld.W3cVcContext.W3C_VC_CONTEXT; + +/** + * Test helpers for processing Json-Ld. + */ +public class JsonLdTextFixtures { + + /** + * Creates a mapper configured to support Json-Ld processing. + */ + public static ObjectMapper createObjectMapper() { + var mapper = new ObjectMapper(); + mapper.configure(FAIL_ON_UNKNOWN_PROPERTIES, false); + mapper.registerModule(new JavaTimeModule()); + mapper.registerModule(new JSONPModule()); + var module = new SimpleModule() { + @Override + public void setupModule(SetupContext context) { + super.setupModule(context); + } + }; + mapper.registerModule(module); + return mapper; + } + + /** + * Performs Json-Ld compaction on an object. + */ + public static JsonObject compact(JsonObject json) { + try { + var document = JsonDocument.of(json); + var jsonFactory = Json.createBuilderFactory(Map.of()); + var contextDocument = JsonDocument.of(jsonFactory.createObjectBuilder().build()); + return com.apicatalog.jsonld.JsonLd.compact(document, contextDocument).get(); + } catch (JsonLdError e) { + throw new AssertionError(e); + } + } + + /** + * Expands the document using the provided cache for resolving referenced contexts. The {@link CredentialsNamespaces#W3C_VC_NS} context is implicitly added to the cache. + */ + public static JsonObject expand(JsonObject json, Map contextCache) { + var map = new HashMap<>(contextCache); + map.put(W3C_VC_NS, W3C_VC_CONTEXT); + try { + var document = JsonDocument.of(json); + var options = new JsonLdOptions((url, options1) -> JsonDocument.of(new StringReader(map.get(url.toString())))); + var expanded = com.apicatalog.jsonld.JsonLd.expand(document).options(options).get(); + if (expanded.size() > 0) { + return expanded.getJsonObject(0); + } + return Json.createObjectBuilder().build(); + } catch (JsonLdError e) { + throw new AssertionError(e); + } + } +} diff --git a/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/SummaryContext.java b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/SummaryContext.java new file mode 100644 index 000000000..245d96722 --- /dev/null +++ b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/SummaryContext.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +/** + * Defines the summary context. + */ +public interface SummaryContext { + String SUMMARY_CONTEXT = """ + { + "@context": { + "@version": 1.1, + "@protected": true, + "summary": "https://w3id.org/2023/catenax/credentials/summary/", + "id": "@id", + "type": "@type", + "SummaryCredential" : { + "@id":"summary:SummaryCredential" + }, + "holderIdentifier": { + "@id": "summary:holderIdentifier" + }, + "name": { + "@id": "summary:name", + "@type": "https://schema.org/Text" + }, + "items": { + "@id": "summary:items", + "@type": "https://schema.org/Text" + }, + "contract-template": { + "@id": "summary:contract-template", + "@type": "https://schema.org/Text" + } + } + }"""; +} diff --git a/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/SummaryCredential.java b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/SummaryCredential.java new file mode 100644 index 000000000..7f190449b --- /dev/null +++ b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/SummaryCredential.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +/** + * Sample summary credential. + */ +public interface SummaryCredential { + String SUMMARY_VP = """ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1" + ], + "type": "VerifiablePresentation", + "verifiableCredential": [ + { + "@context": [ + "https://www.w3.org/2018/credentials/v1", + "https://w3id.org/2023/catenax/credentials/summary/v1" + ], + "id": "urn:uuid:12345678-1234-1234-1234-123456789abc", + "type": [ + "VerifiableCredential", + "SummaryCredential" + ], + "issuer": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "issuanceDate": "2023-06-02T12:00:00Z", + "expirationDate": "2022-06-16T18:56:59Z", + "credentialSubject": { + "id": "did:web:a016-203-129-213-99.ngrok-free.app:BPNL000000000000", + "holderIdentifier": "BPN of holder", + "type": "Summary-List", + "name": "CX-Credentials", + "items": [ + "MembershipCredential", + "DismantlerCredential", + "PcfCredential", + "SustainabilityCredential", + "QualityCredential", + "TraceabilityCredential", + "BehaviorTwinCredential", + "BpnCredential" + ], + "contractTemplates": "https://public.catena-x.org/contracts/" + }, + "proof": { + "type": "Ed25519Signature2018", + "created": "2023-06-02T12:00:00Z", + "proofPurpose": "assertionMethod", + "verificationMethod": "did:web:example.com#key-1", + "jws": "xxxx" + } + } + ] + } + """; +} diff --git a/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/W3cVcContext.java b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/W3cVcContext.java new file mode 100644 index 000000000..f84193b7e --- /dev/null +++ b/spi/ssi-spi/src/testFixtures/java/org/eclipse/tractusx/edc/iam/ssi/spi/jsonld/W3cVcContext.java @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2023 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.tractusx.edc.iam.ssi.spi.jsonld; + +/** + * Local copy of the W3C VC data model context for testing, obtained from {@code https://www.w3.org/ns/credentials/v2}. + */ +public interface W3cVcContext { + + String W3C_VC_CONTEXT = """ + { + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "VerifiableCredential": { + "@id": "https://www.w3.org/2018/credentials#VerifiableCredential", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "credentialSchema": { + "@id": "cred:credentialSchema", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + + "JsonSchemaValidator2018": "cred:JsonSchemaValidator2018" + } + }, + "credentialStatus": {"@id": "cred:credentialStatus", "@type": "@id"}, + "credentialSubject": {"@id": "cred:credentialSubject", "@type": "@id"}, + "evidence": {"@id": "cred:evidence", "@type": "@id"}, + "expirationDate": {"@id": "cred:expirationDate", "@type": "xsd:dateTime"}, + "holder": {"@id": "cred:holder", "@type": "@id"}, + "issued": {"@id": "cred:issued", "@type": "xsd:dateTime"}, + "issuer": {"@id": "cred:issuer", "@type": "@id"}, + "issuanceDate": {"@id": "cred:issuanceDate", "@type": "xsd:dateTime"}, + "proof": {"@id": "sec:proof", "@type": "@id", "@container": "@graph"}, + "refreshService": { + "@id": "cred:refreshService", + "@type": "@id", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + + "ManualRefreshService2018": "cred:ManualRefreshService2018" + } + }, + "termsOfUse": {"@id": "cred:termsOfUse", "@type": "@id"}, + "validFrom": {"@id": "cred:validFrom", "@type": "xsd:dateTime"}, + "validUntil": {"@id": "cred:validUntil", "@type": "xsd:dateTime"} + } + }, + + "VerifiablePresentation": { + "@id": "https://www.w3.org/2018/credentials#VerifiablePresentation", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "cred": "https://www.w3.org/2018/credentials#", + "sec": "https://w3id.org/security#", + + "holder": {"@id": "cred:holder", "@type": "@id"}, + "proof": {"@id": "sec:proof", "@type": "@id", "@container": "@graph"}, + "verifiableCredential": {"@id": "cred:verifiableCredential", "@type": "@id", "@container": "@graph"} + } + }, + + "EcdsaSecp256k1Signature2019": { + "@id": "https://w3id.org/security#EcdsaSecp256k1Signature2019", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "EcdsaSecp256r1Signature2019": { + "@id": "https://w3id.org/security#EcdsaSecp256r1Signature2019", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "Ed25519Signature2018": { + "@id": "https://w3id.org/security#Ed25519Signature2018", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + "xsd": "http://www.w3.org/2001/XMLSchema#", + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "RsaSignature2018": { + "@id": "https://w3id.org/security#RsaSignature2018", + "@context": { + "@version": 1.1, + "@protected": true, + + "challenge": "sec:challenge", + "created": {"@id": "http://purl.org/dc/terms/created", "@type": "xsd:dateTime"}, + "domain": "sec:domain", + "expires": {"@id": "sec:expiration", "@type": "xsd:dateTime"}, + "jws": "sec:jws", + "nonce": "sec:nonce", + "proofPurpose": { + "@id": "sec:proofPurpose", + "@type": "@vocab", + "@context": { + "@version": 1.1, + "@protected": true, + + "id": "@id", + "type": "@type", + + "sec": "https://w3id.org/security#", + + "assertionMethod": {"@id": "sec:assertionMethod", "@type": "@id", "@container": "@set"}, + "authentication": {"@id": "sec:authenticationMethod", "@type": "@id", "@container": "@set"} + } + }, + "proofValue": "sec:proofValue", + "verificationMethod": {"@id": "sec:verificationMethod", "@type": "@id"} + } + }, + + "proof": {"@id": "https://w3id.org/security#proof", "@type": "@id", "@container": "@graph"} + } + } + """; + + +}