Postgres: 'role does not exist' using dblink, but it does - postgresql

So this is super strange. I'm trying to do a simple select using dblink as such:
SELECT * FROM dblink('dbname=my_db_name, user=my_user,
password=password, hostaddr=127.0.0.1', 'SELECT action, object,
created_at, id FROM my_table') AS de(ACTION VARCHAR, OBJECT VARCHAR,
created_at TIMESTAMP, id INT)
And I immediately am getting an error message of:
PG::SqlclientUnableToEstablishSqlconnection: ERROR: could not
establish connection DETAIL: FATAL: role "my_user," does not exist
But if I connect to psql locally and print out the list of users using \du you'll see it's listed:
List of roles
Role name | Attributes | Member of
---------------+------------------------------------------------+-----------
MyName | Superuser, Create role, Create DB, Replication | {}
my_user | Create DB | {}
I'm really at a loss as to how to fix this, googling hasn't helped me much at all either. Any thoughts as to why it's giving me this error message?
When I connect using my superuser account I don't need to specify a password and the dblink runs fine, so I'm quite confused. Here is by pg_hba.conf:
local all all trust
local all all md5
host all all 192.168.33.1/24 trust
# IPv4 local connections:
host all all 127.0.0.1/32 trust
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 trust
host all all ::1/128 md5
Thanks in advance!

Try removing the commas from the connection string.
SELECT * FROM dblink('dbname=my_db_name user=my_user password=password hostaddr=127.0.0.1', 'SELECT action, object, created_at, id FROM my_table') AS de(ACTION VARCHAR, OBJECT VARCHAR, created_at TIMESTAMP, id INT)
This should fix the issue where it tries to authenticate as my_user,.
Secondly, your pg_hba configuration is an issue. Because you have the 'trust' method first, it will be used. Either try placing the 'md5' entries before the 'trust' entries, or remove the 'trust' entries. (Set a password for your own postgres account first, so that you can still authenticate once passwords are required.)
The reason for the second issue is that if 'trust' is enabled for the hostname you're connected from, it will authenticate the user without requiring a password, and since non-superusers cannot connect without a password, it will fail to connect.
Finally, the user running the query that calls dblink must be authenticated using a password. So if you're using 'trust' authentication to connect to the database, then running dblink, you will also get an error. To fix this, change to md5 authentication and connect using a password.

You're using commas in the connection string. The error message says:
FATAL: role "my_user," does not exist
Which indicates the exact error in this case. This is not the way do do it. You should only space separate the items in the connection string like:
SELECT * FROM dblink('dbname=my_db_name user=my_user password=password hostaddr=127.0.0.1', 'SELECT action, object, created_at, id FROM my_table') AS de(ACTION VARCHAR, OBJECT VARCHAR, created_at TIMESTAMP, id INT)

Related

Permission issues accessing tables in PostgreSQL database

I have a PostgreSQL database. I have a library that accesses said database. I have test code to test that library.
Previously everything worked fine, but this morning my test logs have errors like this:
ERROR: permission denied for table configuration
In an attempt to narrow down the problem I created a script to recreate the database and all permissions from scratch. It is based upon countless similar scripts I have used previously. It starts like this:
DROP DATABASE boards_db;
DROP OWNED BY test_user;
DROP USER test_user;
CREATE USER test_user WITH PASSWORD 'testing';
CREATE DATABASE boards_db WITH ENCODING='UTF8' OWNER = test_user;
\c boards_db
GRANT ALL PRIVILEGES ON DATABASE boards_db to test_user;
ALTER DEFAULT PRIVILEGES GRANT ALL ON TABLES TO test_user;
ALTER DEFAULT PRIVILEGES GRANT ALL ON SEQUENCES TO test_user;
CREATE TABLE IF NOT EXISTS sessions (
user_id INTEGER PRIMARY KEY,
admin BOOLEAN NOT NULL,
session_id TEXT
);
In trying to debug this issue I foolishly meddled with the pg_hba.conf file. It now looks as below, and I can now log on as the test user (or other users) without specifying a hostname, thanks to the line "local all all md5" that I added
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all md5
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
# Allow replication connections from localhost, by a user with the
# replication privilege.
local replication all peer
host replication all 127.0.0.1/32 md5
host replication all ::1/128 md5
However, I STILL cannot actually do anything with any of the tables in the database.
$ psql -W -U test_user -d boards_db
Password:
psql (12.9 (Ubuntu 12.9-0ubuntu0.20.04.1))
Type "help" for help.
boards_db=> select * from sessions;
ERROR: permission denied for table sessions
The trick of setting default privileges before creating all the tables etc. has worked before in a multitude of database. Why doesn't it work here? Why can test_user not access the tables?

Authentication error after using stored procedure for creating new db user

I'm having this problem in postgres and I cannot find my way out.
For our key-users to create user accounts in our postgres database (Ubuntu 18.04.6 LTS (GNU/Linux 5.4.0-1074-azure x86_64)), I created a stored procedure that creates a user with a password.
This is the code for the stored procedure:
CREATE OR REPLACE PROCEDURE geodata_create_user(
username CHARACTER VARYING,
password CHARACTER VARYING
)
LANGUAGE PLPGSQL SECURITY DEFINER
AS
$$
DECLARE
user_to_create CHARACTER VARYING;
BEGIN
-- Check name and create user
IF (username like 'user%') THEN
user_to_create := username;
ELSE
user_to_create := 'user_' || username;
END IF;
PERFORM create_role_if_not_exists (user_to_create);
-- Set password and assign geodata_user role to user
EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD ''%I''', user_to_create, password);
EXECUTE format('GRANT another_role TO %I', user_to_create);
end;
$$;
GRANT ALL ON PROCEDURE geodata_create_user TO some_group_role;
If I test it (we have a dev cluster and an acc/prod cluster), it works fine.
The problem is that if one of the key-users creates a new user using this procedure, the user is created yet cannot login using the supplied password.
Following suggestion in pgAdmin and terminal: FATAL: password authentication failed for user to login using peer logon, I tried logging in on psql using the psql -U newuser command it tells me FATAL: Peer authentication failed for user
Then, following suggestion in psql: FATAL: Peer authentication failed for user "dev" logging on the psql using psql -U newuser -d mydbname -h 12.345.678.910 and it replies (after feeding the password created for the user):
Password for user newuser:
psql: error: connection to server at "12.345.678.910", port 8765 failed: could not initiate GSSAPI security context: Unspecified GSS failure. Minor code may provide more information: Server postgres/12.345.678.910#CFSERVICES.COM not found in Kerberos database
connection to server at "12.345.678.910", port 8765 failed: FATAL: password authentication failed for user "newuser"
connection to server at "12.345.678.910", port 8765 failed: FATAL: no pg_hba.conf entry for host "12.345.678.910", user "newuser", database "mydbname", SSL off
I do have a little database experience, however, this kind of stuff is way out of my league. Any one any idea on what goes wrong here? Is there an obvious error in my script? Or might it be a security issue (we use certificates to access the database server when approaching the database server through psql directly, yet usually we set up connections to the database using DBeaver where there is no need to use SSL or SSH Tunnel or certificates or so).
Hope someone can help me out on this.
Regards, Helmoet.
Your format() function is wrong, because a password is not a SQL identifier (which is what %I is for). This will result in it being escaped incorrectly at least in some cases. For example, if the password has a space or a dash in it (or other characters I don't know off the top of my head), this will cause the whole password to be surrounded by literal double quotes. Then the password would work, but you need to specify the double quotes, which is surely not what you would be expecting.
So it should instead look like this, using %L not %I:
EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD %L', user_to_create, password);
Your original code would work for passwords that didn't have any of the special symbols in them, so maybe that is why it tested fine.

MD5 Hashed passwords: where does it get hashed?

I am connecting to a local PostgreSQL database with an md5 hashed password.
It works but I want to understand what is happening under the hood.
Does pq hash the password before it is sent over the network? How would it know whether to hash it or leave it as plain text? The server (in pg_hba.conf) is the one who specifies the authentication method of how the password is sent over the connection.
Is there a handshake that goes on between pq and psql before the connection string with the password is sent over?
user := "foo_user"
password := "test"
dbname := "bar"
connectionString := fmt.Sprintf(
"user=%s password=%s dbname=%s",
user,
password,
dbname)
db, err := sql.Open("postgres", connectionString)
The user was created with a password via:
ALTER USER foo_user WITH PASSWORD 'test';
And verified that the password is being stored as a hash:
postgres=# SELECT rolname, rolpassword from pg_authid;
rolname | rolpassword
-------------------+-------------------------------------
postgres |
pg_signal_backend |
foo_user | md51083525553eab8f4090ada980d2b86e7
(3 rows)
And pg_hba.conf is completely unmodified:
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 md5
# IPv6 local connections:
host all all ::1/128 md5
There are two places where password hashing takes place, and they should not be confused.
When a password is set for a role, it is concatenated with the user name and then hashed. This is the password stored in pg_authid, and that is the actual password used by PostgreSQL. PostgreSQL does not use the password you entered, but a hashed version of it, to keep attackers form stealing your password and then trying it outside of PostgreSQL (in case the same password is used in several places).
So to break into a database, you do not actually need to know the clear text password, the “actual” hashed password is enough.
There are two places where the hashing can take place:
On the server side, if you use
CREATE/ALTER ROLE ... PASSWORD 'mypassword';
This is not so good, because the password is sent over the wire in clear text and it can show up in the database log.
On the client side, if you use
CREATE/ALTER ROLE ... PASSWORD 'hashedpassword';
This is better, and it is what psql uses internally if you use the \password command.
During session authentication, if the authentication method specified for the database and user demands it. The server will then respond to the connection request with a AuthenticationMD5Password message (see the documentation).
The client then hashes the clear text password to obtain the actual password, then hashes it again with a random “salt” provided by the server.
The server hashes the password from pg_authid in the same fashion and compares the result.

PostgreSQL - Create table in schema privilege on Cloud9

I'm using PostgreSQL on Cloude9. I'm trying to run a nodejs program which creates a schema in a database and then creates some tables in the schema. Here is what I'm trying to do and the error I get:
CREATE SCHEMA IF NOT EXISTS salesforce;
CREATE TABLE IF NOT EXISTS salesforce.contact (
id BIGSERIAL,
firstName TEXT,
lastName TEXT,
email TEXT,
mobilePhone TEXT,
leadsource TEXT,
accountid TEXT,
pictureURL__c TEXT,
preference__c TEXT,
size__c TEXT,
loyaltyid__c TEXT,
password__c TEXT,
createddate timestamp
);
Error initializing Postgres tables initialized
{ [Error: permission denied for schema salesforce]
severity: 'ERROR',
code: '42501',
file: 'aclchk.c',
line: '3371',
routine: 'aclcheck_error' }
the PostgreSQL is running under user postgresql, I'm running under user ubuntu, but I granted all privileges on the database to user ubuntu.
I also edited the pg_hba.conf file to:
local all postgres peer
# TYPE DATABASE USER ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all peer
# IPv4 local connections:
host all all 127.0.0.1/32 trust
# IPv6 local connections:
host all all ::1/128 md5
what am I doing wrong?
Thanks,
Nir.
started all from scratch and after creating a role with superuser and login options, it worked fine.

Non-superuser cannot connect if the server does not request a password while using dblink

I want to do some cross database references in my application. Briefly, i have two databases called meta and op. I want to do some select query from meta to a table in op database like below but getting the below error. I tried with password and without password. by the way caixa user is a non-super user and my target server (op db server is having MD5 authentication mode.)
meta=> select * from dblink('dbname=op password=caixa','SELECT op_col from op_table') AS t(op_col varchar);
ERROR: password is required
DETAIL: Non-superuser cannot connect if the server does not request a password.
HINT: Target server's authentication method must be changed.
What the HINT in the above error message suggests? do i need to change the server's auth mode? Without changing the server's auth mode (MD5) can't i run the above query?
From documentation:
Only superusers may use dblink_connect to create
non-password-authenticated connections. If non-superusers need this
capability, use dblink_connect_u instead.
and
dblink_connect_u() is identical to dblink_connect(), except that it
will allow non-superusers to connect using any authentication method.
That means your dblink call is using dblink_connect implicitly. Use dblink_connect_u instead or change your auth method to e.g. md5.
Note that you also need grant execute privilege to caixa role, for example by:
GRANT EXECUTE ON FUNCTION dblink_connect_u(text) TO caixa;
GRANT EXECUTE ON FUNCTION dblink_connect_u(text, text) TO caixa;
Working example (after GRANT):
meta=> SELECT dblink_connect_u('conn1', 'dbname=op');
meta=> SELECT * FROM dblink('conn1','SELECT op_col from op_table')
AS t(op_col varchar);
op_col
--------
aaa
bbb
ccc
(3 rows)
meta=> SELECT dblink_disconnect('conn1');
EDIT:
Sorry for slightly misleading answer. Of course you don't need dblink_connect_u for md5 authenticated
connection. There is one possibility I see. PostgreSQL has two different connection types: host and local.
Running:
psql -h localhost ..
incorporates host connection, but
dblink_connect('mycon','dbname=vchitta_op user=caixa password=caixa');
uses local type, so if you have non-password method for local connection (for example ident method or trust), then it returns
ERROR: password is required
DETAIL: Non-superuser cannot connect if the server does not request a password.
HINT: Target server's authentication method must be changed.
Check
dblink_connect('mycon','hostaddr=127.0.0.1 dbname=vchitta_op user=caixa password=caixa')
for host connection. For clarity if possible please post your pg_hba.conf.
I also checked what about CONNECT privilege on vchitta_op DB, but error message is different:
REVOKE CONNECT ON DATABASE vchitta_op FROM PUBLIC;
REVOKE CONNECT ON DATABASE vchitta_op FROM caixa;
SELECT dblink_connect('mycon','dbname=vchitta_op user=caixa password=caixa');
ERROR: could not establish connection
DETAIL: FATAL: permission denied for database "vchitta_op"
DETAIL: User does not have CONNECT privilege.
There's a workaround that did the trick for me. Non-superusers can execute functions with privileges of a superuser if "SECURITY DEFINER" option is set.
( http://www.postgresql.org/docs/9.1/static/sql-createfunction.html )
That means you can create a function (with superuser owner and SECURITY DEFINER option) that does cross-database manipulation (using dblink() without password) and execute it under non-superuser
I have a similar but a different issue. I have two servers with identical postgres.conf and pg_hba.conf. However one on version 9.2.3 and one on 9.2.4
9.2.3
pg_hba.conf has
local all dblinkuser trust
then I connect to database using any ordinary user
theater_map=# select dblink_connect('dbname=TheaterDB user=dblinkuser password=dbl123');
dblink_connect
----------------
OK
(1 row)
success in connection.
9.2.4
my pg_hba.conf has the same entry as above
theater_map=> select dblink_connect('dbname=TheaterDB user=dblinkuser password=dbl123');
ERROR: password is required
DETAIL: Non-superuser cannot connect if the server does not request a password.
HINT: Target server's authentication method must be changed.
NOW
I change my pg_hba.conf on 9.2.4 as below
local all dblinkuser md5
and restart postgres
theater_map=> select dblink_connect('dbname=TheaterDB user=dblinkuser password=dbl123');
dblink_connect
----------------
OK
(1 row)
I Checked the change log between versions 9.2.3 and 9.2.4 but could not find any details.
note: changing auth method from trust to md5 on 9.2.3 does not make any difference and still works.
I found this question googling for same error message, though I use fdw extension rather than db_link. Following steps helped to fix my problem:
find user has no password and set it on - alter user myuser with password 'mypassword'
find authentication method is trust and set it to md5 - vim /var/lib/postgresql/data_/pg_hba.conf
reload pg_hba.conf - SELECT pg_reload_conf(); from psql (log out and log in to verify password is required)
(optionally try access from remote machine, db browser etc.)
setup foreign server and its user mapping - CREATE USER MAPPING FOR CURRENT_USER SERVER myserver OPTIONS (user 'myuser', password 'mypassword');
PostgreSQL 11.10
SELECT ext.column1 from
dblink('hostaddr=192.192.192.192 dbname=yourDbname user=yourUsername password=yourpass',
'select a."column1" from "Table1" a where a."column2"=2')
as ext(column1 text)