Skip to content

Commit

Permalink
Merge branch 'main' into fix-ts-client
Browse files Browse the repository at this point in the history
  • Loading branch information
patlo-iog committed Jul 1, 2024
2 parents ebe1ab3 + 30ad04b commit a732bba
Show file tree
Hide file tree
Showing 20 changed files with 325 additions and 17 deletions.
25 changes: 16 additions & 9 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -731,10 +731,18 @@ lazy val polluxCore = project
name := "pollux-core",
libraryDependencies ++= D_Pollux.coreDependencies
)
.dependsOn(shared)
.dependsOn(agentWalletAPI)
.dependsOn(polluxVcJWT)
.dependsOn(vc, resolver, agentDidcommx, eventNotification, polluxAnoncreds, polluxSDJWT)
.dependsOn(
shared,
castorCore % "compile->compile;test->test", // Test is for MockDIDService
agentWalletAPI % "compile->compile;test->test", // Test is for MockManagedDIDService
vc,
resolver,
agentDidcommx,
eventNotification,
polluxAnoncreds,
polluxVcJWT,
polluxSDJWT,
)

lazy val polluxDoobie = project
.in(file("pollux/sql-doobie"))
Expand Down Expand Up @@ -864,17 +872,16 @@ lazy val cloudAgentServer = project
.enablePlugins(BuildInfoPlugin)
.dependsOn(agentWalletAPI % "compile->compile;test->test")
.dependsOn(
sharedTest % "test->test",
agent,
polluxCore,
polluxCore % "compile->compile;test->test",
polluxDoobie,
polluxAnoncreds,
connectCore,
connectCore % "compile->compile;test->test", // Test is for MockConnectionService
connectDoobie,
castorCore,
eventNotification
eventNotification,
)
.dependsOn(sharedTest % "test->test")
.dependsOn(polluxCore % "compile->compile;test->test")

// ############################
// #### Release process #####
Expand Down
2 changes: 1 addition & 1 deletion tests/integration-tests/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ dependencies {
testImplementation("io.ktor:ktor-server-netty:2.3.0")
testImplementation("io.ktor:ktor-client-apache:2.3.0")
// RestAPI client
testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.36.1")
testImplementation("org.hyperledger.identus:cloud-agent-client-kotlin:1.37.0")
// Test helpers library
testImplementation("io.iohk.atala:atala-automation:0.4.0")
// Hoplite for configuration
Expand Down
1 change: 1 addition & 0 deletions tests/integration-tests/src/test/kotlin/config/Role.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ data class Role(
val authHeader: String = "apikey",
val webhook: Webhook?,
val agentRole: AgentRole?,
val oid4vciAuthServer: URL?,
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@ data class Keycloak(
@ConfigAlias("client_id") val clientId: String = "prism-agent",
@ConfigAlias("client_secret") val clientSecret: String = "prism-agent-demo-secret",
@ConfigAlias("keep_running") override val keepRunning: Boolean = false,
@ConfigAlias("compose_file") val keycloakComposeFile: String = "src/test/resources/containers/keycloak.yml",
@ConfigAlias("extra_envs") val extraEnvs: Map<String, String> = emptyMap(),
) : ServiceBase() {
private val logger = Logger.get<Keycloak>()
private val keycloakComposeFile = "src/test/resources/containers/keycloak.yml"
private val keycloakEnvConfig: Map<String, String> = mapOf(
private val keycloakEnvConfig: Map<String, String> = extraEnvs + mapOf(
"KEYCLOAK_HTTP_PORT" to httpPort.toString(),
)
override val logServices: List<String> = listOf("keycloak")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ import com.sksamuel.hoplite.ConfigAlias
data class Service(
@ConfigAlias("prism_node") val prismNode: VerifiableDataRegistry?,
val keycloak: Keycloak?,
@ConfigAlias("keycloak_oid4vci") val keycloakOid4vci: Keycloak,
val vault: Vault?,
)
17 changes: 14 additions & 3 deletions tests/integration-tests/src/test/kotlin/steps/Setup.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import abilities.ListenToEvents
import com.sksamuel.hoplite.ConfigException
import com.sksamuel.hoplite.ConfigLoader
import common.TestConstants
import config.AgentRole
import config.Config
import config.*
import io.cucumber.java.AfterAll
import io.cucumber.java.BeforeAll
import io.restassured.RestAssured
Expand Down Expand Up @@ -35,6 +34,7 @@ object Setup {
*/
fun initServices() {
config.services?.keycloak?.setUsers(config.roles)?.start()
config.services?.keycloakOid4vci?.setUsers(config.roles.filter { it.name == "Holder" })?.start()
config.services?.prismNode?.start()
config.services?.vault?.start()
config.agents?.forEach {
Expand Down Expand Up @@ -100,7 +100,10 @@ object Setup {
config.roles.forEach { role ->
val actor = cast.actorNamed(role.name)
try {
actor.remember("BEARER_TOKEN", config.services.keycloak.getKeycloakAuthToken(actor.name, actor.name))
actor.remember(
"BEARER_TOKEN",
config.services.keycloak.getKeycloakAuthToken(actor.name, actor.name),
)
} catch (e: NullPointerException) {
throw ConfigException("Keycloak is configured, but no token found for user ${actor.name}!")
}
Expand All @@ -126,6 +129,14 @@ object Setup {
}
actor.remember("baseUrl", role.url.toExternalForm())
}
if (config.services?.keycloakOid4vci != null) {
val role = config.roles.find { it.name == "Issuer" } ?: throw ConfigException("Issuer role does not exist")
val url = role.oid4vciAuthServer ?: throw ConfigException("Issuer's oid4vci_auth_server must be provided")
val actor = cast.actorNamed(role.name)
actor.remember("OID4VCI_AUTH_SERVER_URL", url.toExternalForm())
actor.remember("OID4VCI_AUTH_SERVER_CLIENT_ID", config.services.keycloakOid4vci.clientId)
actor.remember("OID4VCI_AUTH_SERVER_CLIENT_SECRET", config.services.keycloakOid4vci.clientSecret)
}
OnStage.setTheStage(cast)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package steps.oid4vci

import common.CredentialSchema
import interactions.*
import io.cucumber.java.en.*
import io.iohk.atala.automation.extensions.get
import io.iohk.atala.automation.serenity.ensure.Ensure
import net.serenitybdd.rest.SerenityRest
import net.serenitybdd.screenplay.Actor
import org.apache.http.HttpStatus
import org.hyperledger.identus.client.models.*

class ManageCredentialConfigSteps {
@Given("{actor} has {string} credential configuration created from {}")
fun issuerHasExistingCredentialConfig(issuer: Actor, configurationId: String, schema: CredentialSchema) {
ManageIssuerSteps().issuerHasExistingCredentialIssuer(issuer)
issuerCreateCredentialConfiguration(issuer, schema, configurationId)
}

@When("{actor} uses {} to create a credential configuration {string}")
fun issuerCreateCredentialConfiguration(issuer: Actor, schema: CredentialSchema, configurationId: String) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
val schemaGuid = issuer.recall<String>(schema.name)
val baseUrl = issuer.recall<String>("baseUrl")
issuer.attemptsTo(
Post.to("/oid4vci/issuers/${credentialIssuer.id}/credential-configurations")
.with {
it.body(
CreateCredentialConfigurationRequest(
configurationId = configurationId,
format = CredentialFormat.JWT_VC_JSON,
schemaId = "$baseUrl/schema-registry/schemas/$schemaGuid/schema",
),
)
},
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_CREATED),
)
}

@When("{actor} deletes {string} credential configuration")
fun issuerDeletesCredentialConfiguration(issuer: Actor, configurationId: String) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Delete("/oid4vci/issuers/${credentialIssuer.id}/credential-configurations/$configurationId"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
}

@Then("{actor} sees the {string} configuration on IssuerMetadata endpoint")
fun issuerSeesCredentialConfiguration(issuer: Actor, configurationId: String) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers/${credentialIssuer.id}/.well-known/openid-credential-issuer"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
val metadata = SerenityRest.lastResponse().get<IssuerMetadata>()
val credConfig = metadata.credentialConfigurationsSupported[configurationId]!!
issuer.attemptsTo(
Ensure.that(credConfig.scope).isEqualTo(configurationId),
)
}

@Then("{actor} cannot see the {string} configuration on IssuerMetadata endpoint")
fun issuerCannotSeeCredentialConfiguration(issuer: Actor, configurationId: String) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers/${credentialIssuer.id}/.well-known/openid-credential-issuer"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
val metadata = SerenityRest.lastResponse().get<IssuerMetadata>()
issuer.attemptsTo(
Ensure.that(metadata.credentialConfigurationsSupported.keys).doesNotContain(configurationId),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
package steps.oid4vci

import interactions.*
import io.cucumber.java.en.*
import io.iohk.atala.automation.extensions.get
import io.iohk.atala.automation.serenity.ensure.Ensure
import net.serenitybdd.rest.SerenityRest
import net.serenitybdd.screenplay.Actor
import org.apache.http.HttpStatus
import org.apache.http.HttpStatus.SC_CREATED
import org.apache.http.HttpStatus.SC_OK
import org.hyperledger.identus.client.models.*

class ManageIssuerSteps {
private val UPDATE_AUTH_SERVER_URL = "http://example.com"
private val UPDATE_AUTH_SERVER_CLIENT_ID = "foo"
private val UPDATE_AUTH_SERVER_CLIENT_SECRET = "bar"

@Given("{actor} has an existing oid4vci issuer")
fun issuerHasExistingCredentialIssuer(issuer: Actor) {
issuerCreateCredentialIssuer(issuer)
}

@When("{actor} creates an oid4vci issuer")
fun issuerCreateCredentialIssuer(issuer: Actor) {
issuer.attemptsTo(
Post.to("/oid4vci/issuers")
.with {
it.body(
CreateCredentialIssuerRequest(
authorizationServer = AuthorizationServer(
url = issuer.recall("OID4VCI_AUTH_SERVER_URL"),
clientId = issuer.recall("OID4VCI_AUTH_SERVER_CLIENT_ID"),
clientSecret = issuer.recall("OID4VCI_AUTH_SERVER_CLIENT_SECRET"),
),
),
)
},
Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_CREATED),
)
val credentialIssuer = SerenityRest.lastResponse().get<CredentialIssuer>()
issuer.remember("oid4vciCredentialIssuer", credentialIssuer)
}

@Then("{actor} sees the oid4vci issuer exists on the agent")
fun issuerSeesCredentialIssuerExists(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK),
)
val matchedIssuers = SerenityRest.lastResponse().get<CredentialIssuerPage>().contents!!
.filter { it.id == credentialIssuer.id }
issuer.attemptsTo(
Ensure.that(matchedIssuers).hasSize(1),
)
}

@Then("{actor} sees the oid4vci issuer on IssuerMetadata endpoint")
fun issuerSeesCredentialIssuerExistsOnMetadataEndpoint(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers/${credentialIssuer.id}/.well-known/openid-credential-issuer"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(SC_OK),
)
}

@When("{actor} updates the oid4vci issuer")
fun issuerUpdateCredentialIssuer(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Patch.to("/oid4vci/issuers/${credentialIssuer.id}")
.with {
it.body(
PatchCredentialIssuerRequest(
authorizationServer = PatchAuthorizationServer(
url = UPDATE_AUTH_SERVER_URL,
clientId = UPDATE_AUTH_SERVER_CLIENT_ID,
clientSecret = UPDATE_AUTH_SERVER_CLIENT_SECRET,
),
),
)
},
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
}

@When("{actor} deletes the oid4vci issuer")
fun issuerDeleteCredentialIssuer(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Delete("/oid4vci/issuers/${credentialIssuer.id}"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
}

@Then("{actor} sees the oid4vci issuer updated with new values")
fun issuerSeesUpdatedCredentialIssuer(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
val updatedIssuer = SerenityRest.lastResponse().get<CredentialIssuerPage>().contents!!
.find { it.id == credentialIssuer.id }!!
issuer.attemptsTo(
Ensure.that(updatedIssuer.authorizationServerUrl).isEqualTo(UPDATE_AUTH_SERVER_URL),
)
}

@Then("{actor} sees the oid4vci IssuerMetadata endpoint updated with new values")
fun issuerSeesUpdatedCredentialIssuerMetadata(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers/${credentialIssuer.id}/.well-known/openid-credential-issuer"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
val metadata = SerenityRest.lastResponse().get<IssuerMetadata>()
issuer.attemptsTo(
Ensure.that(metadata.authorizationServers?.first()!!).isEqualTo(UPDATE_AUTH_SERVER_URL),
)
}

@Then("{actor} cannot see the oid4vci issuer on the agent")
fun issuerCannotSeeCredentialIssuer(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_OK),
)
val matchedIssuers = SerenityRest.lastResponse().get<CredentialIssuerPage>().contents!!
.filter { it.id == credentialIssuer.id }
issuer.attemptsTo(
Ensure.that(matchedIssuers).isEmpty(),
)
}

@Then("{actor} cannot see the oid4vci IssuerMetadata endpoint")
fun issuerCannotSeeIssuerMetadata(issuer: Actor) {
val credentialIssuer = issuer.recall<CredentialIssuer>("oid4vciCredentialIssuer")
issuer.attemptsTo(
Get("/oid4vci/issuers/${credentialIssuer.id}/.well-known/openid-credential-issuer"),
Ensure.thatTheLastResponse().statusCode().isEqualTo(HttpStatus.SC_NOT_FOUND),
)
}
}
11 changes: 10 additions & 1 deletion tests/integration-tests/src/test/resources/configs/basic.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ services = {
http_port = 50053
version = "${PRISM_NODE_VERSION}"
}
keycloak_oid4vci = {
http_port = 9981
compose_file = "src/test/resources/containers/keycloak-oid4vci.yml"
realm = "oid4vci-holder"
extra_envs = {
IDENTUS_URL = "${ISSUER_AGENT_URL:-http://localhost:8080}"
}
}
}

# Specify agents that are required to be created before running tests
Expand All @@ -23,7 +31,7 @@ roles = [
url = "${ADMIN_AGENT_URL:-http://localhost:8080}"
apikey = "${ADMIN_API_KEY:-admin}"
auth_header = "x-admin-api-key"
}
},
{
name = "Issuer"
url = "${ISSUER_AGENT_URL:-http://localhost:8080}"
Expand All @@ -32,6 +40,7 @@ roles = [
url = "${ISSUER_WEBHOOK_URL:-http://host.docker.internal:9955}"
init_required = true
}
oid4vci_auth_server = "http://localhost:9981"
},
{
name = "Holder"
Expand Down
Loading

0 comments on commit a732bba

Please sign in to comment.