From 58484837874de26f8dfeff5d2ba540193b1ea535 Mon Sep 17 00:00:00 2001 From: Pavel Bodiachevskii Date: Wed, 7 Feb 2024 02:21:28 +0400 Subject: [PATCH] test(3.0.0): check correctness of realisation by reading AsyncAPI example - Operation Security AsyncAPI example --- README.md | 2 +- .../v3/_0_0/OperationSecurityAsyncAPI.kt | 229 ++++++++++++++++++ .../v3.0.0/operation-security-asyncapi.yml | 117 +++++++++ 3 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 asyncapi-core/src/test/kotlin/com/asyncapi/examples/v3/_0_0/OperationSecurityAsyncAPI.kt create mode 100644 asyncapi-core/src/test/resources/examples/v3.0.0/operation-security-asyncapi.yml diff --git a/README.md b/README.md index 5dca70a8..c90cb4eb 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Hints: - [x] [mercure-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/mercure-asyncapi.yml) - [x] [not-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/not-asyncapi.yml) - [x] [oneof-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/oneof-asyncapi.yml) -- [ ] [operation-security-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/operation-security-asyncapi.yml) +- [x] [operation-security-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/operation-security-asyncapi.yml) - [x] [rpc-client-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/rpc-client-asyncapi.yml) - [x] [rpc-server-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/rpc-server-asyncapi.yml) - [x] [simple-asyncapi.yml](https://github.com/asyncapi/spec/blob/master/examples/simple-asyncapi.yml) diff --git a/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v3/_0_0/OperationSecurityAsyncAPI.kt b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v3/_0_0/OperationSecurityAsyncAPI.kt new file mode 100644 index 00000000..46cd3011 --- /dev/null +++ b/asyncapi-core/src/test/kotlin/com/asyncapi/examples/v3/_0_0/OperationSecurityAsyncAPI.kt @@ -0,0 +1,229 @@ +package com.asyncapi.examples.v3._0_0 + +import com.asyncapi.v3.Reference +import com.asyncapi.v3._0_0.model.channel.Channel +import com.asyncapi.v3._0_0.model.channel.message.Message +import com.asyncapi.v3._0_0.model.component.Components +import com.asyncapi.v3._0_0.model.info.Info +import com.asyncapi.v3._0_0.model.operation.Operation +import com.asyncapi.v3._0_0.model.operation.OperationAction +import com.asyncapi.v3.binding.operation.http.HTTPOperationBinding +import com.asyncapi.v3.binding.operation.http.HTTPOperationMethod +import com.asyncapi.v3.schema.Schema +import com.asyncapi.v3.security_scheme.oauth2.OAuth2SecurityScheme +import com.asyncapi.v3.security_scheme.oauth2.OAuthFlows +import com.asyncapi.v3.security_scheme.oauth2.flow.ClientCredentialsOAuthFlow + +class OperationSecurityAsyncAPI: AbstractExampleValidationTest() { + + override fun specificationLocation(): String = "/examples/v3.0.0/operation-security-asyncapi.yml" + + override fun expectedInfo(): Info { + return Info.builder() + .title("Notifications") + .version("1.0.0") + .description("This contract defines HTTP Push notification for application authorization revocation topic") + .build() + } + + override fun expectedServers(): Map = emptyMap() + + override fun expectedChannels(): Map { + return mapOf( + Pair("authRevoke", + Channel.builder() + .address("AUTHORIZATION_REVOCATION") + .messages(mapOf( + Pair("message", Reference("#/components/messages/message")) + )) + .build() + ) + ) + } + + override fun expectedOperations(): Map { + return mapOf( + Pair("sendAuthRevoke", + Operation.builder() + .action(OperationAction.SEND) + .channel(Reference("#/channels/authRevoke")) + .security(listOf( + OAuth2SecurityScheme( + "The oauth security descriptions", + OAuthFlows( + null, + null, + ClientCredentialsOAuthFlow( + "", + mapOf( + Pair("subscribe:auth_revocations", "Scope required for authorization revocation topic") + ), + "https://example.com/api/oauth/dialog" + ), + null + ), + listOf("subscribe:auth_revocations"), + ) + )) + .bindings(mapOf( + Pair("http", HTTPOperationBinding.builder() + .method(HTTPOperationMethod.POST) + .build()) + )) + .messages(listOf( + Reference("#/channels/authRevoke/messages/message") + )) + .build() + ) + ) + } + + override fun expectedComponents(): Components? { + return Components.builder() + .messages(mapOf( + Pair("message", + Message.builder() + .headers(Schema.builder() + .type("object") + .properties(mapOf( + Pair("X-SIGNATURE", Schema.builder() + .description("ECC message signature") + .type("string") + .build() + ), + Pair("Content-Type", Schema.builder() + .type("string") + .enumValue(listOf( + "application/json" + )) + .build() + ) + )) + .build()) + .payload(Schema.builder() + .type("object") + .properties(mapOf( + Pair("metadata", Schema.builder().ref("#/components/schemas/MetaData").build()), + Pair("notification", Schema.builder().ref("#/components/schemas/Notification").build()) + )) + .build()) + .build() + ) + )) + .schemas(mapOf( + Pair("MetaData", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("topic", Schema.builder() + .type("string") + .description("Topic subscribed to.") + .build() + ), + Pair("schemaVersion", Schema.builder() + .type("string") + .description("The schema for this topic.") + .build() + ), + Pair("deprecated", Schema.builder() + .type("boolean") + .description("If this is a deprecated schema or topic.") + .defaultValue("false") + .build() + ) + )) + .build() + ), + Pair("Notification", + Schema.builder() + .type("object") + .properties(mapOf( + Pair("notificationId", Schema.builder() + .type("string") + .description("The notification Id.") + .build() + ), + Pair("eventDate", Schema.builder() + .type("string") + .description("The event date associated with this notification in UTC.") + .build() + ), + Pair("publishDate", Schema.builder() + .type("string") + .description("The message publish date in UTC.") + .build() + ), + Pair("publishAttemptCount", Schema.builder() + .type("integer") + .description("The number of attempts made to publish this message.") + .build() + ), + Pair("data", Schema.builder() + .ref("#/components/schemas/AuthorizationRevocationData") + .build() + ) + )) + .build() + ), + Pair("AuthorizationRevocationData", + Schema.builder() + .type("object") + .description("The Authorization Revocation payload.") + .properties(mapOf( + Pair("username", Schema.builder() + .type("string") + .description("The username for the user.") + .build() + ), + Pair("userId", Schema.builder() + .type("string") + .description("The immutable public userId for the user") + .build() + ), + Pair("eiasToken", Schema.builder() + .type("string") + .description("The legacy eiasToken specific to the user") + .build() + ), + Pair("revokeReason", Schema.builder() + .type("string") + .description("The reason for authorization revocation") + .enumValue(listOf( + "REVOKED_BY_APP", + "REVOKED_BY_USER", + "REVOKED_BY_ADMIN", + "PASSWORD_CHANGE" + )) + .build() + ), + Pair("revocationDate", Schema.builder() + .type("string") + .description("Date and time when the authorization was revoked") + .build() + ) + )) + .build() + ) + )) + .securitySchemes(mapOf( + Pair("petstore_auth", OAuth2SecurityScheme( + "The oauth security descriptions", + OAuthFlows( + null, + null, + ClientCredentialsOAuthFlow( + "", + mapOf( + Pair("subscribe:auth_revocations", "Scope required for authorization revocation topic") + ), + "https://example.com/api/oauth/dialog" + ), + null + ), + null + )) + )) + .build() + } + +} \ No newline at end of file diff --git a/asyncapi-core/src/test/resources/examples/v3.0.0/operation-security-asyncapi.yml b/asyncapi-core/src/test/resources/examples/v3.0.0/operation-security-asyncapi.yml new file mode 100644 index 00000000..cd003954 --- /dev/null +++ b/asyncapi-core/src/test/resources/examples/v3.0.0/operation-security-asyncapi.yml @@ -0,0 +1,117 @@ +asyncapi: 3.0.0 +info: + title: Notifications + version: 1.0.0 + description: >- + This contract defines HTTP Push notification for application authorization + revocation topic +channels: + authRevoke: + address: AUTHORIZATION_REVOCATION + messages: + message: + $ref: '#/components/messages/message' +operations: + sendAuthRevoke: + action: send + channel: + $ref: '#/channels/authRevoke' + security: + - type: oauth2 + description: The oauth security descriptions + flows: + clientCredentials: + tokenUrl: 'https://example.com/api/oauth/dialog' + availableScopes: + 'subscribe:auth_revocations': Scope required for authorization revocation topic + scopes: + - 'subscribe:auth_revocations' + bindings: + http: + method: POST + messages: + - $ref: '#/channels/authRevoke/messages/message' +components: + messages: + message: + headers: + type: object + properties: + X-SIGNATURE: + description: ECC message signature + type: string + Content-Type: + type: string + enum: + - application/json + payload: + type: object + properties: + metadata: + $ref: '#/components/schemas/MetaData' + notification: + $ref: '#/components/schemas/Notification' + schemas: + MetaData: + type: object + properties: + topic: + type: string + description: Topic subscribed to. + schemaVersion: + type: string + description: The schema for this topic. + deprecated: + type: boolean + description: If this is a deprecated schema or topic. + default: 'false' + Notification: + type: object + properties: + notificationId: + type: string + description: The notification Id. + eventDate: + type: string + description: The event date associated with this notification in UTC. + publishDate: + type: string + description: The message publish date in UTC. + publishAttemptCount: + type: integer + description: The number of attempts made to publish this message. + data: + $ref: '#/components/schemas/AuthorizationRevocationData' + AuthorizationRevocationData: + type: object + description: The Authorization Revocation payload. + properties: + username: + type: string + description: The username for the user. + userId: + type: string + description: The immutable public userId for the user + eiasToken: + type: string + description: The legacy eiasToken specific to the user + revokeReason: + type: string + enum: + - REVOKED_BY_APP + - REVOKED_BY_USER + - REVOKED_BY_ADMIN + - PASSWORD_CHANGE + description: The reason for authorization revocation + revocationDate: + type: string + description: Date and time when the authorization was revoked + securitySchemes: + petstore_auth: + type: oauth2 + description: The oauth security descriptions + flows: + clientCredentials: + tokenUrl: 'https://example.com/api/oauth/dialog' + availableScopes: + 'subscribe:auth_revocations': Scope required for authorization revocation topic \ No newline at end of file