Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(prism-agent): add verification policy OpenAPI description #835

Merged
merged 1 commit into from
Jan 10, 2024
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
@@ -1,6 +1,7 @@
package io.iohk.atala.agent.server.http

import io.iohk.atala.connect.controller.ConnectionEndpoints
import io.iohk.atala.pollux.credentialschema.VerificationPolicyEndpoints
import sttp.apispec.openapi.*
import sttp.apispec.{SecurityScheme, Tag}
import sttp.model.headers.AuthenticationScheme
Expand Down Expand Up @@ -50,9 +51,21 @@ object DocModels {
Info(
title = "Open Enterprise Agent API Reference",
version = "1.0", // Will be replaced dynamically by 'Tapir2StaticOAS'
summary = Some("Info - Summary"),
description = Some("Info - Description"),
termsOfService = Some("Info - Terms Of Service"),
summary = Some("""
|This API provides interfaces for managing decentralized identities and secure communications in a self-sovereign identity framework.
|It enables seamless interaction with various decentralized identity protocols and services using the [Open Enterprise Agent](https://github.com/hyperledger-labs/open-enterprise-agent)
|""".stripMargin),
description = Some("""
|The Open Enterprise Agent API facilitates the integration and management of self-sovereign identity capabilities within applications.
|It supports DID (Decentralized Identifiers) management, verifiable credential exchange, and secure messaging based on DIDComm standards.
|The API is designed to be interoperable with various blockchain and DLT (Distributed Ledger Technology) platforms, ensuring wide compatibility and flexibility.
|Key features include connection management, credential issuance and verification, and secure, privacy-preserving communication between entities.
|Additional information and the full list of capabilities can be found in the [Open Enterprise Agent documentation](https://docs.atalaprism.io/docs/category/prism-cloud-agent)
|""".stripMargin),
termsOfService = Some("""
|Users of the Open Enterprise Agent API must adhere to the terms and conditions outlined in [Link to Terms of Service](/).
|This includes compliance with relevant data protection regulations, responsible usage policies, and adherence to the principles of decentralized identity management.
|""".stripMargin),
contact = Some(
Contact(
name = Some("Contact - Name"),
Expand All @@ -63,8 +76,8 @@ object DocModels {
),
license = Some(
License(
name = "License - Name",
url = Some("License - URL"),
name = "Apache 2.0",
url = Some("https://www.apache.org/licenses/LICENSE-2.0"),
extensions = ListMap.empty
)
),
Expand Down Expand Up @@ -101,23 +114,8 @@ object DocModels {
)
.tags(
List(
Tag(
ConnectionEndpoints.TAG,
Some(
s"""
|The '${ConnectionEndpoints.TAG}' endpoints facilitate the initiation of connection flows between the current agent and peer agents, regardless of whether they reside in cloud or edge environments.
|<br>
|This implementation adheres to the DIDComm Messaging v2.0 - [Out of Band Messages](https://identity.foundation/didcomm-messaging/spec/v2.0/#out-of-band-messages) specification [section 9.5.4](https://identity.foundation/didcomm-messaging/spec/v2.0/#invitation) - to generate invitations.
|The <b>from</b> field of the out-of-band invitation message contains a freshly generated Peer DID that complies with the [did:peer:2](https://identity.foundation/peer-did-method-spec/#generating-a-didpeer2) specification.
|This Peer DID includes the 'uri' location of the DIDComm messaging service, essential for the invitee's subsequent execution of the connection flow.
|<br>
|Upon accepting an invitation, the invitee sends a connection request to the inviter's DIDComm messaging service endpoint.
|The connection request's 'type' attribute must be specified as "https://atalaprism.io/mercury/connections/1.0/request".
|The inviter agent responds with a connection response message, indicated by a 'type' attribute of "https://atalaprism.io/mercury/connections/1.0/response".
|Both request and response types are proprietary to the Open Enterprise Agent ecosystem.
|""".stripMargin
)
)
ConnectionEndpoints.tag,
VerificationPolicyEndpoints.tag
)
)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package io.iohk.atala.agent.server.http

import sttp.apispec.SecurityScheme
import sttp.apispec.openapi.{OpenAPI, Server}
import sttp.model.headers.AuthenticationScheme
import io.iohk.atala.agent.server.buildinfo.BuildInfo
import sttp.apispec.openapi.OpenAPI
import sttp.tapir.redoc.RedocUIOptions
import sttp.tapir.redoc.bundle.RedocInterpreter
import sttp.tapir.server.ServerEndpoint
import sttp.tapir.swagger.SwaggerUIOptions
import sttp.tapir.swagger.bundle.SwaggerInterpreter

import scala.collection.immutable.ListMap

object ZHttpEndpoints {

private val swaggerUIOptions = SwaggerUIOptions.default
Expand All @@ -21,11 +18,11 @@ object ZHttpEndpoints {

def swaggerEndpoints[F[_]](apiEndpoints: List[ServerEndpoint[Any, F]]): List[ServerEndpoint[Any, F]] =
SwaggerInterpreter(swaggerUIOptions = swaggerUIOptions, customiseDocsModel = DocModels.customiseDocsModel)
.fromServerEndpoints[F](apiEndpoints, "Prism Agent", "1.0.0")
.fromServerEndpoints[F](apiEndpoints, "Prism Agent", BuildInfo.version)

def redocEndpoints[F[_]](apiEndpoints: List[ServerEndpoint[Any, F]]): List[ServerEndpoint[Any, F]] =
RedocInterpreter(redocUIOptions = redocUIOptions, customiseDocsModel = DocModels.customiseDocsModel)
.fromServerEndpoints[F](apiEndpoints, "Prism Agent", "1.0.0")
.fromServerEndpoints[F](apiEndpoints, "Prism Agent", BuildInfo.version)

def withDocumentations[F[_]](apiEndpoints: List[ServerEndpoint[Any, F]]): List[ServerEndpoint[Any, F]] = {
apiEndpoints ++ swaggerEndpoints[F](apiEndpoints) ++ redocEndpoints[F](apiEndpoints)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package io.iohk.atala.api.http.model
import sttp.tapir.EndpointIO.annotations.{description, query}
import sttp.tapir.Schema.annotations.validateEach
import sttp.tapir.{Schema, Validator}

case class PaginationInput(
@query
@validateEach(Validator.positiveOrZero[Int])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import io.iohk.atala.iam.authentication.apikey.ApiKeyCredentials
import io.iohk.atala.iam.authentication.apikey.ApiKeyEndpointSecurityLogic.apiKeyHeader
import io.iohk.atala.iam.authentication.oidc.JwtCredentials
import io.iohk.atala.iam.authentication.oidc.JwtSecurityLogic.jwtAuthHeader
import sttp.apispec.Tag
import sttp.model.StatusCode
import sttp.tapir.*
import sttp.tapir.json.zio.jsonBody
Expand All @@ -21,7 +22,22 @@ import java.util.UUID

object ConnectionEndpoints {

val TAG: String = "Connections Management"
private val tagName = "Connections Management"
private val tagDescription =
s"""
|The '$tagName' endpoints facilitate the initiation of connection flows between the current agent and peer agents, regardless of whether they reside in cloud or edge environments.
|<br>
|This implementation adheres to the DIDComm Messaging v2.0 - [Out of Band Messages](https://identity.foundation/didcomm-messaging/spec/v2.0/#out-of-band-messages) specification [section 9.5.4](https://identity.foundation/didcomm-messaging/spec/v2.0/#invitation) - to generate invitations.
|The <b>from</b> field of the out-of-band invitation message contains a freshly generated Peer DID that complies with the [did:peer:2](https://identity.foundation/peer-did-method-spec/#generating-a-didpeer2) specification.
|This Peer DID includes the 'uri' location of the DIDComm messaging service, essential for the invitee's subsequent execution of the connection flow.
|<br>
|Upon accepting an invitation, the invitee sends a connection request to the inviter's DIDComm messaging service endpoint.
|The connection request's 'type' attribute must be specified as "https://atalaprism.io/mercury/connections/1.0/request".
|The inviter agent responds with a connection response message, indicated by a 'type' attribute of "https://atalaprism.io/mercury/connections/1.0/response".
|Both request and response types are proprietary to the Open Enterprise Agent ecosystem.
|""".stripMargin

val tag = Tag(tagName, Some(tagDescription))

private val paginationInput: EndpointInput[PaginationInput] = EndpointInput.derived[PaginationInput]

Expand Down Expand Up @@ -61,7 +77,7 @@ object ConnectionEndpoints {
|In the agent database, the created connection record has an initial state set to `InvitationGenerated`.
|The request body may contain a `label` that can be used as a human readable alias for the connection, for example `{'label': "Connection with Bob"}`
|""".stripMargin)
.tag(TAG)
.tag(tagName)

val getConnection
: Endpoint[(ApiKeyCredentials, JwtCredentials), (RequestContext, UUID), ErrorResponse, Connection, Any] =
Expand All @@ -85,7 +101,7 @@ object ConnectionEndpoints {
|The API returns a comprehensive collection of connection flow records within the system, regardless of their state.
|The returned connection item includes essential metadata such as connection ID, thread ID, state, role, participant information, and other relevant details.
|""".stripMargin)
.tag(TAG)
.tag(tagName)

val getConnections: Endpoint[
(ApiKeyCredentials, JwtCredentials),
Expand Down Expand Up @@ -117,7 +133,7 @@ object ConnectionEndpoints {
|Each connection item includes essential metadata such as connection ID, thread ID, state, role, participant information, and other relevant details.
|Pagination support is available, allowing for efficient handling of large datasets.
|""".stripMargin)
.tag(TAG)
.tag(tagName)

val acceptConnectionInvitation: Endpoint[
(ApiKeyCredentials, JwtCredentials),
Expand Down Expand Up @@ -154,6 +170,6 @@ object ConnectionEndpoints {
|The created record will contain a newly generated pairwise Peer DID used for that connection.
|A connection request will then be sent to the peer agent to actually establish the connection, moving the record state to `ConnectionRequestSent`, and waiting the connection response from the peer agent.
|""".stripMargin)
.tag(TAG)
.tag(tagName)

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import io.iohk.atala.iam.authentication.apikey.ApiKeyEndpointSecurityLogic.apiKe
import io.iohk.atala.iam.authentication.oidc.JwtCredentials
import io.iohk.atala.iam.authentication.oidc.JwtSecurityLogic.jwtAuthHeader
import io.iohk.atala.pollux.credentialschema.http.*
import sttp.apispec.Tag
import sttp.model.StatusCode
import sttp.tapir.*
import sttp.tapir.json.zio.jsonBody
Expand All @@ -17,11 +18,23 @@ import java.util.UUID

object VerificationPolicyEndpoints {

private val tagName = "Verification"
private val tagDescription = """
|<p>The `Verification` endpoints enable the management and querying of verification policies,
|which are applied to W3C Verifiable Credentials in JWT format.</p>
|<p>Users can retrieve and paginate existing policies or create new ones.
|These policies determine the verification criteria, allowing users to specify constraints such as `schemaId` and `trustedIssuers` in the current implementation.</p>
|<p>The constraints are defined using the `schemaId` and a sequence of `trustedIssuers`.
|This functionality ensures the system's integrity and adherence to specific verification requirements.</p>
|<p>Endpoints are secured by `apiKeyAuth` or `jwtAuth` authentication</p>""".stripMargin
yshyn-iohk marked this conversation as resolved.
Show resolved Hide resolved

val tag = Tag(tagName, Some(tagDescription))

val createVerificationPolicyEndpoint: Endpoint[
(ApiKeyCredentials, JwtCredentials),
(RequestContext, VerificationPolicyInput),
ErrorResponse,
VerificationPolicy,
VerificationPolicyResponse,
Any
] = endpoint.post
.securityIn(apiKeyHeader)
Expand All @@ -39,21 +52,21 @@ object VerificationPolicyEndpoints {
)
)
.out(
jsonBody[VerificationPolicy].description(
jsonBody[VerificationPolicyResponse].description(
"Created verification policy entity"
)
)
.errorOut(basicFailuresAndForbidden)
.name("createVerificationPolicy")
.summary("Create the new verification policy")
.description("Create the new verification policy")
.tag("Verification")
.tag(tagName)

val updateVerificationPolicyEndpoint: Endpoint[
(ApiKeyCredentials, JwtCredentials),
(RequestContext, UUID, Int, VerificationPolicyInput),
ErrorResponse,
VerificationPolicy,
VerificationPolicyResponse,
Any
] =
endpoint.put
Expand All @@ -72,20 +85,20 @@ object VerificationPolicyEndpoints {
)
)
.out(statusCode(StatusCode.Ok))
.out(jsonBody[VerificationPolicy])
.out(jsonBody[VerificationPolicyResponse])
.errorOut(basicFailureAndNotFoundAndForbidden)
.name("updateVerificationPolicy")
.summary("Update the verification policy object by id")
.description(
"Update the verification policy entry"
)
.tag("Verification")
.tag(tagName)

val getVerificationPolicyByIdEndpoint: Endpoint[
(ApiKeyCredentials, JwtCredentials),
(RequestContext, UUID),
ErrorResponse,
VerificationPolicy,
VerificationPolicyResponse,
Any
] =
endpoint.get
Expand All @@ -96,14 +109,14 @@ object VerificationPolicyEndpoints {
"verification" / "policies" / path[UUID]("id")
.description("Get the verification policy by id")
)
.out(jsonBody[VerificationPolicy])
.out(jsonBody[VerificationPolicyResponse])
.errorOut(basicFailureAndNotFoundAndForbidden)
.name("getVerificationPolicyById")
.summary("Fetch the verification policy by id")
.description(
"Get the verification policy by id"
)
.tag("Verification")
.tag(tagName)

val deleteVerificationPolicyByIdEndpoint: Endpoint[
(ApiKeyCredentials, JwtCredentials),
Expand Down Expand Up @@ -131,13 +144,13 @@ object VerificationPolicyEndpoints {
.description(
"Delete the verification policy by id"
)
.tag("Verification")
.tag(tagName)

val lookupVerificationPoliciesByQueryEndpoint: Endpoint[
(ApiKeyCredentials, JwtCredentials),
(RequestContext, VerificationPolicy.Filter, PaginationInput, Option[Order]),
(RequestContext, VerificationPolicyResponse.Filter, PaginationInput, Option[Order]),
ErrorResponse,
VerificationPolicyPage,
VerificationPolicyResponsePage,
Any
] =
endpoint.get
Expand All @@ -148,19 +161,23 @@ object VerificationPolicyEndpoints {
"verification" / "policies"
.description("Lookup verification policy by query")
)
.in(query[Option[String]]("name").mapTo[VerificationPolicy.Filter])
.in(
query[Option[String]]("name")
.description(VerificationPolicyResponse.annotations.name.description)
.mapTo[VerificationPolicyResponse.Filter]
)
.in(
query[Option[Int]]("offset")
.and(query[Option[Int]]("limit"))
.mapTo[PaginationInput]
)
.in(query[Option[Order]]("order"))
.out(jsonBody[VerificationPolicyPage])
.out(jsonBody[VerificationPolicyResponsePage])
.errorOut(basicFailuresAndForbidden)
.name("lookupVerificationPoliciesByQuery")
.summary("Lookup verification policies by query")
.description(
"Lookup verification policies by `name`, and control the pagination by `offset` and `limit` parameters"
)
.tag("Verification")
.tag(tagName)
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import io.iohk.atala.iam.authentication.DefaultAuthenticator
import io.iohk.atala.iam.authentication.SecurityLogic
import io.iohk.atala.pollux.credentialschema.VerificationPolicyEndpoints.*
import io.iohk.atala.pollux.credentialschema.controller.VerificationPolicyController
import io.iohk.atala.pollux.credentialschema.http.{VerificationPolicy, VerificationPolicyInput}
import io.iohk.atala.pollux.credentialschema.http.{VerificationPolicyResponse, VerificationPolicyInput}
import io.iohk.atala.shared.models.WalletAccessContext
import java.util.UUID
import sttp.tapir.ztapir.*
Expand Down Expand Up @@ -82,7 +82,7 @@ class VerificationPolicyServerEndpoints(
{
case (
ctx: RequestContext,
filter: VerificationPolicy.Filter,
filter: VerificationPolicyResponse.Filter,
paginationInput: PaginationInput,
order: Option[Order]
) =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ package io.iohk.atala.pollux.credentialschema.controller

import io.iohk.atala.api.http.model.{Order, Pagination}
import io.iohk.atala.api.http.{ErrorResponse, RequestContext}
import io.iohk.atala.pollux.credentialschema.http.{VerificationPolicy, VerificationPolicyInput, VerificationPolicyPage}
import io.iohk.atala.pollux.credentialschema.http.{
VerificationPolicyResponse,
VerificationPolicyInput,
VerificationPolicyResponsePage
}
import io.iohk.atala.shared.models.WalletAccessContext
import zio.*

Expand All @@ -12,19 +16,19 @@ trait VerificationPolicyController {
def createVerificationPolicy(
ctx: RequestContext,
in: VerificationPolicyInput
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicy]
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicyResponse]

def getVerificationPolicyById(
ctx: RequestContext,
id: UUID
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicy]
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicyResponse]

def updateVerificationPolicyById(
ctx: RequestContext,
id: UUID,
nonce: Int,
update: VerificationPolicyInput
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicy]
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicyResponse]

def deleteVerificationPolicyById(
ctx: RequestContext,
Expand All @@ -33,8 +37,8 @@ trait VerificationPolicyController {

def lookupVerificationPolicies(
ctx: RequestContext,
filter: VerificationPolicy.Filter,
filter: VerificationPolicyResponse.Filter,
pagination: Pagination,
order: Option[Order]
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicyPage]
): ZIO[WalletAccessContext, ErrorResponse, VerificationPolicyResponsePage]
}
Loading
Loading