diff --git a/README.md b/README.md index 653ddc9..39395ce 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ def admin_error(e): Example specification located at `./docs/asyncapi.yaml`: ```yaml -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: User Account Service @@ -176,7 +176,7 @@ Without Asynction, one would need to add additional boilerplate to register the ## Security (Authentication and Authorization) -Asynction supports authentication of incoming connections through the security mechanisms specified in the AsyncAPI spec of an application. See [this guide](https://www.asyncapi.com/docs/getting-started/security) on how to add security as part of an API specification. To take advantage of this feature, a security handler callable should be attached to each security scheme definition under the [components](https://www.asyncapi.com/docs/specifications/v2.2.0#componentsObjectSecuritySchemes) section. To attach a security handler(s), see the [security specification extention](#security-handers) section below. +Asynction supports authentication of incoming connections through the security mechanisms specified in the AsyncAPI spec of an application. See [this guide](https://www.asyncapi.com/docs/getting-started/security) on how to add security as part of an API specification. To take advantage of this feature, a security handler callable should be attached to each security scheme definition under the [components](https://www.asyncapi.com/docs/specifications/v2.3.0#componentsObjectSecuritySchemes) section. To attach a security handler(s), see the [security specification extention](#security-handers) section below. The security handler callable(s) will be called upon every new client connection and MUST return a [`SecurityInfo`](https://asynction.dedouss.is/#asynction.SecurityInfo) typed dictionary (which allows extra keys). Asynction then validates this returned dictionary, refusing the connection to any unauthenticated/unauthorised requests. Finally, the validated `SecurityInfo` dictionary is passed to the connection handler as an extra `token_info` kwarg, to allow further/custom processing if needed. @@ -336,7 +336,7 @@ In the future, the Message Ack Object may be extended with extra fields to enabl ### Security handers -In order to support the [AuthN/AuthZ functionality](#security-authentication-and-authorization) of asynction, the [Security Scheme Object](https://www.asyncapi.com/docs/specifications/v2.2.0#securitySchemeObject) needs to be extended as follows: +In order to support the [AuthN/AuthZ functionality](#security-authentication-and-authorization) of asynction, the [Security Scheme Object](https://www.asyncapi.com/docs/specifications/v2.3.0#securitySchemeObject) needs to be extended as follows: - A Security Scheme Object of `oauth2` type MUST include the `x-tokenInfoFunc` field. - A Security Scheme Object of `oauth2` type MAY include the `x-scopeValidateFunc` field. diff --git a/asynction/types.py b/asynction/types.py index 776ebe4..03b3543 100644 --- a/asynction/types.py +++ b/asynction/types.py @@ -34,7 +34,7 @@ class HTTPAuthenticationScheme(Enum): class OAuth2FlowType(Enum): """ - https://www.asyncapi.com/docs/specifications/v2.2.0#oauthFlowsObject + https://www.asyncapi.com/docs/specifications/v2.3.0#oauthFlowsObject """ IMPLICIT = "implicit" @@ -46,7 +46,7 @@ class OAuth2FlowType(Enum): @dataclass class OAuth2Flow: """ - https://www.asyncapi.com/docs/specifications/v2.2.0#oauthFlowObject + https://www.asyncapi.com/docs/specifications/v2.3.0#oauthFlowObject """ scopes: Mapping[str, str] @@ -126,7 +126,7 @@ def supported_scopes(self) -> Iterator[str]: class SecuritySchemesType(Enum): """ - https://www.asyncapi.com/docs/specifications/v2.2.0#securitySchemeObjectType + https://www.asyncapi.com/docs/specifications/v2.3.0#securitySchemeObjectType """ USER_PASSWORD = "userPassword" @@ -146,7 +146,7 @@ class SecuritySchemesType(Enum): class ApiKeyLocation(Enum): """ - https://www.asyncapi.com/docs/specifications/v2.2.0#securitySchemeObject + https://www.asyncapi.com/docs/specifications/v2.3.0#securitySchemeObject """ USER = "user" @@ -159,7 +159,7 @@ class ApiKeyLocation(Enum): @dataclass class SecurityScheme: """ - https://www.asyncapi.com/docs/specifications/v2.2.0#securitySchemeObject + https://www.asyncapi.com/docs/specifications/v2.3.0#securitySchemeObject """ type: SecuritySchemesType @@ -264,7 +264,7 @@ class MessageAck: @dataclass class Message: """ - https://www.asyncapi.com/docs/specifications/2.2.0#messageObject + https://www.asyncapi.com/docs/specifications/2.3.0#messageObject The above message object is extended as follows: * `x-handler`: Allows the coupling of the message specification to @@ -275,7 +275,7 @@ class Message: to the callback of the `emit`/`send` function. Deserialized to `x_ack`. The extentions are implemented as per: - https://www.asyncapi.com/docs/specifications/2.2.0#specificationExtensions + https://www.asyncapi.com/docs/specifications/2.3.0#specificationExtensions """ name: str @@ -326,7 +326,7 @@ def with_name(self, name: str) -> Optional[Message]: @dataclass class Operation: - """https://www.asyncapi.com/docs/specifications/2.2.0#operationObject""" + """https://www.asyncapi.com/docs/specifications/2.3.0#operationObject""" message: OneOfMessages @@ -345,7 +345,7 @@ class WebSocketsChannelBindings: @dataclass class ChannelBindings: - """https://www.asyncapi.com/docs/specifications/2.2.0#channelBindingsObject""" + """https://www.asyncapi.com/docs/specifications/2.3.0#channelBindingsObject""" ws: WebSocketsChannelBindings @@ -360,11 +360,11 @@ class ChannelHandlers: @dataclass class Channel: """ - https://www.asyncapi.com/docs/specifications/2.2.0#channelItemObject + https://www.asyncapi.com/docs/specifications/2.3.0#channelItemObject The above channel item object is extended to support default namespace handlers as per: - https://www.asyncapi.com/docs/specifications/2.2.0#specificationExtensions + https://www.asyncapi.com/docs/specifications/2.3.0#specificationExtensions The `x_handlers` field is serialized as `x-handlers`. """ @@ -412,7 +412,7 @@ class ServerProtocol(Enum): @dataclass class Server: - """https://www.asyncapi.com/docs/specifications/2.2.0#serverObject""" + """https://www.asyncapi.com/docs/specifications/2.3.0#serverObject""" url: str protocol: ServerProtocol @@ -421,7 +421,7 @@ class Server: @dataclass class Info: - """https://www.asyncapi.com/docs/specifications/v2.2.0#infoObject""" + """https://www.asyncapi.com/docs/specifications/v2.3.0#infoObject""" title: str version: str @@ -430,7 +430,7 @@ class Info: @dataclass class Components: - """https://www.asyncapi.com/docs/specifications/v2.2.0#componentsObject""" + """https://www.asyncapi.com/docs/specifications/v2.3.0#componentsObject""" security_schemes: Mapping[str, SecurityScheme] = field(default_factory=dict) @@ -451,7 +451,7 @@ def forge( @dataclass class AsyncApiSpec: - """https://www.asyncapi.com/docs/specifications/2.2.0#A2SObject""" + """https://www.asyncapi.com/docs/specifications/2.3.0#A2SObject""" asyncapi: str channels: Mapping[str, Channel] diff --git a/example/asyncapi.yml b/example/asyncapi.yml index 950afc8..5ec3a6d 100644 --- a/example/asyncapi.yml +++ b/example/asyncapi.yml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Socket.IO chat demo service diff --git a/setup.py b/setup.py index 127a876..0c463dc 100644 --- a/setup.py +++ b/setup.py @@ -12,10 +12,6 @@ readme = readme_file.read() -with open("requirements.txt") as requiremets_file: - requirements = requiremets_file.read().split() - - def parse_requirements(file_path: Path) -> Sequence[str]: reqs = [] with file_path.open() as f: @@ -50,6 +46,8 @@ def make_extra_requirements() -> Mapping[str, str]: return extra_requirements +requirements = parse_requirements(Path(__file__).parent / "requirements.txt") + version = os.environ["PKG_VERSION"] diff --git a/tests/fixtures/array_vs_tuple.yaml b/tests/fixtures/array_vs_tuple.yaml index 09be15a..df3fddb 100644 --- a/tests/fixtures/array_vs_tuple.yaml +++ b/tests/fixtures/array_vs_tuple.yaml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Simple API version: 0.0.1 diff --git a/tests/fixtures/echo.yml b/tests/fixtures/echo.yml index 166d6a9..104d311 100644 --- a/tests/fixtures/echo.yml +++ b/tests/fixtures/echo.yml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Echo API version: 0.0.1 diff --git a/tests/fixtures/namespace_security.yaml b/tests/fixtures/namespace_security.yaml index 0c49186..d42a9ea 100644 --- a/tests/fixtures/namespace_security.yaml +++ b/tests/fixtures/namespace_security.yaml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Test version: 1.0.0 diff --git a/tests/fixtures/security.yaml b/tests/fixtures/security.yaml index 4b9e45c..f16db4e 100644 --- a/tests/fixtures/security.yaml +++ b/tests/fixtures/security.yaml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Test version: 1.0.0 diff --git a/tests/fixtures/security_oauth2.yaml b/tests/fixtures/security_oauth2.yaml index 9e7a142..106663e 100644 --- a/tests/fixtures/security_oauth2.yaml +++ b/tests/fixtures/security_oauth2.yaml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Test version: 1.0.0 diff --git a/tests/fixtures/simple.yml b/tests/fixtures/simple.yml index 9b87ba7..93a6058 100644 --- a/tests/fixtures/simple.yml +++ b/tests/fixtures/simple.yml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Simple API version: 0.0.1 diff --git a/tests/fixtures/simple_with_servers.yml b/tests/fixtures/simple_with_servers.yml index 68265bb..19624ea 100644 --- a/tests/fixtures/simple_with_servers.yml +++ b/tests/fixtures/simple_with_servers.yml @@ -1,4 +1,4 @@ -asyncapi: 2.2.0 +asyncapi: 2.3.0 info: title: Simple API with Servers version: 0.0.1 diff --git a/tests/unit/test_mock_server.py b/tests/unit/test_mock_server.py index 99d9857..231263a 100644 --- a/tests/unit/test_mock_server.py +++ b/tests/unit/test_mock_server.py @@ -352,7 +352,7 @@ def test_register_handlers_registers_connection_handler_with_bindings_validation def test_register_namespace_handlers_includes_server_security_validation(): channel_handlers = ChannelHandlers(connect="tests.fixtures.handlers.connect") spec = AsyncApiSpec( - asyncapi="2.2.0", + asyncapi="2.3.0", info=Info("test", "1.0.0"), servers={ "test": Server("https://localhost/", ServerProtocol.WSS, [{"basic": []}]) @@ -389,7 +389,7 @@ def test_register_namespace_handlers_includes_server_security_validation(): def test_register_namespace_handlers_channel_security_overrides_server_security(): channel_handlers = ChannelHandlers(connect="tests.fixtures.handlers.connect") spec = AsyncApiSpec( - asyncapi="2.2.0", + asyncapi="2.3.0", info=Info("test", "1.0.0"), servers={"test": Server("https://localhost/", ServerProtocol.WSS, [])}, channels={ diff --git a/tests/unit/test_server.py b/tests/unit/test_server.py index cc9e242..0f587b0 100644 --- a/tests/unit/test_server.py +++ b/tests/unit/test_server.py @@ -126,7 +126,7 @@ def my_default_error_handler(_): def test_resolve_references_resolves_successfully(): raw_spec = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": "My API", "version": "0.0.0", @@ -174,7 +174,7 @@ def test_resolve_references_resolves_successfully(): } resolved = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": "My API", "version": "0.0.0", @@ -504,7 +504,7 @@ def test_register_namespace_handlers_omits_bindings_validator_if_validation_disa def test_register_namespace_handlers_includes_server_security_validation(): channel_handlers = ChannelHandlers(connect="tests.fixtures.handlers.connect") spec = AsyncApiSpec( - asyncapi="2.2.0", + asyncapi="2.3.0", info=Info("test", "1.0.0"), servers={ "test": Server("https://localhost/", ServerProtocol.WSS, [{"basic": []}]) @@ -547,7 +547,7 @@ def test_register_namespace_handlers_channel_security_overrides_server_security( channel_handlers = ChannelHandlers(connect="tests.fixtures.handlers.connect") channel_security = [{"basic": []}] spec = AsyncApiSpec( - asyncapi="2.2.0", + asyncapi="2.3.0", info=Info("test", "1.0.0"), servers={"test": Server("https://localhost/", ServerProtocol.WSS, [])}, channels={ diff --git a/tests/unit/test_types.py b/tests/unit/test_types.py index 0e8dc75..89774a7 100644 --- a/tests/unit/test_types.py +++ b/tests/unit/test_types.py @@ -169,7 +169,7 @@ def test_channel_raises_value_error_if_publish_messages_miss_handler(faker: Fake def test_async_api_spec_from_and_to_dict(faker: Faker): data = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": faker.sentence(), "version": faker.pystr(), @@ -309,7 +309,7 @@ def test_security_scheme_validation(): def test_asyncapi_spec_validation_invalid_security_requirement(faker: Faker): data = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": faker.sentence(), "version": faker.pystr(), @@ -348,7 +348,7 @@ def test_asyncapi_spec_validation_invalid_security_requirement(faker: Faker): def test_asyncapi_spec_validation_invalid_security_requirement_scopes(faker: Faker): data = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": faker.sentence(), "version": faker.pystr(), @@ -389,7 +389,7 @@ def test_asyncapi_spec_validation_invalid_security_requirement_undefined_scopes( faker: Faker, ): data = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": faker.sentence(), "version": faker.pystr(), @@ -430,7 +430,7 @@ def test_asyncapi_spec_validation_invalid_security_requirement_on_namespace( faker: Faker, ): data = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": faker.sentence(), "version": faker.pystr(), @@ -472,7 +472,7 @@ def test_asyncapi_spec_validation_invalid_security_requirement_on_namespace( def test_asyncapi_spec_validation_missing_security_scheme(faker: Faker): data = { - "asyncapi": "2.2.0", + "asyncapi": "2.3.0", "info": { "title": faker.sentence(), "version": faker.pystr(),