Colon not allowed in a connection string password

Issue #265 resolved
Jan Deelstra
created an issue

According to the documentation only single quotes and backslashes need to be escaped ( https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING ). This seemed to work correctly in older versions (up to 0.18, but in newer versions it doesn't work anymore. It doesn't matter if the password is contained within single quotes or not. Normally I would have worked around this issue by using a different method signature, but I'm reusing these connection strings for db_link connections which makes it pretty inconvenient.

PG 0.18: (correct behaviour)

[1] pry(main)> require 'pg'
=> false
[2] pry(main)> PG::Connection.connect("host=localhost port=5432 dbname=looker user=postgres password=a:a")
PG::ConnectionBad: could not connect to server: Connection refused
    Is the server running on host "localhost" (::1) and accepting
    TCP/IP connections on port 5432?
could not connect to server: Connection refused
    Is the server running on host "localhost" (127.0.0.1) and accepting
    TCP/IP connections on port 5432?
from (pry):2:in `initialize'

PG 0.19 and later:

[1] pry(main)> require 'pg'
=> false
[2] pry(main)> PG::Connection.connect("host=localhost port=5432 dbname=looker user=postgres password=a:a")
URI::InvalidURIError: bad URI(is not URI?): host=localhost port=5432 dbname=looker user=postgres password=a:a
from /Users/jjoos/.rbenv/versions/2.3.3/lib/ruby/2.3.0/uri/rfc3986_parser.rb:67:in `split'

This bug is in /lib/pg/connection.rb:

class PG::Connection
       ...
    def self::parse_connect_args( *args )
                ...
        if args.length == 1
            case args.first
            when URI, URI.regexp
                uri = URI(args.first)
                options.merge!( Hash[URI.decode_www_form( uri.query )] ) if uri.query
            when /=/
                # Option string style
                option_string = args.first.to_s
                        ...

Since:

!!(URI.regexp.match "host=localhost port=5432 dbname=looker user=postgres password='a:a'")
=> true

the code thinks it's dealing with an uri connection string, because it checks if the string contains an uri and not if it is an uri. The regex is missing a start and end anchor, changing the code like this will fix the issue:

            when URI, /\A#{URI::regexp}\z/

since:

!!(/\A#{URI::regexp}\z/.match "host=localhost port=5432 dbname=looker user=postgres password='a:a'")
=> false

Comments (5)

  1. Lars Kanis

    Thank you for reporting this bug and thank you for providing such a detailed description!

    Your fix looks reasonable. Would you mind to open a pull request with your patch? You can alternatively is the github mirror.

  2. Log in to comment