Skip to content

Commit 28d6747

Browse files
committed
Turn off PostgreSQL 'trust' authentication
When trust authentication [1] is specified, PostgreSQL assumes that anyone who can connect to the server is authorized to access the database with whatever database user name they specify (even superuser). Since this action is intended to be used on CI, this is unlikely a desired behaviour. First, all credentials are known and must be specified in order to avoid flakes. Second, most commonly folks around there want to test that secrets are gathered and passed down to the database server correctly. This patch turns off 'trust' authentication for the PostgreSQL server. [1] https://www.postgresql.org/docs/15/auth-trust.html Resolves #5
1 parent 3973215 commit 28d6747

File tree

2 files changed

+83
-12
lines changed

2 files changed

+83
-12
lines changed

action.yml

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,26 +42,54 @@ runs:
4242
- name: Setup and start PostgreSQL
4343
run: |
4444
export PGDATA="$RUNNER_TEMP/pgdata"
45-
pg_ctl init --options="--encoding=UTF-8 --locale=en_US.UTF-8"
45+
export PWFILE="$RUNNER_TEMP/pwfile"
4646
47-
# Forbid creating unix sockets since they are created by default in the
48-
# directory we don't have permissions to.
49-
echo "unix_socket_directories = ''" >> "$PGDATA/postgresql.conf"
50-
echo "port = ${{ inputs.port }}" >> "$PGDATA/postgresql.conf"
47+
# Save user password on disk so we can create a new PostgreSQL database
48+
# cluster. Password must be set because we're turning 'trust'
49+
# authentication off, and there's no other option since this script is
50+
# not executed interactively.
51+
echo '${{ inputs.password }}' > $PWFILE
52+
53+
# There are couple of reasons why we need to create a new PostgreSQL
54+
# database cluster:
55+
#
56+
# * TODO
57+
# --auth="scram-sha-256" \
58+
initdb \
59+
--username="${{ inputs.username }}" \
60+
--pwfile="$PWFILE" \
61+
--auth-local="trust" \
62+
--auth-host="scram-sha-256" \
63+
--encoding="UTF-8" \
64+
--locale="en_US.UTF-8" \
65+
--no-instructions
66+
67+
cat <<EOF > "$PGDATA/postgresql.conf"
68+
port = ${{ inputs.port }}
69+
EOF
70+
71+
# Client authentication is controlled by a host-based authentication
72+
# configuration file. By default local connections are trusted and do
73+
# not require password (in fact, passwords are ignored). It's undesired
74+
# behaviour in our case since in case of CI we want to make sure that
75+
# the password is configured and passed properly by the application
76+
# under test.
77+
# cat <<EOF > "$PGDATA/pg_hba.conf"
78+
# host all all all scram-sha-256
79+
# EOF
5180
pg_ctl start
5281
5382
# Both PGHOST and PGUSER are used by PostgreSQL tooling such as 'psql'
54-
# or 'createuser'. Since PostgreSQL data has been resetup, we cannot
83+
# or 'createuser'. Since PostgreSQL data has been recreated, we cannot
5584
# rely on defaults anymore.
5685
#
5786
# PGHOST is required for Linux and macOS since they default to unix
5887
# sockets, and we have turned them off.
5988
#
60-
# PGUSER is required for Windows since default the tooling's default
61-
# user is 'postgres', while 'pg_ctl init' creates one with the name of
62-
# the current user.
63-
echo "PGHOST=localhost" >> $GITHUB_ENV
64-
echo "PGUSER=${USER:-$USERNAME}" >> $GITHUB_ENV
89+
# PGUSER is required for Windows since default tooling user is
90+
# 'postgres', while 'pg_ctl init' creates one with the name of the
91+
# current user.
92+
#echo "PGHOST=localhost" >> $GITHUB_ENV
6593
echo "PGPORT=${{ inputs.port }}" >> $GITHUB_ENV
6694
shell: bash
6795

test_action.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import typing as t
21
import os
2+
import typing as t
3+
import urllib.parse
34

45
import psycopg
56
import pytest
@@ -91,3 +92,45 @@ def test_user_create_drop_database(connection: psycopg.Connection):
9192
database_name = "foobar42"
9293
connection.execute(f"CREATE DATABASE {database_name}")
9394
connection.execute(f"DROP DATABASE {database_name}")
95+
96+
97+
def test_auth_wrong_username(connection_factory: t.Callable[[str], psycopg.Connection]):
98+
"""Test that wrong username is rejected!"""
99+
100+
connection_uri = os.getenv("CONNECTION_URI")
101+
connection_parts = urllib.parse.urlparse(connection_uri)
102+
103+
# Despite of exposting username/password of network location, poor Python
104+
# doesn't allow their modification. Thus we have to have these dances in
105+
# order to change the password in the connection URI.
106+
userinfo, _, hostinfo = connection_parts.netloc.rpartition("@")
107+
_ , _, password = userinfo.rpartition(":")
108+
connection_parts = connection_parts._replace(netloc=f"bruteforce:{password}@{hostinfo}")
109+
connection_uri = urllib.parse.urlunparse(connection_parts)
110+
111+
with pytest.raises(psycopg.OperationalError) as excinfo:
112+
test_user_create_insert_select(connection_factory(connection_uri))
113+
assert str(excinfo.value) == (
114+
f'connection failed: FATAL: password authentication failed for user "bruteforce"'
115+
)
116+
117+
118+
def test_auth_wrong_password(connection_factory: t.Callable[[str], psycopg.Connection]):
119+
"""Test that wrong password is rejected!"""
120+
121+
connection_uri = os.getenv("CONNECTION_URI")
122+
connection_parts = urllib.parse.urlparse(connection_uri)
123+
124+
# Despite of exposting username/password of network location, poor Python
125+
# doesn't allow their modification. Thus we have to have these dances in
126+
# order to change the password in the connection URI.
127+
userinfo, _, hostinfo = connection_parts.netloc.rpartition("@")
128+
username, _, _ = userinfo.rpartition(":")
129+
connection_parts = connection_parts._replace(netloc=f"{username}:bruteforce@{hostinfo}")
130+
connection_uri = urllib.parse.urlunparse(connection_parts)
131+
132+
with pytest.raises(psycopg.OperationalError) as excinfo:
133+
test_user_create_insert_select(connection_factory(connection_uri))
134+
assert str(excinfo.value) == (
135+
f'connection failed: FATAL: password authentication failed for user "{username}"'
136+
)

0 commit comments

Comments
 (0)