Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,25 @@ class LoTEFilterService {
* Extracts certificates matching the requested service type identifier where
* the certificate's subject organization aligns with the trusted provider's registered names
*/
fun extractTrustedCertificates(lote: ListOfTrustedEntities, criteria: LoTEFilterCriteria): List<TrustedCertificate> {
fun extractTrustedCertificates(sourceUrl: String, lote: ListOfTrustedEntities, criteria: LoTEFilterCriteria): List<TrustedCertificate> {
val entities = lote.trustedEntitiesList ?: return emptyList()

val loteType = lote.listAndSchemeInformation?.loteType?.toString()
return entities.flatMap { entity ->
val providerName = entity.trustedEntityInformation.teName

entity.trustedEntityServices
.filter { it.serviceInformation.serviceTypeIdentifier?.string == criteria.expectedServiceType }
.filter { service ->
val serviceTypeId = service.serviceInformation.serviceTypeIdentifier?.string

if (serviceTypeId != null) {
// Field is present. Check if it matches type
serviceTypeId.contains(criteria.expectedServiceType.type, ignoreCase = true)
} else {
// Field is absent. The services inherit the list's default type
loteType?.contains(criteria.expectedServiceType.type, ignoreCase = true) == true ||
sourceUrl.contains(criteria.expectedServiceType.type, ignoreCase = true)
}
}
.flatMap { service -> service.serviceInformation.serviceDigitalIdentity.x509Certificates }
.filter { cert -> cert?.hasMatchingOrganization(providerName) == true }
.map { cert -> TrustedCertificate(cert, providerName, criteria.expectedServiceType) }
Expand Down Expand Up @@ -58,9 +69,36 @@ class LoTEFilterService {
data class TrustedCertificate(
val certificate: @Serializable(with = EtsiX509CertificateSerializer::class) X509Certificate?,
val providerName: TEName,
val serviceType: String
val serviceType: LoTEServiceType
)

data class LoTEFilterCriteria(
val expectedServiceType: String,
)
val expectedServiceType: LoTEServiceType,
)

enum class LoTEServiceType(
val type: String,
val fileName: String,
private val identifiers: List<String> = emptyList()
) {
PID("pid", "pid-providers.json", listOf("urn:eudi:pid:", "eu.europa.ec.eudi.pid.")),
MDL("mdl", "mdl-providers.json", listOf("org.iso.18013.5.1.mDL")),
WRPAC("wrpac", "wrpac-providers.json"),
WALLET("wallet", "wallet-providers.json"),
EAA("eaa", "pub-eaa-providers.json");

fun defaultUrl(baseUrl: String = DEFAULT_BASE_URL) = "$baseUrl/$fileName"

companion object {
const val DEFAULT_BASE_URL = "https://acceptance.trust.tech.ec.europa.eu/lists/eudiw"
val defaultUrls = entries.map { it.defaultUrl() }

fun fromSchemeIdentifier(schemeIdentifier: String?): LoTEServiceType {
if (schemeIdentifier.isNullOrBlank()) return EAA

return entries.firstOrNull { entry ->
entry.identifiers.any { schemeIdentifier.contains(it, ignoreCase = true) }
} ?: EAA
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7029,23 +7029,40 @@ val LoTEFilterTest by matrixSuite {

data class TestData(
val json: String,
val expectedServiceType: String
val fetchUrl: String,
val schemeIdentifier: String? = null,
val fixedType: LoTEServiceType? = null
)

testSuite("filter lote by type identifier") {
mapOf(
"pidProviders" to TestData(pidProvidersFixed, "http://uri.etsi.org/19602/SvcType/PID/Issuance"),
"walletProviders" to TestData(walletProvidersFixed, "http://uri.etsi.org/19602/SvcType/WalletSolution/Issuance"),
"wrpacProviders" to TestData(wrpacProvidersFixed, "http://uri.etsi.org/19602/SvcType/WRPAC/Issuance"),
"mdlProviders" to TestData(mdlProvidersFixed, "http://uri.etsi.org/19602/SvcType/mDL/Issuance"),
).asData() test{ (_, data) ->
"pidProviders" to TestData(
json = pidProvidersFixed,
fetchUrl = LoTEServiceType.PID.defaultUrl(),
schemeIdentifier = "urn:eudi:pid:de:1"
),
"walletProviders" to TestData(
json = walletProvidersFixed,
fetchUrl = LoTEServiceType.WALLET.defaultUrl(),
fixedType = LoTEServiceType.WALLET
),
"wrpacProviders" to TestData(
json = wrpacProvidersFixed,
fetchUrl = LoTEServiceType.WRPAC.defaultUrl(),
fixedType = LoTEServiceType.WRPAC
),
"mdlProviders" to TestData(
json = mdlProvidersFixed,
fetchUrl = LoTEServiceType.MDL.defaultUrl(),
schemeIdentifier = "org.iso.18013.5.1.mDL"
),
).asData() test { (_, data) ->
val lote = Json.decodeFromString<ListOfTrustedEntities>(data.json)
val expectedType = data.fixedType ?: LoTEServiceType.fromSchemeIdentifier(data.schemeIdentifier)
val criteria = LoTEFilterCriteria(expectedServiceType = expectedType)
val trustedCerts = LoTEFilterService().extractTrustedCertificates(data.fetchUrl, lote, criteria)

val criteria = LoTEFilterCriteria(expectedServiceType = data.expectedServiceType)

val trustedCerts = LoTEFilterService().extractTrustedCertificates(lote, criteria)

trustedCerts.size shouldNotBe(0)
trustedCerts.size shouldNotBe 0
}
}
}