diff options
author | Heikki Linnakangas | 2017-04-07 11:56:05 +0000 |
---|---|---|
committer | Heikki Linnakangas | 2017-04-07 11:56:05 +0000 |
commit | 60f11b87a2349985230c08616fa8a34ffde934c8 (patch) | |
tree | fe3eaa86daee5df071c4dfbc1072d89fd86ff37d /src/test | |
parent | 32e33a7979a10e9fcf2c9b32703838cec1daf674 (diff) |
Use SASLprep to normalize passwords for SCRAM authentication.
An important step of SASLprep normalization, is to convert the string to
Unicode normalization form NFKC. Unicode normalization requires a fairly
large table of character decompositions, which is generated from data
published by the Unicode consortium. The script to generate the table is
put in src/common/unicode, as well test code for the normalization.
A pre-generated version of the tables is included in src/include/common,
so you don't need the code in src/common/unicode to build PostgreSQL, only
if you wish to modify the normalization tables.
The SASLprep implementation depends on the UTF-8 functions from
src/backend/utils/mb/wchar.c. So to use it, you must also compile and link
that. That doesn't change anything for the current users of these
functions, the backend and libpq, as they both already link with wchar.o.
It would be good to move those functions into a separate file in
src/commmon, but I'll leave that for another day.
No documentation changes included, because there is no details on the
SCRAM mechanism in the docs anyway. An overview on that in the protocol
specification would probably be good, even though SCRAM is documented in
detail in RFC5802. I'll write that as a separate patch. An important thing
to mention there is that we apply SASLprep even on invalid UTF-8 strings,
to support other encodings.
Patch by Michael Paquier and me.
Discussion: https://www.postgresql.org/message-id/CAB7nPqSByyEmAVLtEf1KxTRh=PWNKiWKEKQR=e1yGehz=wbymQ@mail.gmail.com
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/authentication/t/002_saslprep.pl | 98 |
1 files changed, 98 insertions, 0 deletions
diff --git a/src/test/authentication/t/002_saslprep.pl b/src/test/authentication/t/002_saslprep.pl new file mode 100644 index 00000000000..0c18528e7af --- /dev/null +++ b/src/test/authentication/t/002_saslprep.pl @@ -0,0 +1,98 @@ +# Test password normalization in SCRAM. +# +# This test cannot run on Windows as Postgres cannot be set up with Unix +# sockets and needs to go through SSPI. + +use strict; +use warnings; +use PostgresNode; +use TestLib; +use Test::More tests => 12; + +# Delete pg_hba.conf from the given node, add a new entry to it +# and then execute a reload to refresh it. +sub reset_pg_hba +{ + my $node = shift; + my $hba_method = shift; + + unlink($node->data_dir . '/pg_hba.conf'); + $node->append_conf('pg_hba.conf', "local all all $hba_method"); + $node->reload; +} + +# Test access for a single role, useful to wrap all tests into one. +sub test_login +{ + my $node = shift; + my $role = shift; + my $password = shift; + my $expected_res = shift; + my $status_string = 'failed'; + + $status_string = 'success' if ($expected_res eq 0); + + $ENV{"PGPASSWORD"} = $password; + my $res = $node->psql('postgres', 'SELECT 1', extra_params => ['-U', $role]); + is($res, $expected_res, + "authentication $status_string for role $role with password $password"); +} + +SKIP: +{ + skip "authentication tests cannot run on Windows", 12 if ($windows_os); + + # Initialize master node + my $node = get_new_node('master'); + $node->init; + $node->start; + + # These tests are based on the example strings from RFC4013.txt, + # Section "3. Examples": + # + # # Input Output Comments + # - ----- ------ -------- + # 1 I<U+00AD>X IX SOFT HYPHEN mapped to nothing + # 2 user user no transformation + # 3 USER USER case preserved, will not match #2 + # 4 <U+00AA> a output is NFKC, input in ISO 8859-1 + # 5 <U+2168> IX output is NFKC, will match #1 + # 6 <U+0007> Error - prohibited character + # 7 <U+0627><U+0031> Error - bidirectional check + + # Create test roles. + $node->safe_psql('postgres', +"SET password_encryption='scram'; + SET client_encoding='utf8'; + CREATE ROLE saslpreptest1_role LOGIN PASSWORD 'IX'; + CREATE ROLE saslpreptest4a_role LOGIN PASSWORD 'a'; + CREATE ROLE saslpreptest4b_role LOGIN PASSWORD E'\\xc2\\xaa'; + CREATE ROLE saslpreptest6_role LOGIN PASSWORD E'foo\\x07bar'; + CREATE ROLE saslpreptest7_role LOGIN PASSWORD E'foo\\u0627\\u0031bar'; +"); + + # Require password from now on. + reset_pg_hba($node, 'scram'); + + # Check that #1 and #5 are treated the same as just 'IX' + test_login($node, 'saslpreptest1_role', "I\xc2\xadX", 0); + test_login($node, 'saslpreptest1_role', "\xe2\x85\xa8", 0); + + # but different from lower case 'ix' + test_login($node, 'saslpreptest1_role', "ix", 2); + + # Check #4 + test_login($node, 'saslpreptest4a_role', "a", 0); + test_login($node, 'saslpreptest4a_role', "\xc2\xaa", 0); + test_login($node, 'saslpreptest4b_role', "a", 0); + test_login($node, 'saslpreptest4b_role', "\xc2\xaa", 0); + + # Check #6 and #7 - In PostgreSQL, contrary to the spec, if the password + # contains prohibited characters, we use it as is, without normalization. + test_login($node, 'saslpreptest6_role', "foo\x07bar", 0); + test_login($node, 'saslpreptest6_role', "foobar", 2); + + test_login($node, 'saslpreptest7_role', "foo\xd8\xa71bar", 0); + test_login($node, 'saslpreptest7_role', "foo1\xd8\xa7bar", 2); + test_login($node, 'saslpreptest7_role', "foobar", 2); +} |