From 811415b8664aea4353f3ade35e3c8f6d6aee649d Mon Sep 17 00:00:00 2001 From: Akram Yakubov Date: Fri, 3 Jan 2025 06:15:22 -0800 Subject: [PATCH] Support GSS encrypt request decoding as part of psql 14.15 client (#1361) --- .../gss.encrypt.request/client.rpt | 31 +++++++ .../gss.encrypt.request/server.rpt | 35 ++++++++ .../network/gss.encrypt.request/client.rpt | 85 ++++++++++++++++++ .../network/gss.encrypt.request/server.rpt | 87 +++++++++++++++++++ .../binding/pgsql/streams/ApplicationIT.java | 9 ++ .../binding/pgsql/streams/NetworkIT.java | 9 ++ .../internal/stream/PgsqlServerFactory.java | 43 +++++++-- .../binding-pgsql/src/main/zilla/protocol.idl | 11 +++ .../pgsql/internal/stream/ServerIT.java | 10 +++ 9 files changed, 315 insertions(+), 5 deletions(-) create mode 100644 incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/client.rpt create mode 100644 incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/server.rpt create mode 100644 incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/client.rpt create mode 100644 incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/server.rpt diff --git a/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/client.rpt b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/client.rpt new file mode 100644 index 0000000000..2e9c31cf2a --- /dev/null +++ b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/client.rpt @@ -0,0 +1,31 @@ +# +# Copyright 2021-2024 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +connect "zilla://streams/app0" + option zilla:window 8192 + option zilla:transmission "duplex" + +write zilla:begin.ext ${pgsql:beginEx() + .typeId(zilla:id("pgsql")) + .parameter("user", "root") + .parameter("database", "dev") + .parameter("application_name", "psql") + .parameter("client_encoding", "UTF8") + .build()} + +connected + +read closed +write close diff --git a/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/server.rpt b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/server.rpt new file mode 100644 index 0000000000..7eea0f9676 --- /dev/null +++ b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/application/gss.encrypt.request/server.rpt @@ -0,0 +1,35 @@ +# +# Copyright 2021-2024 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +property serverAddress "zilla://streams/app0" + +accept ${serverAddress} + option zilla:window 8192 + option zilla:transmission "duplex" + +accepted + +read zilla:begin.ext ${pgsql:beginEx() + .typeId(zilla:id("pgsql")) + .parameter("user", "root") + .parameter("database", "dev") + .parameter("application_name", "psql") + .parameter("client_encoding", "UTF8") + .build()} + +connected + +write close +read closed diff --git a/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/client.rpt b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/client.rpt new file mode 100644 index 0000000000..5ad39e1122 --- /dev/null +++ b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/client.rpt @@ -0,0 +1,85 @@ +# +# Copyright 2021-2024 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +property networkConnectWindow 8192 + +connect "zilla://streams/net0" + option zilla:window ${networkConnectWindow} + option zilla:transmission "duplex" + option zilla:byteorder "network" + +connected + +write 8 # length + [0x04 0xd2 0x16 0x30] # gss encrypt request code + +read [0x4e] + +write 8 # length + [0x04 0xd2 0x16 0x2f] # ssl request code + +read [0x4e] + +write 75 # length + 3s # major version + 0s # minor version + "user" [0x00] # name + "root" [0x00] # value + "database" [0x00] # name + "dev" [0x00] # value + "application_name" [0x00] # name + "psql" [0x00] # value + "client_encoding" [0x00] # name + "UTF8" [0x00] # value + [0x00] # end of parameters + +read [0x52] # type R + 8 # length + 0 # authentication type + +read [0x4b] # type K + 12 # length + 0 # pid + 0 # key + +read [0x53] # type S + 25 # length + "client_encoding" [0x00] # name + "UTF8" [0x00] # value + +read [0x53] # type S + 35 # length + "standard_conforming_strings" [0x00] # name + [0x6f 0x6e 0x00] # value + +read [0x53] # type S + 25 # length + "server_version" [0x00] # name + "9.1.0" [0x00] # value + +read [0x53] # type S + 27 # length + "application_name" [0x00] # name + "zilla" [0x00] # value + +read [0x5a] # type Z + 5 # length + [0x49] # status + +read [0x58] # type X + 4 # length + +read closed +write close diff --git a/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/server.rpt b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/server.rpt new file mode 100644 index 0000000000..be17159fe3 --- /dev/null +++ b/incubator/binding-pgsql.spec/src/main/scripts/io/aklivity/zilla/specs/binding/pgsql/streams/network/gss.encrypt.request/server.rpt @@ -0,0 +1,87 @@ +# +# Copyright 2021-2024 Aklivity Inc +# +# Licensed under the Aklivity Community License (the "License"); you may not use +# this file except in compliance with the License. You may obtain a copy of the +# License at +# +# https://www.aklivity.io/aklivity-community-license/ +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OF ANY KIND, either express or implied. See the License for the +# specific language governing permissions and limitations under the License. +# + +property networkAcceptWindow 8192 + +accept "zilla://streams/net0" + option zilla:window ${networkAcceptWindow} + option zilla:transmission "duplex" + option zilla:byteorder "network" + +accepted + +connected + +read 8 # length + [0x04 0xd2 0x16 0x30] # gss encrypt request code + +write [0x4e] + +read 8 # length + [0x04 0xd2 0x16 0x2f] # ssl request code + +write [0x4e] + +read 75 # length + 3s # major version + 0s # minor version + "user" [0x00] # name + "root" [0x00] # value + "database" [0x00] # name + "dev" [0x00] # value + "application_name" [0x00] # name + "psql" [0x00] # value + "client_encoding" [0x00] # name + "UTF8" [0x00] # value + [0x00] # end of parameters + +write [0x52] # type R + 8 # length + 0 # authentication type + +write [0x4b] # type K + 12 # length + 0 # pid + 0 # key + +write [0x53] # type S + 25 # length + "client_encoding" [0x00] # name + "UTF8" [0x00] # value + +write [0x53] # type S + 35 # length + "standard_conforming_strings" [0x00] # name + [0x6f 0x6e 0x00] # value + +write [0x53] # type S + 25 # length + "server_version" [0x00] # name + "9.1.0" [0x00] # value + +write [0x53] # type S + 27 # length + "application_name" [0x00] # name + "zilla" [0x00] # value + +write [0x5a] # type Z + 5 # length + [0x49] # status + +write [0x58] # type X + 4 # length + +write close +read closed diff --git a/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/ApplicationIT.java b/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/ApplicationIT.java index 4874ddaf64..48c61f2343 100644 --- a/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/ApplicationIT.java +++ b/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/ApplicationIT.java @@ -101,6 +101,15 @@ public void shouldHandleFragmentedCreateTable() throws Exception k3po.finish(); } + @Test + @Specification({ + "${app}/gss.encrypt.request/client", + "${app}/gss.encrypt.request/server" }) + public void shouldHandleGssEncryptRequest() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${app}/ssl.request/client", diff --git a/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/NetworkIT.java b/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/NetworkIT.java index e386a8a532..1078e25d1a 100644 --- a/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/NetworkIT.java +++ b/incubator/binding-pgsql.spec/src/test/java/io/aklivity/zilla/specs/binding/pgsql/streams/NetworkIT.java @@ -83,6 +83,15 @@ public void shouldHandleSslRequest() throws Exception k3po.finish(); } + @Test + @Specification({ + "${net}/gss.encrypt.request/client", + "${net}/gss.encrypt.request/server" }) + public void shouldHandleGssEncryptRequest() throws Exception + { + k3po.finish(); + } + @Test @Specification({ "${net}/client.sent.write.abort/client", diff --git a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/PgsqlServerFactory.java b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/PgsqlServerFactory.java index 02f07dc7df..1da532c1bc 100644 --- a/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/PgsqlServerFactory.java +++ b/incubator/binding-pgsql/src/main/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/PgsqlServerFactory.java @@ -38,6 +38,8 @@ import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlAuthenticationMessageFW; import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlBackendKeyMessageFW; import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlCancelRequestMessageFW; +import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlGssEncryptRequestFW; +import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlGssEncryptResponseFW; import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlMessageFW; import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlSslRequestFW; import io.aklivity.zilla.runtime.binding.pgsql.internal.types.codec.PgsqlSslResponseFW; @@ -79,6 +81,7 @@ public final class PgsqlServerFactory implements PgsqlStreamFactory private static final Byte MESSAGE_TYPE_PARAMETER_STATUS = 'S'; private static final int SSL_REQUEST_CODE = 80877103; + private static final int GSS_ENCRYPT_REQUEST_CODE = 80877104; private static final int CANCEL_REQUEST_CODE = 80877102; private static final int END_OF_FIELD = 0x00; @@ -122,11 +125,13 @@ public final class PgsqlServerFactory implements PgsqlStreamFactory private final PgsqlMessageFW messageRO = new PgsqlMessageFW(); private final PgsqlSslRequestFW sslRequestRO = new PgsqlSslRequestFW(); + private final PgsqlGssEncryptRequestFW gssRequestRO = new PgsqlGssEncryptRequestFW(); private final PgsqlStartupMessageFW startupMessageRO = new PgsqlStartupMessageFW(); private final PgsqlCancelRequestMessageFW cancelReqMessageRO = new PgsqlCancelRequestMessageFW(); private final PgsqlMessageFW.Builder messageRW = new PgsqlMessageFW.Builder(); private final PgsqlSslResponseFW.Builder sslResponseRW = new PgsqlSslResponseFW.Builder(); + private final PgsqlGssEncryptResponseFW.Builder gssResponseRW = new PgsqlGssEncryptResponseFW.Builder(); private final PgsqlAuthenticationMessageFW.Builder authMessageRW = new PgsqlAuthenticationMessageFW.Builder(); private final PgsqlBackendKeyMessageFW.Builder backendKeyMessageRW = new PgsqlBackendKeyMessageFW.Builder(); @@ -146,6 +151,7 @@ public final class PgsqlServerFactory implements PgsqlStreamFactory private final int pgsqlTypeId; private final PgsqlServerDecoder decodePgsqlInitial = this::decodePgsqlInitial; + private final PgsqlServerDecoder decodePgsqlGssRequest = this::decodePgsqlGssEncryptRequest; private final PgsqlServerDecoder decodePgsqlSslRequest = this::decodePgsqlSslRequest; private final PgsqlServerDecoder decodePgsqlStartupMessage = this::decodePgsqlStartupMessage; private final PgsqlServerDecoder decodePgsqlCancelRequest = this::decodePgsqlCancelRequest; @@ -605,6 +611,14 @@ public void onDecodeSslRequest( doNetworkData(traceId, authorization, FLAGS_COMP, 0L, messageBuffer, 0, sslResponse.limit()); } + public void onDecodeGssEncryptRequest( + long traceId, + long authorization) + { + PgsqlGssEncryptResponseFW gssResponse = gssResponseRW.wrap(messageBuffer, 0, messageBuffer.capacity()).build(); + doNetworkData(traceId, authorization, FLAGS_COMP, 0L, messageBuffer, 0, gssResponse.limit()); + } + public void onDecodeCancelRequest( long traceId, long authorization, @@ -1493,10 +1507,16 @@ private int decodePgsqlInitial( int limit) { final PgsqlSslRequestFW pgsqlSslRequest = sslRequestRO.tryWrap(buffer, offset, limit); + final PgsqlGssEncryptRequestFW pgsqlGssRequest = gssRequestRO.tryWrap(buffer, offset, limit); final PgsqlCancelRequestMessageFW cancelRequest = cancelReqMessageRO.tryWrap(buffer, offset, limit); final PgsqlStartupMessageFW startupMessage = startupMessageRO.tryWrap(buffer, offset, limit); - if (pgsqlSslRequest != null && + if (pgsqlGssRequest != null && + pgsqlGssRequest.code() == GSS_ENCRYPT_REQUEST_CODE) + { + server.decoder = decodePgsqlGssRequest; + } + else if (pgsqlSslRequest != null && pgsqlSslRequest.code() == SSL_REQUEST_CODE) { server.decoder = decodePgsqlSslRequest; @@ -1510,10 +1530,6 @@ else if (startupMessage != null) { server.decoder = decodePgsqlStartupMessage; } - else - { - server.decoder = decodePgsqlIgnoreAll; - } return offset; } @@ -1535,6 +1551,23 @@ private int decodePgsqlSslRequest( return sslRequest.limit(); } + private int decodePgsqlGssEncryptRequest( + PgsqlServer server, + long traceId, + long authorization, + long budgetId, + DirectBuffer buffer, + int offset, + int limit) + { + PgsqlGssEncryptRequestFW gssRequest = gssRequestRO.wrap(buffer, offset, limit); + + server.onDecodeGssEncryptRequest(traceId, authorization); + server.decoder = decodePgsqlInitial; + + return gssRequest.limit(); + } + private int decodePgsqlStartupMessage( PgsqlServer server, long traceId, diff --git a/incubator/binding-pgsql/src/main/zilla/protocol.idl b/incubator/binding-pgsql/src/main/zilla/protocol.idl index 84db203fcf..df40e8877a 100644 --- a/incubator/binding-pgsql/src/main/zilla/protocol.idl +++ b/incubator/binding-pgsql/src/main/zilla/protocol.idl @@ -29,6 +29,17 @@ scope protocol uint8 answer = 78; } + struct PgsqlGssEncryptRequest + { + int32 length = 4; + int32 code = 80877104; + } + + struct PgsqlGssEncryptResponse + { + uint8 answer = 78; + } + struct PgsqlStartupMessage { int32 length; diff --git a/incubator/binding-pgsql/src/test/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/ServerIT.java b/incubator/binding-pgsql/src/test/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/ServerIT.java index 26ec542b52..d4b5bb6f00 100644 --- a/incubator/binding-pgsql/src/test/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/ServerIT.java +++ b/incubator/binding-pgsql/src/test/java/io/aklivity/zilla/runtime/binding/pgsql/internal/stream/ServerIT.java @@ -58,6 +58,16 @@ public void shouldHandleSslRequest() throws Exception k3po.finish(); } + @Test + @Configuration("server.yaml") + @Specification({ + "${net}/gss.encrypt.request/client", + "${app}/gss.encrypt.request/server" }) + public void shouldHandleGssEncryptRequest() throws Exception + { + k3po.finish(); + } + @Test @Configuration("server.yaml") @Specification({