Skip to content

Commit

Permalink
fix(electric): Implement support for AuthenticationMD5Password upstre…
Browse files Browse the repository at this point in the history
…am auth method (#859)

Fixes VAX-1553.
  • Loading branch information
alco committed Jan 24, 2024
1 parent e1ec666 commit 30179e8
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-snakes-jog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@core/electric": patch
---

[VAX-1553] Add support for AuthenticationMD5Password upstream auth method in the Migrations proxy. This fixes a connectivity issue between Electric and DigitalOcean Managed PostgreSQL.
8 changes: 8 additions & 0 deletions components/electric/lib/electric/errors.ex
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ defmodule Electric.Errors do
"""
end

defp format_header(:not_implemented) do
"""
┌─────────────────────────┐
│ NOT IMPLEMENTED ERROR │
┕━━━━━━━━━━━━━━━━━━━━━━━━━┙
"""
end

defp format_header(module_alias) do
module_line = " MODULE ERROR: " <> inspect(module_alias) <> " "
n = byte_size(module_line)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,17 @@ defmodule Electric.Postgres.Proxy.UpstreamConnection do
upstream(response, state)
end

defp handle_backend_msg(
%M.AuthenticationMD5Password{salt: salt},
%{authenticated: false, conn_opts: conn_opts} = state
) do
userspec_digest = md5_hex_digest([conn_opts[:password], conn_opts[:username]])
salted_digest = md5_hex_digest([userspec_digest, salt])
response = %M.PasswordMessage{password: "md5" <> salted_digest}

upstream(response, state)
end

defp handle_backend_msg(%M.AuthenticationSASL{} = msg, %{authenticated: false} = state) do
{sasl_mechanism, response} = SASL.initial_response(msg)

Expand All @@ -176,6 +187,15 @@ defmodule Electric.Postgres.Proxy.UpstreamConnection do
%{state | sasl: nil}
end

defp handle_backend_msg(%msg_type{} = msg, _state)
when msg_type in [M.AuthenticationKerberosV5, M.AuthenticationGSS, M.AuthenticationSSPI] do
error_msg = "Proxy's upstream connection requested unsupported authentication method:"
error_val = inspect(msg, pretty: true)

Electric.Errors.print_error(:not_implemented, error_msg <> "\n\n " <> error_val)
exit(error_msg <> " " <> error_val)
end

defp handle_backend_msg(msg, state) do
%{state | pending: [msg | state.pending]}
end
Expand Down Expand Up @@ -206,4 +226,8 @@ defmodule Electric.Postgres.Proxy.UpstreamConnection do
defp reset_conn(state) do
%{state | conn: nil, transport_module: :gen_tcp}
end

defp md5_hex_digest(iodata) do
:crypto.hash(:md5, iodata) |> Base.encode16(case: :lower)
end
end
2 changes: 0 additions & 2 deletions components/electric/test/electric/postgres/proxy_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ defmodule Electric.Postgres.ProxyTest do
# Verify that both upstream connections have shut down without errors.
assert_receive {:DOWN, ^mon1, :process, ^pid1, :normal}
assert_receive {:DOWN, ^mon2, :process, ^pid2, :normal}

Process.sleep(1000)
end)
end
end

0 comments on commit 30179e8

Please sign in to comment.