Skip to content

Commit

Permalink
Merge pull request #8 from catenax-ng/allow-list-did-config
Browse files Browse the repository at this point in the history
Allow list did config
  • Loading branch information
jpbu committed Feb 9, 2023
2 parents 5b90dae + 5d05dc8 commit 985184c
Show file tree
Hide file tree
Showing 29 changed files with 364 additions and 50 deletions.
1 change: 1 addition & 0 deletions .env.docker
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ MIW_NAME=Base-Wallet
MIW_BPN=BPNL000000000000
MIW_SHORT_DID=replace-short-did-of-endorser
MIW_VERKEY=replace-verjkey-of-endorser
MIW_ALLOWLIST_DIDS=
MIW_MEMBERSHIP_ORG=replace-name-of-organisation

MIW_DB_JDBC_URL=jdbc:postgresql://db-host-placeholder:5432/db-name-placeholder?user=db-user-placeholder&password=db-password-placeholder
Expand Down
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ MIW_BPN="BPNL000000000000"
MIW_SHORT_DID="replace-short-did-of-endorser"
# The verkey of the base wallet DID
MIW_VERKEY="replace-verjkey-of-endorser"
MIW_ALLOWLIST_DIDS=
MIW_MEMBERSHIP_ORG="replace-name-of-organisation"

# Database connection
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ below. Here a few hints on how to set it up:
| `MIW_DID` | String | DID of the base wallet, this wallet must be registered on ledger with the endorser role |
| `MIW_VERKEY` | String | Verification key of the base wallet, this wallet must be registered on ledger with the endorser role |
| `MIW_NAME` | String | Name of the base wallet |
|`MIW_ALLOWLIST_DIDS` | String | List of full DIDs seperated by comma ",". Those DIDs are allowed to send a connection request to managed wallets. Empty for public invitation allowance |
| `MIW_MEMBERSHIP_ORG` | String | The name used in the Membership credential |
| `BPDM_DATAPOOL_URL` | String | BPDM data pool API endpoint |
| `BPDM_AUTH_CLIENT_ID` | String | client id for accessing the BPDM data pool endpoint |
Expand Down
4 changes: 2 additions & 2 deletions charts/managed-identity-wallets/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ 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.6.8
appVersion: 3.1.2
version: 0.6.9
appVersion: 3.2.0

dependencies:
- name: postgresql
Expand Down
5 changes: 3 additions & 2 deletions charts/managed-identity-wallets/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# managed-identity-wallets

![Version: 0.6.8](https://img.shields.io/badge/Version-0.6.8-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 3.1.2](https://img.shields.io/badge/AppVersion-3.1.2-informational?style=flat-square)
![Version: 0.6.9](https://img.shields.io/badge/Version-0.6.9-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 3.2.0](https://img.shields.io/badge/AppVersion-3.2.0-informational?style=flat-square)

Managed Identity Wallets Service

Expand Down Expand Up @@ -42,6 +42,7 @@ Managed Identity Wallets Service
| wallet.baseWalletShortDid | string | `""` | The short DID of the base wallet. It can be created with its verkey as described in https://github.com/eclipse-tractusx/managed-identity-wallets#Integrate-with-Indy-Ledger. It should be registered on the Indy ledger with role endorser. |
| wallet.baseWalletVerkey | string | `""` | The verkey (public key) of the base wallet |
| wallet.baseWalletName | string | `""` | The name of the base wallet |
| wallet.allowlistDids | string | `""` | A list of full DIDs seperated by comma ",". Those DIDs are allowed to send a connection request to managed wallets. Empty for public invitation allowance |
| wallet.membershipOrganisation | string | `"Platform-A"` | The name used in the Membership credential |
| revocation.refreshHour | string | `"3"` | At which hour (24-hour clock) the cron job should issue/update status-list credentials |
| revocation.revocationServiceUrl | string | `"http://localhost:8086"` | The url of the revocation service |
Expand Down Expand Up @@ -103,7 +104,7 @@ Managed Identity Wallets Service
| postgresql.primary.extraVolumes[0].name | string | `"initdb"` | |
| postgresql.primary.extraVolumes[0].emptyDir | object | `{}` | |
| postgresql.primary.initContainers[0].name | string | `"initdb"` | |
| postgresql.primary.initContainers[0].image | string | `"ghcr.io/catenax-ng/tx-managed-identity-wallets_initdb:3.1.2"` | The image is built and used to initialize the database of MIW. The tag must equal the appVersion in Chart.yaml |
| postgresql.primary.initContainers[0].image | string | `"ghcr.io/catenax-ng/tx-managed-identity-wallets_initdb:3.2.0"` | The image is built and used to initialize the database of MIW. The tag must equal the appVersion in Chart.yaml |
| postgresql.primary.initContainers[0].imagePullPolicy | string | `"Always"` | |
| postgresql.primary.initContainers[0].command[0] | string | `"sh"` | |
| postgresql.primary.initContainers[0].args[0] | string | `"-c"` | |
Expand Down
2 changes: 2 additions & 0 deletions charts/managed-identity-wallets/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ spec:
value: {{ .Values.wallet.baseWalletVerkey }}
- name: MIW_NAME
value: {{ .Values.wallet.baseWalletName }}
- name: MIW_ALLOWLIST_DIDS
value: {{ .Values.wallet.allowlistDids }}
- name: MIW_MEMBERSHIP_ORG
value: {{ .Values.wallet.membershipOrganisation }}
- name: MIW_OPENAPI_TITLE
Expand Down
4 changes: 3 additions & 1 deletion charts/managed-identity-wallets/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ wallet:
baseWalletVerkey: ""
# -- The name of the base wallet
baseWalletName: ""
# -- A list of full DIDs seperated by comma ",". Those DIDs are allowed to send a connection request to managed wallets. Empty for public invitation allowance
allowlistDids: ""
# -- The name used in the Membership credential
membershipOrganisation: "Platform-A"
# The configuration of revocation service in MIW
Expand Down Expand Up @@ -167,7 +169,7 @@ postgresql:
initContainers:
- name: initdb
# -- The image is built and used to initialize the database of MIW. The tag must equal the appVersion in Chart.yaml
image: ghcr.io/catenax-ng/tx-managed-identity-wallets_initdb:3.1.2
image: ghcr.io/catenax-ng/tx-managed-identity-wallets_initdb:3.2.0
imagePullPolicy: Always
command:
- sh
Expand Down
5 changes: 3 additions & 2 deletions docs/ExternalWalletInteraction.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
- Send a presentation to external wallet as defined in [Aries RFC 0454](https://github.com/hyperledger/aries-rfcs/tree/main/features/0454-present-proof-v2)

- Current limitation:
- The managed wallets accept all invitations and credentials
- The managed wallets can accept invitations and credentials from other stored wallets and allowed DIDs. Currently, allowed DIDs are given in the configuration using the environment property `MIW_ALLOWLIST_DIDS`. This restriction can be deactivated by keeping the `MIW_ALLOWLIST_DIDS` empty
- The managed wallets can issue credentials only to other managed or registered self-managed wallets after a connection is established
- The base wallet accepts connections from stored wallets
- The issuer must be an Indy DID on the same ledger as the MIW
- Credential revocation is not supported for credentials issued using the flows
- Extensible credentials with extra properties are not supported https://www.w3.org/TR/vc-data-model/#extensibility. The only exception is the property `provenanceProof` which is a list of any type
Expand All @@ -32,7 +33,7 @@ A Credential-Offer is sent from the external wallet using the established connec
not implemented yet!

### Local Test Steps:
1. Follow the steps in `Steps for initial local deployment and wallet Creation` section in the `README.md` file
1. Follow the steps in `Steps for initial local deployment and wallet Creation` section in the `README.md` file. Make sure that either `MIW_ALLOWLIST_DIDS` is empty, or it includes the full DID of the external wallet
1. Import a new postman collection `Test-Acapy-SelfManagedWallet-Or-ExternalWallet.postman_collection.json` from `./dev-asset`
1. Run `Test-Acapy-SelfManagedWallet-Or-ExternalWallet/Get Connections` and make sure there are no connections. If there are any please delete them using `Remove Connection`
1. From `Test-Acapy-SelfManagedWallet-Or-ExternalWallet/Send Connection Request` using the public DID of the managed wallet
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ acapy_java_library_version=0.7.33
kotlin.code.style=official
kompendium_version=2.3.5
exposed_version=0.38.2
version=3.1.2
version=3.2.0
coverage_excludes=**/models/**,**/entities/**,**/Application*,**/services/IWalletService*,**/services/IAcaPyService*,**/services/AcaPyService*,**/services/IBusinessPartnerDataService*,**/services/IRevocationService*,**/services/RevocationService*

Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ fun Application.module(testing: Boolean = false) {
val utilsService = UtilsService(networkIdentifier = networkIdentifier)

val baseWalletBpn = environment.config.property("wallet.baseWalletBpn").getString()
val allowlistDidsAsString = environment.config.property("wallet.allowlistDids").getString()
val allowlistDids = if (allowlistDidsAsString.isBlank()) {
emptyList()
} else {
allowlistDidsAsString.split(",")
}
val acaPyConfig = WalletAndAcaPyConfig(
networkIdentifier = networkIdentifier,
baseWalletBpn = baseWalletBpn,
Expand All @@ -99,6 +105,7 @@ fun Application.module(testing: Boolean = false) {
adminApiKey = environment.config.property("acapy.adminApiKey").getString(),
baseWalletAdminUrl = environment.config.property("acapy.baseWalletApiAdminUrl").getString(),
baseWalletAdminApiKey = environment.config.property("acapy.baseWalletAdminApiKey").getString(),
allowlistDids = allowlistDids
)
val revocationUrl = environment.config.property("revocation.baseUrl").getString()
val revocationService = IRevocationService.createRevocationService(revocationUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ data class WalletAndAcaPyConfig(
val apiAdminUrl: String,
val adminApiKey: String,
val baseWalletAdminUrl: String,
val baseWalletAdminApiKey: String
val baseWalletAdminApiKey: String,
val allowlistDids: List<String>
)

@Serializable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/********************************************************************************
* 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
********************************************************************************/

package org.eclipse.tractusx.managedidentitywallets.models.ssi.acapy

class AriesLdFormats {
companion object {
val ARIES_LD_PROOF_VC_DETAIL_V_1_0 = "aries/ld-proof-vc-detail@v1.0"
val ARIES_LD_PROOF_VC_V_1_0 = "aries/ld-proof-vc@v1.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class CredentialRepository {
query.andWhere { VerifiableCredentials.holderDid eq it }
}
type?.let {
query.andWhere { VerifiableCredentials.type eq it }
query.andWhere { VerifiableCredentials.type like "%$it%" }
}
credentialId?.let {
query.andWhere { VerifiableCredentials.credentialId eq it }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@ class WalletRepository {
}
}

fun getWalletOrNull(identifier: String): Wallet? {
return transaction {
Wallet.find {
(Wallets.did eq identifier) or (Wallets.bpn eq identifier) or (Wallets.walletId eq identifier)
}.firstOrNull()
}
}

@Throws(ConflictException::class)
fun checkWalletAlreadyExists(identifier: String) {
if (!Wallet.find { (Wallets.did eq identifier) or (Wallets.bpn eq identifier) }.empty()) {
Expand All @@ -51,7 +59,7 @@ class WalletRepository {
}

fun isWalletExists(identifier: String): Boolean {
return transaction{
return transaction {
!Wallet.find { (Wallets.did eq identifier) or (Wallets.bpn eq identifier) }.empty()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import org.eclipse.tractusx.managedidentitywallets.models.ssi.acapy.VerifyReques
import org.eclipse.tractusx.managedidentitywallets.models.ssi.acapy.VerifyResponse
import org.eclipse.tractusx.managedidentitywallets.models.ssi.acapy.WalletAndAcaPyConfig
import org.eclipse.tractusx.managedidentitywallets.models.ssi.acapy.WalletKey
import org.eclipse.tractusx.managedidentitywallets.models.ssi.acapy.WalletList
import org.hyperledger.acy_py.generated.model.DID
import org.hyperledger.acy_py.generated.model.TransactionJobs
import org.hyperledger.acy_py.generated.model.V20CredRequestRequest
import org.hyperledger.acy_py.generated.model.V20CredStoreRequest
Expand All @@ -65,6 +67,7 @@ import org.hyperledger.aries.api.issue_credential_v2.V2CredentialExchangeFree
import org.hyperledger.aries.api.jsonld.ProofType
import org.hyperledger.aries.api.jsonld.VerifiableCredential
import org.hyperledger.aries.api.multitenancy.RemoveWalletRequest
import org.hyperledger.aries.api.wallet.ListWalletDidFilter
import java.util.*

/**
Expand All @@ -88,7 +91,8 @@ class AcaPyService(
baseWalletVerkey = acaPyConfig.baseWalletVerkey,
adminApiKey = "", // don't expose the api key outside the AcaPyService
baseWalletAdminUrl = acaPyConfig.baseWalletAdminUrl,
baseWalletAdminApiKey = "" // don't expose the api key outside the AcaPyService
baseWalletAdminApiKey = "", // don't expose the api key outside the AcaPyService
allowlistDids = acaPyConfig.allowlistDids
)
}

Expand Down Expand Up @@ -131,6 +135,13 @@ class AcaPyService(
}
}

override suspend fun isDidOfWallet(did: String, tokenOfWallet: String?): Boolean {
val acapyClient = getAcapyClient(tokenOfWallet)
val filter = ListWalletDidFilter.builder().did(did).method(DID.MethodEnum.SOV).build()
val listOfDids = acapyClient.walletDid(filter)
return !listOfDids.isEmpty && listOfDids.get().isNotEmpty()
}

override suspend fun registerDidOnLedgerUsingBaseWallet(
didRegistration: DidRegistration
): DidRegistrationResult {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

package org.eclipse.tractusx.managedidentitywallets.services

import com.google.gson.GsonBuilder
import foundation.identity.jsonld.JsonLDUtils
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.decodeFromString
Expand Down Expand Up @@ -106,7 +105,6 @@ class AcaPyWalletServiceImpl(

companion object {
private val log = LoggerFactory.getLogger(this::class.java)
private val gson = GsonBuilder().create()
}

override fun getWallet(identifier: String, withCredentials: Boolean): WalletDto {
Expand Down Expand Up @@ -216,8 +214,8 @@ class AcaPyWalletServiceImpl(
}

acaPyService.sendConnectionRequest(
didOfTheirWallet = getBaseWallet().did,
usePublicDid = false,
didOfTheirWallet = utilsService.getIdentifierOfDid(getBaseWallet().did),
usePublicDid = false, // It has no public DID yet
alias = "endorser",
token = createdSubWalletDto.token,
label = walletToCreate.bpn
Expand Down Expand Up @@ -481,7 +479,7 @@ class AcaPyWalletServiceImpl(

override suspend fun addService(identifier: String, serviceDto: DidServiceDto) {
log.debug("Add Service Endpoint for $identifier")
utilsService.checkSupportedId(serviceDto.id)
utilsService.checkSupportedServiceId(serviceDto.id)
val walletData = getWalletExtendedInformation(identifier)
val didDoc = resolveDocument(walletData.did)
if (!didDoc.services.isNullOrEmpty()) {
Expand Down Expand Up @@ -518,7 +516,7 @@ class AcaPyWalletServiceImpl(
serviceUpdateRequestDto: DidServiceUpdateRequestDto
) {
log.debug("Update Service Endpoint for $identifier")
utilsService.checkSupportedId(id)
utilsService.checkSupportedServiceId(id)
val walletData = getWalletExtendedInformation(identifier)
val didDoc = resolveDocument(walletData.did)
if (!didDoc.services.isNullOrEmpty()) {
Expand Down Expand Up @@ -1052,6 +1050,52 @@ class AcaPyWalletServiceImpl(
)
}

override fun validateConnectionRequestForManagedWallets(connection: ConnectionRecord): Boolean {
val allowlistDids = acaPyService.getWalletAndAcaPyConfig().allowlistDids
val filteredAllowlistShortDids = allowlistDids.filter {
it.startsWith(utilsService.getOldDidMethodPrefixWithNetworkIdentifier())
|| it.startsWith(utilsService.getDidMethodPrefixWithNetworkIdentifier())
}
.map { did -> utilsService.getIdentifierOfDid(did) }
val connectionDid = utilsService.getIdentifierOfDid(
did = connection.theirPublicDid ?: connection.theirDid
)
if (allowlistDids.isNotEmpty()
&& !filteredAllowlistShortDids.contains(connectionDid)
&& !walletRepository.isWalletExists(utilsService.convertToFullDidIfShort(connectionDid))
) {
log.warn(
"Connection request ${connection.connectionId} and DID $connectionDid " +
"has been rejected due to unfulfilled conditions"
)
return false
}
return true
}

override suspend fun validateConnectionRequestForBaseWallet(
connection: ConnectionRecord,
bpn: String
): WalletDto? {
val connectionDid = utilsService.getIdentifierOfDid(
did = connection.theirPublicDid ?: connection.theirDid
)
val wallet = walletRepository.getWalletOrNull(bpn)
if (wallet != null) {
val walletData = walletRepository.toWalletCompleteDataObject(wallet)
// It could be an internal AcaPy DID (e.g. when a managed wallet is created)
return if (acaPyService.isDidOfWallet(connectionDid, wallet.walletToken)) {
getWallet(walletData.did)
} else {
log.warn("The used did $connectionDid in connection ${connection.connectionId} " +
"does not belong to the given BPN $bpn")
null
}
}
log.warn("A connection ${connection.connectionId} from a not stored wallet $bpn is forbidden")
return null
}

override suspend fun setAuthorMetaData(
walletId: String,
connectionId: String
Expand Down
Loading

0 comments on commit 985184c

Please sign in to comment.