mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2026-11-02 20:30:17 -06:00
libpq looks a service up in the connection service file of the account pgAdmin runs as, and an entry there can hold a password or name a password file or client certificate. In server mode any user could set a server's service, or a 'service' connection parameter, to one of those entries and connect with its credentials. Likewise, a PGPASSWORD or PGSERVICE variable set for that account was used by libpq for every connection that had no value of its own, and passed on to the utilities. In server mode a service may now only be used if it is listed in the new SERVER_MODE_ALLOWED_SERVICES setting, which is empty by default. Creating or updating a server, an ad hoc workspace connection or a servers.json import that names any other service is refused, and connecting to an existing server, or running psql or a utility for it, fails with a message that names the setting. The 'servicefile' connection parameter is refused in server mode, and PGPASSWORD and PGSERVICE are removed from pgAdmin's environment at startup, with a warning. PGSERVICEFILE and PGSYSCONFDIR are kept, since they locate the listed services. Desktop mode is unchanged. The allowlist is checked again on the final connection string, as libpq will parse it, so a service smuggled in through a crafted parameter key is refused however the parameters were serialised. pg_dumpall expands a --database value containing "=" as a connection string, so the maintenance database name of Backup Server and Globals is wrapped in one and a name such as "service=name" no longer selects a service from the service account's service file. client_files_isolated() treats a missing PGADMIN_RUNTIME as "not the desktop runtime", so "setup.py load-servers" no longer fails on any servers.json containing a Service and still enforces the allowlist in server mode. The tests run the real job-creation path of every tool that starts a utility, and check that a service that is not listed is refused before the utility starts, a listed one is exported as PGSERVICE, and a service or servicefile connection parameter, or a database name that looks like a connection string, never selects a service. Compatibility: in server mode, servers that use a service stop connecting until the administrator lists it in SERVER_MODE_ALLOWED_SERVICES, and a PGPASSWORD or PGSERVICE set in the environment pgAdmin starts with is ignored. "setup.py load-servers" now refuses a servers.json whose Service is not in SERVER_MODE_ALLOWED_SERVICES (exit status 1) instead of printing an error and exiting 0. Co-authored-by: Dave Page <dpage@pgadmin.org> Co-authored-by: hiteshjambhale <hitesh.jambhale@enterprisedb.com>
245 lines
9.4 KiB
Python
245 lines
9.4 KiB
Python
##########################################################################
|
||
#
|
||
# pgAdmin 4 - PostgreSQL Tools
|
||
#
|
||
# Copyright (C) 2013 - 2026, The pgAdmin Development Team
|
||
# This software is released under the PostgreSQL Licence
|
||
#
|
||
##########################################################################
|
||
|
||
"""Application wide constants."""
|
||
from flask_babel import gettext
|
||
|
||
# Mimetypes
|
||
MIMETYPE_APP_HTML = 'text/html'
|
||
MIMETYPE_APP_JS = 'application/javascript'
|
||
MIMETYPE_APP_JSON = 'application/json'
|
||
|
||
NO_CACHE_CONTROL = 'no-cache, no-store, must-revalidate'
|
||
|
||
# Preference labels
|
||
PREF_LABEL_KEYBOARD_SHORTCUTS = gettext('Keyboard shortcuts')
|
||
PREF_LABEL_DISPLAY = gettext('Display')
|
||
PREF_LABEL_BREADCRUMBS = gettext('Object Breadcrumbs')
|
||
PREF_LABEL_OPTIONS = gettext('Options')
|
||
PREF_LABEL_EXPLAIN = gettext('Explain')
|
||
PREF_LABEL_EDITOR = gettext('Editor')
|
||
PREF_LABEL_CSV_TXT = gettext('CSV/TXT Output')
|
||
PREF_LABEL_RESULTS_GRID = gettext('Results grid')
|
||
PREF_LABEL_SQL_FORMATTING = gettext('SQL formatting')
|
||
PREF_LABEL_TABS_SETTINGS = gettext('Tab settings')
|
||
PREF_LABEL_REFRESH_RATES = gettext('Refresh rates')
|
||
PREF_LABEL_GRAPH_VISUALISER = gettext('Graph Visualiser')
|
||
PREF_LABEL_GEOMETRY_VIEWER = gettext('Geometry Viewer')
|
||
PREF_LABEL_USER_INTERFACE = gettext('User Interface')
|
||
PREF_LABEL_FILE_DOWNLOADS = gettext('File Downloads')
|
||
PREF_LABEL_AI = gettext('AI')
|
||
|
||
PGADMIN_STRING_SEPARATOR = '_$PGADMIN$_'
|
||
PGADMIN_NODE = 'pgadmin.node.%s'
|
||
UNAUTH_REQ = "Unauthorized request."
|
||
SERVER_CONNECTION_CLOSED = gettext(
|
||
'Not connected to server or connection with the server has been closed.')
|
||
|
||
# Query tool placeholder
|
||
QT_DEFAULT_PLACEHOLDER = '%DATABASE%/%USERNAME%@%SERVER%'
|
||
VW_EDT_DEFAULT_PLACEHOLDER = '%SCHEMA%.%TABLE%/%DATABASE%/%USERNAME%@%SERVER%'
|
||
|
||
# Data Types
|
||
DATATYPE_TIME_WITH_TIMEZONE = 'time with time zone'
|
||
DATATYPE_TIME_WITHOUT_TIMEZONE = 'time without time zone'
|
||
|
||
DATATYPE_TIMESTAMP_WITH_TIMEZONE = 'timestamp with time zone'
|
||
DATATYPE_TIMESTAMP_WITHOUT_TIMEZONE = 'timestamp without time zone'
|
||
|
||
# Error Messages
|
||
ERROR_MSG_TRANS_ID_NOT_FOUND = gettext(
|
||
'Transaction ID not found in the session.')
|
||
|
||
ERROR_MSG_FAIL_TO_PROMOTE_QT = gettext('FAIL TO PROMOTE VIEW/EDIT DATA '
|
||
'TO QUERY TOOL')
|
||
|
||
# Role module constant
|
||
ERROR_FETCHING_ROLE_INFORMATION = gettext(
|
||
'Error fetching role information from the database server.')
|
||
|
||
ERROR_FETCHING_DATA = gettext('Unable to fetch data.')
|
||
|
||
ERROR_SERVER_ID_NOT_SPECIFIED = gettext('Server ID not specified.')
|
||
|
||
# Authentication Sources
|
||
INTERNAL = 'internal'
|
||
LDAP = 'ldap'
|
||
KERBEROS = 'kerberos'
|
||
OAUTH2 = 'oauth2'
|
||
WEBSERVER = 'webserver'
|
||
|
||
SUPPORTED_AUTH_SOURCES = [INTERNAL,
|
||
LDAP,
|
||
KERBEROS,
|
||
OAUTH2,
|
||
WEBSERVER]
|
||
|
||
BINARY_PATHS = {
|
||
"as_bin_paths": [
|
||
{"version": "130000", "next_major_version": "140000",
|
||
"serverType": gettext("EDB Advanced Server 13"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "140000", "next_major_version": "150000",
|
||
"serverType": gettext("EDB Advanced Server 14"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "150000", "next_major_version": "160000",
|
||
"serverType": gettext("EDB Advanced Server 15"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "160000", "next_major_version": "170000",
|
||
"serverType": gettext("EDB Advanced Server 16"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "170000", "next_major_version": "180000",
|
||
"serverType": gettext("EDB Advanced Server 17"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "180000", "next_major_version": "190000",
|
||
"serverType": gettext("EDB Advanced Server 18"), "binaryPath": None,
|
||
"isDefault": False}
|
||
],
|
||
"pg_bin_paths": [
|
||
{"version": "130000", "next_major_version": "140000",
|
||
"serverType": gettext("PostgreSQL 13"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "140000", "next_major_version": "150000",
|
||
"serverType": gettext("PostgreSQL 14"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "150000", "next_major_version": "160000",
|
||
"serverType": gettext("PostgreSQL 15"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "160000", "next_major_version": "170000",
|
||
"serverType": gettext("PostgreSQL 16"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "170000", "next_major_version": "180000",
|
||
"serverType": gettext("PostgreSQL 17"), "binaryPath": None,
|
||
"isDefault": False},
|
||
{"version": "180000", "next_major_version": "190000",
|
||
"serverType": gettext("PostgreSQL 18"), "binaryPath": None,
|
||
"isDefault": False}
|
||
]
|
||
}
|
||
|
||
UTILITIES_ARRAY = ['pg_dumpall', 'pg_dump', 'pg_restore', 'psql']
|
||
|
||
BG_PROCESS_ERROR_MSGS = {
|
||
3221225781: gettext('Unable to find a dll needed by the utility. Ensure '
|
||
'.dll files needed by the utility are in the same '
|
||
'folder as your executable.')
|
||
}
|
||
|
||
ENTER_EMAIL_ADDRESS = "Email address: "
|
||
USER_NOT_FOUND = gettext("The specified user ID (%s) could not be found.")
|
||
DATABASE_LAST_SYSTEM_OID = 16383
|
||
|
||
# Drivers
|
||
PSYCOPG3 = 'psycopg3'
|
||
|
||
# Shared storage
|
||
MY_STORAGE = 'my_storage'
|
||
ACCESS_DENIED_MESSAGE = gettext(
|
||
"Access denied: You’re having limited access. You’re not allowed to "
|
||
"Rename, Delete or Create any files/folders")
|
||
|
||
KEY_RING_SERVICE_NAME = 'pgAdmin4'
|
||
KEY_RING_USER_NAME = 'pgadmin4-master-password'
|
||
KEY_RING_USERNAME_FORMAT = KEY_RING_SERVICE_NAME + '-{0}-{1}'
|
||
KEY_RING_TUNNEL_FORMAT = KEY_RING_SERVICE_NAME + '-tunnel-{0}-{1}'
|
||
KEY_RING_DESKTOP_USER = KEY_RING_SERVICE_NAME + '-desktop-user-{0}'
|
||
|
||
|
||
class MessageType:
|
||
SUCCESS = 'Success',
|
||
ERROR = 'Error',
|
||
INFO = 'Info',
|
||
CLOSE = 'Close',
|
||
WARNING = 'Warning'
|
||
|
||
|
||
DBMS_JOB_SCHEDULER_ID = 999999
|
||
|
||
# String Constants
|
||
IP_ADDRESS_STRING = '{}/{}'
|
||
TWO_PARAM_STRING = '{0}/{1}'
|
||
SERVER_NOT_FOUND = gettext("Could not find the specified server.")
|
||
SSL_MODES = ['prefer', 'require', 'verify-ca', 'verify-full']
|
||
|
||
DATA_TYPE_WITH_LENGTH = [1560, 'bit', 1561, 'bit[]',
|
||
1562, 'varbit', 'bit varying',
|
||
1563, 'varbit[]', 'bit varying[]',
|
||
1042, 'bpchar', 'character',
|
||
1043, 'varchar', 'character varying',
|
||
1014, 'bpchar[]', 'character[]',
|
||
1015, 'varchar[]', 'character varying[]',
|
||
'vector', 'vector[]', 'halfvec', 'halfvec[]',
|
||
'sparsevec', 'sparsevec[]']
|
||
|
||
RESTRICTION_TYPE_DATABASES = 'databases'
|
||
RESTRICTION_TYPE_SQL = 'sql'
|
||
RESTRICT_COMMAND = '\\restrict'
|
||
|
||
# Connection parameters whose value is a file selected through the file
|
||
# manager, and so must be resolved to a complete path before it is handed
|
||
# to libpq. 'sslrootcert' is handled separately, because the literal value
|
||
# 'system' asks libpq for the trusted CA store rather than naming a file.
|
||
CONNECTION_PARAM_FILE_PATHS = [
|
||
'passfile', 'sslcert', 'sslkey', 'sslcrl'
|
||
]
|
||
|
||
# Connection parameters naming a client credential file. When one is not
|
||
# given, libpq falls back to ~/.pgpass, ~/.postgresql/postgresql.crt or
|
||
# ~/.postgresql/postgresql.key in the home directory of the account it runs
|
||
# as, which in server mode is the pgAdmin service account, not the user.
|
||
CONNECTION_PARAM_CREDENTIAL_FILES = ['passfile', 'sslcert', 'sslkey']
|
||
|
||
# Connection parameters whose value is a directory selected through the
|
||
# file manager, resolved in the same way but checked as a directory.
|
||
CONNECTION_PARAM_DIR_PATHS = ['sslcrldir']
|
||
|
||
# Connection parameters that pgAdmin stores as a boolean but libpq expects
|
||
# as an integer.
|
||
CONNECTION_PARAM_BOOLEANS = ['sslcompression', 'sslsni', 'gssdelegation']
|
||
|
||
# Connection parameters that libpq also reads from the environment, mapped
|
||
# to the variable that carries them. Taken from PQconninfoOptions in
|
||
# src/interfaces/libpq/fe-connect.c; parameters that libpq offers no
|
||
# environment variable for (keepalives and friends, sslpassword,
|
||
# sslkeylogfile, fallback_application_name, replication) are absent, and
|
||
# cannot be passed to a utility this way. The service name is not passed
|
||
# from the connection parameters; the server's service is set separately
|
||
# as PGSERVICE.
|
||
CONNECTION_PARAM_ENV_VARS = {
|
||
'application_name': 'PGAPPNAME',
|
||
'channel_binding': 'PGCHANNELBINDING',
|
||
'client_encoding': 'PGCLIENTENCODING',
|
||
'connect_timeout': 'PGCONNECT_TIMEOUT',
|
||
'gssdelegation': 'PGGSSDELEGATION',
|
||
'gssencmode': 'PGGSSENCMODE',
|
||
'gsslib': 'PGGSSLIB',
|
||
'hostaddr': 'PGHOSTADDR',
|
||
'krbsrvname': 'PGKRBSRVNAME',
|
||
'load_balance_hosts': 'PGLOADBALANCEHOSTS',
|
||
'max_protocol_version': 'PGMAXPROTOCOLVERSION',
|
||
'min_protocol_version': 'PGMINPROTOCOLVERSION',
|
||
'options': 'PGOPTIONS',
|
||
'passfile': 'PGPASSFILE',
|
||
'require_auth': 'PGREQUIREAUTH',
|
||
'requirepeer': 'PGREQUIREPEER',
|
||
'ssl_max_protocol_version': 'PGSSLMAXPROTOCOLVERSION',
|
||
'ssl_min_protocol_version': 'PGSSLMINPROTOCOLVERSION',
|
||
'sslcert': 'PGSSLCERT',
|
||
'sslcertmode': 'PGSSLCERTMODE',
|
||
'sslcompression': 'PGSSLCOMPRESSION',
|
||
'sslcrl': 'PGSSLCRL',
|
||
'sslcrldir': 'PGSSLCRLDIR',
|
||
'sslkey': 'PGSSLKEY',
|
||
'sslmode': 'PGSSLMODE',
|
||
'sslnegotiation': 'PGSSLNEGOTIATION',
|
||
'sslrootcert': 'PGSSLROOTCERT',
|
||
'sslsni': 'PGSSLSNI',
|
||
'target_session_attrs': 'PGTARGETSESSIONATTRS',
|
||
}
|