Skip to content

Commit

Permalink
Merge pull request #272 from walt-id/verificatio-policy-result-result…
Browse files Browse the repository at this point in the history
…-pattern

refactor: verification-policy-result implement operation-result-pattern
  • Loading branch information
mikeplotean authored Apr 10, 2023
2 parents 0c7d120 + 3b3ce9c commit d2d35ff
Show file tree
Hide file tree
Showing 13 changed files with 72 additions and 66 deletions.
33 changes: 17 additions & 16 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,20 @@ jobs:
MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
with:
arguments: build publish --no-daemon
- name: Docker Build and Push SNAPSHOT
uses: philpotisk/github-action-docker-build-push@master
env:
DOCKER_USERNAME: ${{secrets.DOCKER_USERNAME}}
DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
DOCKER_FILE: Dockerfile
CONTAINER_TAG: waltid/ssikit:latest
- name: Prepare CD K8S
run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" k8s/deployment-dev.yaml > k8s/deployment-dev_mod.yaml
- name: Continuous deployment K8S
uses: actions-hub/kubectl@master
env:
KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
with:
args: apply -n dev -f k8s/deployment-dev_mod.yaml
arguments: build --no-daemon
# arguments: build publish --no-daemon
# - name: Docker Build and Push SNAPSHOT
# uses: philpotisk/github-action-docker-build-push@master
# env:
# DOCKER_USERNAME: ${{secrets.DOCKER_USERNAME}}
# DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
# DOCKER_FILE: Dockerfile
# CONTAINER_TAG: waltid/ssikit:latest
# - name: Prepare CD K8S
# run: sed "s/_DEFAULT_DEPLOYMENT_/$GITHUB_SHA/g" k8s/deployment-dev.yaml > k8s/deployment-dev_mod.yaml
# - name: Continuous deployment K8S
# uses: actions-hub/kubectl@master
# env:
# KUBE_CONFIG: ${{ secrets.KUBE_CONFIG }}
# with:
# args: apply -n dev -f k8s/deployment-dev_mod.yaml
6 changes: 3 additions & 3 deletions src/main/kotlin/id/walt/auditor/Auditor.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,18 @@ class WaltIdAuditor : Auditor() {
log.debug { "Verifying vc with ${policy.id} ..." }

val vcResult = policy.verify(vc)
val success = AtomicBoolean(vcResult.result)
val success = AtomicBoolean(vcResult.isSuccess)
val allErrors = vcResult.errors.toMutableList()
if (allErrors.isEmpty() && vc is VerifiablePresentation) {
vc.verifiableCredential?.forEach { cred ->
log.debug { "Verifying ${cred.type.last()} in VP with ${policy.id}..." }
val vpResult = policy.verify(cred)
allErrors.addAll(vpResult.errors)
success.compareAndSet(true, vpResult.result)
success.compareAndSet(true, vpResult.isSuccess)
}
}
allErrors.forEach { log.error { "${policy.id}: $it" } }
VerificationPolicyResult(success.get(), allErrors)
success.get().takeIf { it }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure(*allErrors.toTypedArray())
}

return VerificationResult(allAccepted(policyResults), policyResults)
Expand Down
19 changes: 12 additions & 7 deletions src/main/kotlin/id/walt/auditor/VerificationPolicy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,26 @@ data class VerificationPolicyMetadata(
val isMutable: Boolean
)

data class VerificationPolicyResult(val result: Boolean, @JsonIgnore val errors: List<Throwable> = listOf()) {
class VerificationPolicyResult private constructor(
private val result: Boolean,
@JsonIgnore
private val errorList: List<Throwable> = emptyList()
) {

companion object {
fun success() = VerificationPolicyResult(true)
fun failure(error: Throwable): VerificationPolicyResult {
log.debug { "VerificationPolicy failed: ${error.stackTraceToString()}" }
return VerificationPolicyResult(false, listOf(error))
fun failure(vararg error: Throwable): VerificationPolicyResult {
log.debug { "VerificationPolicy failed: ${error.joinToString { it.localizedMessage }}" }
return VerificationPolicyResult(false, error.asList())
}

fun failure(errors: List<Throwable> = listOf()) = VerificationPolicyResult(false, errors.toList())
}

val isSuccess = result
val isFailure = !result
@JsonIgnore
val errors = errorList

fun getErrorString() = errors.mapIndexed { index, throwable ->
private fun getErrorString() = errorList.mapIndexed { index, throwable ->
"#${index + 1}: ${throwable::class.simpleName ?: "Error"} - ${throwable.message}"
}.joinToString()

Expand Down
8 changes: 2 additions & 6 deletions src/main/kotlin/id/walt/auditor/dynamic/OPAPolicyEngine.kt
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
package id.walt.auditor.dynamic

import com.beust.klaxon.JsonObject
import com.beust.klaxon.Klaxon
import com.beust.klaxon.Parser
import id.walt.auditor.VerificationPolicyResult
import id.walt.common.resolveContentToFile
import id.walt.credentials.w3c.JsonConverter
import kotlinx.serialization.json.buildJsonObject
import mu.KotlinLogging
import java.io.File

object OPAPolicyEngine : PolicyEngine {
private val log = KotlinLogging.logger {}
Expand Down Expand Up @@ -37,7 +32,8 @@ object OPAPolicyEngine : PolicyEngine {
val output = p.inputStream.reader().use { it.readText() }
p.waitFor()
log.debug("rego eval output: {}", output)
return VerificationPolicyResult(Klaxon().parseArray<Boolean>(output)?.all { it } ?: false)
return (Klaxon().parseArray<Boolean>(output)?.all { it } ?: false).takeIf { it }
?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
} finally {
if (regoFile.exists() && regoFile.name.startsWith(TEMP_PREFIX)) {
regoFile.delete()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,30 @@ private val dateFormatter =
class IssuedDateBeforePolicy : SimpleVerificationPolicy() {
override val description: String = "Verify by issuance date"
override fun doVerify(vc: VerifiableCredential): VerificationPolicyResult {
return VerificationPolicyResult(when (vc) {
return when (vc) {
is VerifiablePresentation -> true
else -> parseDate(vc.issued).let { it != null && it.before(Date()) }
})
}.takeIf { it }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
}
}

class ValidFromBeforePolicy : SimpleVerificationPolicy() {
override val description: String = "Verify by valid from"
override fun doVerify(vc: VerifiableCredential): VerificationPolicyResult {
return VerificationPolicyResult(when (vc) {
return when (vc) {
is VerifiablePresentation -> true
else -> parseDate(vc.validFrom).let { it != null && it.before(Date()) }
})
}.takeIf { it }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
}
}

class ExpirationDateAfterPolicy : SimpleVerificationPolicy() {
override val description: String = "Verify by expiration date"
override fun doVerify(vc: VerifiableCredential): VerificationPolicyResult {
return VerificationPolicyResult(when (vc) {
return when (vc) {
is VerifiablePresentation -> true
else -> parseDate(vc.expirationDate).let { it == null || it.after(Date()) }
})
}.takeIf { it }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
}
}

Expand Down Expand Up @@ -92,7 +92,8 @@ class ChallengePolicy(challengeArg: ChallengePolicyArg) :

override val description: String = "Verify challenge"
override fun doVerify(vc: VerifiableCredential): VerificationPolicyResult {
return VerificationPolicyResult(vc.challenge?.let { argument.challenges.contains(it) } ?: false)
return (vc.challenge?.let { argument.challenges.contains(it) } ?: false).takeIf { it }
?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
}

override val applyToVC: Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class EbsiTrustedIssuerDidPolicy : SimpleVerificationPolicy() {
override val description: String = "Verify by trusted issuer did"
override fun doVerify(vc: VerifiableCredential): VerificationPolicyResult {
return try {
VerificationPolicyResult(DidService.loadOrResolveAnyDid(vc.issuerId!!) != null)
DidService.loadOrResolveAnyDid(vc.issuerId!!)?.let { VerificationPolicyResult.success() }
?: VerificationPolicyResult.failure()
} catch (e: ClientRequestException) {
VerificationPolicyResult.failure(
IllegalArgumentException(
Expand Down Expand Up @@ -147,15 +148,15 @@ class EbsiTrustedIssuerRegistryPolicy(registryArg: EbsiTrustedIssuerRegistryPoli
class EbsiTrustedSubjectDidPolicy : SimpleVerificationPolicy() {
override val description: String = "Verify by trusted subject did"
override fun doVerify(vc: VerifiableCredential): VerificationPolicyResult {
return VerificationPolicyResult(vc.subjectId?.let {
return (vc.subjectId?.let {
if (it.isEmpty()) true
else try {
DidService.loadOrResolveAnyDid(it) != null
} catch (e: ClientRequestException) {
if (!e.message.contains("did must be a valid DID") && !e.message.contains("Identifier Not Found")) throw e
false
}
} ?: false)
} ?: false).takeIf { it }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
}
}

Expand Down
10 changes: 4 additions & 6 deletions src/main/kotlin/id/walt/auditor/policies/SignaturePolicy.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ class SignaturePolicy : SimpleVerificationPolicy() {

override fun doVerify(vc: VerifiableCredential) = runCatching {
log.debug { "is jwt: ${vc.jwt != null}" }
VerificationPolicyResult(
vc.verifyByFormatType(
{ jwtCredentialService.verify(it) },
{ jsonLdCredentialService.verify(it) }
).verified
)
vc.verifyByFormatType(
{ jwtCredentialService.verify(it) },
{ jsonLdCredentialService.verify(it) }
).verified.takeIf { it }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
}.getOrElse {
VerificationPolicyResult.failure(it)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ class PresentationDefinitionPolicy(presentationDefinition: PresentationDefinitio
ParameterizedVerificationPolicy<PresentationDefinition>(presentationDefinition) {
override val description: String = "Verify that verifiable presentation complies with presentation definition"
override fun doVerify(vc: VerifiableCredential): VerificationPolicyResult {
return VerificationPolicyResult(if (vc is VerifiablePresentation) {
return (if (vc is VerifiablePresentation) {
argument.input_descriptors.all { desc ->
vc.verifiableCredential?.any { cred -> OIDCUtils.matchesInputDescriptor(cred, desc) } ?: false
}
} else false)
} else false).takeIf { it }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure()
}

override var applyToVC: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class NetworkntSchemaValidator(versionFlag: SpecVersion.VersionFlag, schema: Str
log.debug { "Could not validate vc against schema. The validation errors are:" }
errors.forEach { log.debug { it } }
}
return VerificationPolicyResult(errors.isEmpty(), errors.map { SchemaViolationException(it.toString()) })
return errors.takeIf { it.isEmpty() }?.let {
VerificationPolicyResult.success()
} ?: VerificationPolicyResult.failure(*errors.map { SchemaViolationException(it.toString()) }.toTypedArray())
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ class PWallSchemaValidator(schema: String) : SchemaValidator {
log.debug { "Could not validate vc against schema. The validation errors are:" }
errors.forEach { log.debug { it } }
}
return VerificationPolicyResult(errors.isEmpty(), errors.map {
SchemaViolationException(it.error)
})
return errors.takeIf { it.isEmpty() }?.let { VerificationPolicyResult.success() } ?: VerificationPolicyResult.failure(
*errors.map {
SchemaViolationException(it.error)
}.toTypedArray()
)
}
}
8 changes: 4 additions & 4 deletions src/test/kotlin/id/walt/auditor/AuditorTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ class AuditorCommandTest : StringSpec() {

res.policyResults.keys shouldContainAll policyList.map { it.id }

res.policyResults.values.forEach { it.result shouldBe true }
res.policyResults.values.forEach { it.isSuccess shouldBe true }
}

"2. verify vc" {
Expand All @@ -107,7 +107,7 @@ class AuditorCommandTest : StringSpec() {

res.policyResults.keys shouldContainAll listOf(SignaturePolicy()).map { it.id }

res.policyResults.values.forEach { it.result shouldBe true }
res.policyResults.values.forEach { it.isSuccess shouldBe true }
}

"3. verify vc jwt" {
Expand All @@ -121,7 +121,7 @@ class AuditorCommandTest : StringSpec() {

res.policyResults.keys shouldContainAll listOf(SignaturePolicy()).map { it.id }

res.policyResults.values.forEach { it.result shouldBe true }
res.policyResults.values.forEach { it.isSuccess shouldBe true }
}

"4. verify vp jwt" {
Expand All @@ -136,7 +136,7 @@ class AuditorCommandTest : StringSpec() {

res.policyResults.keys shouldContainAll listOf(SignaturePolicy()).map { it.id }

res.policyResults.values.forEach { it.result shouldBe true }
res.policyResults.values.forEach { it.isSuccess shouldBe true }
}

// CLI call for testing VerifiableMandatePolicy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,10 +234,10 @@ class WaltIdJsonLdCredentialServiceTest : AnnotationSpec() {
)
val notParsableVc = ""

credentialService.validateSchemaTsr(noSchemaVc).result shouldBe false
credentialService.validateSchemaTsr(validVc).result shouldBe true
credentialService.validateSchemaTsr(invalidDataVc).result shouldBe false
credentialService.validateSchemaTsr(notParsableVc).result shouldBe false
credentialService.validateSchemaTsr(noSchemaVc).isSuccess shouldBe false
credentialService.validateSchemaTsr(validVc).isSuccess shouldBe true
credentialService.validateSchemaTsr(invalidDataVc).isSuccess shouldBe false
credentialService.validateSchemaTsr(notParsableVc).isSuccess shouldBe false
}

/*@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,10 @@ class WaltIdJwtCredentialServiceTest : AnnotationSpec() {
)
val notParsableVc = ""

credentialService.validateSchemaTsr(noSchemaVc).result shouldBe true
credentialService.validateSchemaTsr(validVc).result shouldBe true
credentialService.validateSchemaTsr(invalidDataVc).result shouldBe false
credentialService.validateSchemaTsr(notParsableVc).result shouldBe false
credentialService.validateSchemaTsr(noSchemaVc).isSuccess shouldBe true
credentialService.validateSchemaTsr(validVc).isSuccess shouldBe true
credentialService.validateSchemaTsr(invalidDataVc).isSuccess shouldBe false
credentialService.validateSchemaTsr(notParsableVc).isSuccess shouldBe false
}

@Test
Expand Down

0 comments on commit d2d35ff

Please sign in to comment.