mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
1. Added Master Password to increase the security of saved passwords. Fixes #4184
2. In server(web) mode, update all the saved server credentials when user password is changed. Fixes #3377
This commit is contained in:
committed by
Akshay Joshi
parent
6f0eafb223
commit
dfa892d2a2
@@ -26,6 +26,8 @@ import config
|
||||
from config import PG_DEFAULT_DRIVER
|
||||
from pgadmin.model import db, Server, ServerGroup, User
|
||||
from pgadmin.utils.driver import get_driver
|
||||
from pgadmin.utils.master_password import get_crypt_key
|
||||
from pgadmin.utils.exception import CryptKeyMissing
|
||||
|
||||
|
||||
def has_any(data, keys):
|
||||
@@ -117,9 +119,16 @@ class ServerModule(sg.ServerGroupPluginModule):
|
||||
driver = get_driver(PG_DEFAULT_DRIVER)
|
||||
|
||||
for server in servers:
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
connected = False
|
||||
manager = None
|
||||
try:
|
||||
manager = driver.connection_manager(server.id)
|
||||
conn = manager.connection()
|
||||
connected = conn.connected()
|
||||
except CryptKeyMissing:
|
||||
# show the nodes at least even if not able to connect.
|
||||
pass
|
||||
|
||||
in_recovery = None
|
||||
wal_paused = None
|
||||
|
||||
@@ -723,6 +732,11 @@ class ServerNode(PGChildNodeView):
|
||||
request.data, encoding='utf-8'
|
||||
)
|
||||
|
||||
# Get enc key
|
||||
crypt_key_present, crypt_key = get_crypt_key()
|
||||
if not crypt_key_present:
|
||||
raise CryptKeyMissing
|
||||
|
||||
# Some fields can be provided with service file so they are optional
|
||||
if 'service' in data and not data['service']:
|
||||
required_args.extend([
|
||||
@@ -807,7 +821,7 @@ class ServerNode(PGChildNodeView):
|
||||
# login with password
|
||||
have_password = True
|
||||
password = data['password']
|
||||
password = encrypt(password, current_user.password)
|
||||
password = encrypt(password, crypt_key)
|
||||
elif 'passfile' in data and data["passfile"] != '':
|
||||
passfile = data['passfile']
|
||||
setattr(server, 'passfile', passfile)
|
||||
@@ -817,7 +831,7 @@ class ServerNode(PGChildNodeView):
|
||||
have_tunnel_password = True
|
||||
tunnel_password = data['tunnel_password']
|
||||
tunnel_password = \
|
||||
encrypt(tunnel_password, current_user.password)
|
||||
encrypt(tunnel_password, crypt_key)
|
||||
|
||||
status, errmsg = conn.connect(
|
||||
password=password,
|
||||
@@ -998,6 +1012,11 @@ class ServerNode(PGChildNodeView):
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
|
||||
# Get enc key
|
||||
crypt_key_present, crypt_key = get_crypt_key()
|
||||
if not crypt_key_present:
|
||||
raise CryptKeyMissing
|
||||
|
||||
# If server using SSH Tunnel
|
||||
if server.use_ssh_tunnel:
|
||||
if 'tunnel_password' not in data:
|
||||
@@ -1014,12 +1033,12 @@ class ServerNode(PGChildNodeView):
|
||||
# Encrypt the password before saving with user's login
|
||||
# password key.
|
||||
try:
|
||||
tunnel_password = encrypt(tunnel_password, user.password) \
|
||||
tunnel_password = encrypt(tunnel_password, crypt_key) \
|
||||
if tunnel_password is not None else \
|
||||
server.tunnel_password
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=e.message)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
if 'password' not in data:
|
||||
conn_passwd = getattr(conn, 'password', None)
|
||||
@@ -1038,11 +1057,11 @@ class ServerNode(PGChildNodeView):
|
||||
# Encrypt the password before saving with user's login
|
||||
# password key.
|
||||
try:
|
||||
password = encrypt(password, user.password) \
|
||||
password = encrypt(password, crypt_key) \
|
||||
if password is not None else server.password
|
||||
except Exception as e:
|
||||
current_app.logger.exception(e)
|
||||
return internal_server_error(errormsg=e.message)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
# Check do we need to prompt for the database server or ssh tunnel
|
||||
# password or both. Return the password template in case password is
|
||||
@@ -1235,6 +1254,7 @@ class ServerNode(PGChildNodeView):
|
||||
"""
|
||||
try:
|
||||
data = json.loads(request.form['data'], encoding='utf-8')
|
||||
crypt_key = get_crypt_key()[1]
|
||||
|
||||
# Fetch Server Details
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
@@ -1292,7 +1312,7 @@ class ServerNode(PGChildNodeView):
|
||||
|
||||
# Check against old password only if no pgpass file
|
||||
if not is_passfile:
|
||||
decrypted_password = decrypt(manager.password, user.password)
|
||||
decrypted_password = decrypt(manager.password, crypt_key)
|
||||
|
||||
if isinstance(decrypted_password, bytes):
|
||||
decrypted_password = decrypted_password.decode()
|
||||
@@ -1328,7 +1348,7 @@ class ServerNode(PGChildNodeView):
|
||||
|
||||
# Store password in sqlite only if no pgpass file
|
||||
if not is_passfile:
|
||||
password = encrypt(data['newPassword'], user.password)
|
||||
password = encrypt(data['newPassword'], crypt_key)
|
||||
# Check if old password was stored in pgadmin4 sqlite database.
|
||||
# If yes then update that password.
|
||||
if server.password is not None and config.ALLOW_SAVE_PASSWORD:
|
||||
@@ -1472,6 +1492,7 @@ class ServerNode(PGChildNodeView):
|
||||
|
||||
def get_response_for_password(self, server, status, prompt_password=False,
|
||||
prompt_tunnel_password=False, errmsg=None):
|
||||
|
||||
if server.use_ssh_tunnel:
|
||||
return make_json_response(
|
||||
success=0,
|
||||
@@ -1498,7 +1519,7 @@ class ServerNode(PGChildNodeView):
|
||||
server_label=server.name,
|
||||
username=server.username,
|
||||
errmsg=errmsg,
|
||||
_=gettext
|
||||
_=gettext,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user