diff --git a/dev/postgres/password/etc/postgresql/pg_hba.conf b/dev/postgres/password/etc/postgresql/pg_hba.conf new file mode 100644 index 00000000..f19c2163 --- /dev/null +++ b/dev/postgres/password/etc/postgresql/pg_hba.conf @@ -0,0 +1,91 @@ +# PostgreSQL Client Authentication Configuration File +# =================================================== +# +# Refer to the "Client Authentication" section in the PostgreSQL +# documentation for a complete description of this file. A short +# synopsis follows. +# +# This file controls: which hosts are allowed to connect, how clients +# are authenticated, which PostgreSQL user names they can use, which +# databases they can access. Records take one of these forms: +# +# local DATABASE USER METHOD [OPTIONS] +# host DATABASE USER ADDRESS METHOD [OPTIONS] +# hostssl DATABASE USER ADDRESS METHOD [OPTIONS] +# hostnossl DATABASE USER ADDRESS METHOD [OPTIONS] +# hostgssenc DATABASE USER ADDRESS METHOD [OPTIONS] +# hostnogssenc DATABASE USER ADDRESS METHOD [OPTIONS] +# +# (The uppercase items must be replaced by actual values.) +# +# The first field is the connection type: "local" is a Unix-domain +# socket, "host" is either a plain or SSL-encrypted TCP/IP socket, +# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a +# non-SSL TCP/IP socket. Similarly, "hostgssenc" uses a +# GSSAPI-encrypted TCP/IP socket, while "hostnogssenc" uses a +# non-GSSAPI socket. +# +# DATABASE can be "all", "sameuser", "samerole", "replication", a +# database name, or a comma-separated list thereof. The "all" +# keyword does not match "replication". Access to replication +# must be enabled in a separate record (see example below). +# +# USER can be "all", a user name, a group name prefixed with "+", or a +# comma-separated list thereof. In both the DATABASE and USER fields +# you can also write a file name prefixed with "@" to include names +# from a separate file. +# +# ADDRESS specifies the set of hosts the record matches. It can be a +# host name, or it is made up of an IP address and a CIDR mask that is +# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that +# specifies the number of significant bits in the mask. A host name +# that starts with a dot (.) matches a suffix of the actual host name. +# Alternatively, you can write an IP address and netmask in separate +# columns to specify the set of hosts. Instead of a CIDR-address, you +# can write "samehost" to match any of the server's own IP addresses, +# or "samenet" to match any address in any subnet that the server is +# directly connected to. +# +# METHOD can be "trust", "reject", "md5", "password", "scram-sha-256", +# "gss", "sspi", "ident", "peer", "pam", "ldap", "radius" or "cert". +# Note that "password" sends passwords in clear text; "md5" or +# "scram-sha-256" are preferred since they send encrypted passwords. +# +# OPTIONS are a set of options for the authentication in the format +# NAME=VALUE. The available options depend on the different +# authentication methods -- refer to the "Client Authentication" +# section in the documentation for a list of which options are +# available for which authentication methods. +# +# Database and user names containing spaces, commas, quotes and other +# special characters must be quoted. Quoting one of the keywords +# "all", "sameuser", "samerole" or "replication" makes the name lose +# its special character, and just match a database or username with +# that name. +# +# This file is read on server startup and when the server receives a +# SIGHUP signal. If you edit the file on a running system, you have to +# SIGHUP the server for the changes to take effect, run "pg_ctl reload", +# or execute "SELECT pg_reload_conf()". +# +# Put your actual configuration here +# ---------------------------------- +# +# If you want to allow non-local connections, you need to add more +# "host" records. In that case you will also need to make PostgreSQL +# listen on a non-local interface via the listen_addresses +# configuration parameter, or via the -i or -h command line switches. + +# TYPE DATABASE USER ADDRESS METHOD + +# trust local connections +local all supabase_admin password +local all all peer map=supabase_map +host all all 127.0.0.1/32 trust +host all all ::1/128 trust + +# IPv4 external connections +host all all 10.0.0.0/8 password +host all all 172.16.0.0/12 password +host all all 192.168.0.0/16 password +host all all 0.0.0.0/0 password diff --git a/docker-compose.db.yml b/docker-compose.db.yml index 00a8f5de..3c06c267 100644 --- a/docker-compose.db.yml +++ b/docker-compose.db.yml @@ -10,9 +10,13 @@ services: - ./dev/postgres:/docker-entrypoint-initdb.d/ # Uncomment to set MD5 authentication method on uninitialized databases # - ./dev/postgres/md5/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf + # Uncomment to set password authentication method on uninitialized databases + # - ./dev/postgres/password/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf command: postgres -c config_file=/etc/postgresql/postgresql.conf -c max_prepared_transactions=2000 environment: POSTGRES_HOST: /var/run/postgresql POSTGRES_PASSWORD: postgres # Uncomment to set MD5 authentication method on uninitialized databases # POSTGRES_INITDB_ARGS: --auth-host=md5 + # Uncomment to set password authentication method on uninitialized databases + # POSTGRES_INITDB_ARGS: --auth-host=password diff --git a/docker-compose.yml b/docker-compose.yml index b09159f4..985fceb2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,12 +10,16 @@ services: - ./dev/postgres:/docker-entrypoint-initdb.d/ # Uncomment to set MD5 authentication method on uninitialized databases # - ./dev/postgres/md5/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf + # Uncomment to set password authentication method on uninitialized databases + # - ./dev/postgres/password/etc/postgresql/pg_hba.conf:/etc/postgresql/pg_hba.conf command: postgres -c config_file=/etc/postgresql/postgresql.conf -c max_prepared_transactions=2000 environment: POSTGRES_HOST: /var/run/postgresql POSTGRES_PASSWORD: postgres # Uncomment to set MD5 authentication method on uninitialized databases # POSTGRES_INITDB_ARGS: --auth-host=md5 + # Uncomment to set password authentication method on uninitialized databases + # POSTGRES_INITDB_ARGS: --auth-host=password supavisor: build: . container_name: supavisor diff --git a/lib/supavisor/db_handler.ex b/lib/supavisor/db_handler.ex index 739710a2..136414d2 100644 --- a/lib/supavisor/db_handler.ex +++ b/lib/supavisor/db_handler.ex @@ -175,6 +175,9 @@ defmodule Supavisor.DbHandler do :authentication_md5 -> {:keep_state, data} + :authentication_cleartext -> + {:keep_state, data} + {:error_response, ["SFATAL", "VFATAL", "C28P01", reason, _, _, _]} -> handle_authentication_error(data, reason) Logger.error("DbHandler: Auth error #{inspect(reason)}") @@ -657,6 +660,15 @@ defmodule Supavisor.DbHandler do :authentication_md5 end + defp handle_auth_pkts(%{payload: :authentication_cleartext_password} = dec_pkt, _, data) do + Logger.debug("DbHandler: dec_pkt, #{inspect(dec_pkt, pretty: true)}") + + payload = <> + bin = [?p, <>, payload] + :ok = HandlerHelpers.sock_send(data.sock, bin) + :authentication_cleartext + end + defp handle_auth_pkts(%{tag: :error_response, payload: error}, _acc, _data), do: {:error_response, error} diff --git a/test/supavisor/db_handler_test.exs b/test/supavisor/db_handler_test.exs index f8be0b40..acee33c5 100644 --- a/test/supavisor/db_handler_test.exs +++ b/test/supavisor/db_handler_test.exs @@ -131,6 +131,41 @@ defmodule Supavisor.DbHandlerTest do end end + describe "handle_event/4 info tcp authentication authentication_cleartext_password payload events" do + test "keeps state while sending the cleartext password" do + # `82` is `?R`, which identifies the payload tag as `:authentication` + # `0, 0, 0, 8` is the packet length + # `0, 0, 0, 3` is the authentication type, identified as `:authentication_cleartext_password` + bin = <<82, 0, 0, 0, 8, 0, 0, 0, 3>> + + {a, b} = sockpair() + + content = {:tcp, b, bin} + + data = %{ + auth: %{ + password: fn -> "some_password" end, + user: "some_user", + method: :password + }, + sock: {:gen_tcp, a} + } + + assert {:keep_state, ^data} = Db.handle_event(:info, content, :authentication, data) + + assert {:ok, message} = :gen_tcp.recv(b, 0) + + # client response + # p, identifies the payload as password message + # 0,0,0,9 is the payload length (length field + null terminated string) + # 41, 41, 41, 41, 00 is the null terminated password string + password = <> + + assert message == + <> + end + end + describe "handle_event/4 info tcp authentication authentication_md5_password payload events" do test "keeps state while sending the digested md5" do # `82` is `?R`, which identifies the payload tag as `:authentication`