mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Ensure password changes are successful if authenticating using a pgpass file. Fixes #2720
This commit is contained in:
committed by
Dave Page
parent
55254a649f
commit
4246a3b22f
@@ -240,7 +240,8 @@ class ServerNode(PGChildNodeView):
|
||||
'change_password': [{'post': 'change_password'}],
|
||||
'wal_replay': [{
|
||||
'delete': 'pause_wal_replay', 'put': 'resume_wal_replay'
|
||||
}]
|
||||
}],
|
||||
'check_pgpass': [{'get': 'check_pgpass'}]
|
||||
})
|
||||
EXP_IP4 = "^\s*((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."\
|
||||
"(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\."\
|
||||
@@ -1118,12 +1119,43 @@ class ServerNode(PGChildNodeView):
|
||||
"""
|
||||
try:
|
||||
data = json.loads(request.form['data'], encoding='utf-8')
|
||||
if data and ('password' not in data or
|
||||
data['password'] == '' or
|
||||
'newPassword' not in data or
|
||||
data['newPassword'] == '' or
|
||||
'confirmPassword' not in data or
|
||||
data['confirmPassword'] == ''):
|
||||
|
||||
# Fetch Server Details
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
if server is None:
|
||||
return bad_request(gettext("Server not found."))
|
||||
|
||||
# Fetch User Details.
|
||||
user = User.query.filter_by(id=current_user.id).first()
|
||||
if user is None:
|
||||
return unauthorized(gettext("Unauthorized request."))
|
||||
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
is_passfile = False
|
||||
|
||||
# If there is no password found for the server
|
||||
# then check for pgpass file
|
||||
if not server.password and not manager.password:
|
||||
if server.passfile and manager.passfile and \
|
||||
server.passfile == manager.passfile:
|
||||
is_passfile = True
|
||||
|
||||
# Check for password only if there is no pgpass file used
|
||||
if not is_passfile:
|
||||
if data and ('password' not in data or data['password'] == ''):
|
||||
return make_json_response(
|
||||
status=400,
|
||||
success=0,
|
||||
errormsg=gettext(
|
||||
"Could not find the required parameter(s)."
|
||||
)
|
||||
)
|
||||
|
||||
if data and ('newPassword' not in data or
|
||||
data['newPassword'] == '' or
|
||||
'confirmPassword' not in data or
|
||||
data['confirmPassword'] == ''):
|
||||
return make_json_response(
|
||||
status=400,
|
||||
success=0,
|
||||
@@ -1141,29 +1173,18 @@ class ServerNode(PGChildNodeView):
|
||||
)
|
||||
)
|
||||
|
||||
# Fetch Server Details
|
||||
server = Server.query.filter_by(id=sid).first()
|
||||
if server is None:
|
||||
return bad_request(gettext("Server not found."))
|
||||
# Check against old password only if no pgpass file
|
||||
if not is_passfile:
|
||||
decrypted_password = decrypt(manager.password, user.password)
|
||||
|
||||
# Fetch User Details.
|
||||
user = User.query.filter_by(id=current_user.id).first()
|
||||
if user is None:
|
||||
return unauthorized(gettext("Unauthorized request."))
|
||||
if isinstance(decrypted_password, bytes):
|
||||
decrypted_password = decrypted_password.decode()
|
||||
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
password = data['password']
|
||||
|
||||
decrypted_password = decrypt(manager.password, user.password)
|
||||
|
||||
if isinstance(decrypted_password, bytes):
|
||||
decrypted_password = decrypted_password.decode()
|
||||
|
||||
password = data['password']
|
||||
|
||||
# Validate old password before setting new.
|
||||
if password != decrypted_password:
|
||||
return unauthorized(gettext("Incorrect password."))
|
||||
# Validate old password before setting new.
|
||||
if password != decrypted_password:
|
||||
return unauthorized(gettext("Incorrect password."))
|
||||
|
||||
# Hash new password before saving it.
|
||||
password = pqencryptpassword(data['newPassword'], manager.user)
|
||||
@@ -1178,15 +1199,17 @@ class ServerNode(PGChildNodeView):
|
||||
if not status:
|
||||
return internal_server_error(errormsg=res)
|
||||
|
||||
password = encrypt(data['newPassword'], user.password)
|
||||
# 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:
|
||||
setattr(server, 'password', password)
|
||||
db.session.commit()
|
||||
# Also update password in connection manager.
|
||||
manager.password = password
|
||||
manager.update_session()
|
||||
# Store password in sqlite only if no pgpass file
|
||||
if not is_passfile:
|
||||
password = encrypt(data['newPassword'], user.password)
|
||||
# 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:
|
||||
setattr(server, 'password', password)
|
||||
db.session.commit()
|
||||
# Also update password in connection manager.
|
||||
manager.password = password
|
||||
manager.update_session()
|
||||
|
||||
return make_json_response(
|
||||
status=200,
|
||||
@@ -1277,5 +1300,46 @@ class ServerNode(PGChildNodeView):
|
||||
"""
|
||||
return self.wal_replay(sid, True)
|
||||
|
||||
def check_pgpass(self, gid, sid):
|
||||
"""
|
||||
This function is used to check whether server is connected
|
||||
using pgpass file or not
|
||||
|
||||
Args:
|
||||
gid: Group id
|
||||
sid: Server id
|
||||
"""
|
||||
is_pgpass = False
|
||||
server = Server.query.filter_by(
|
||||
user_id=current_user.id, id=sid
|
||||
).first()
|
||||
|
||||
if server is None:
|
||||
return make_json_response(
|
||||
success=0,
|
||||
errormsg=gettext("Could not find the required server.")
|
||||
)
|
||||
|
||||
try:
|
||||
manager = get_driver(PG_DEFAULT_DRIVER).connection_manager(sid)
|
||||
conn = manager.connection()
|
||||
if not conn.connected():
|
||||
return gone(
|
||||
errormsg=_('Please connect the server.')
|
||||
)
|
||||
|
||||
if not server.password or not manager.password:
|
||||
if server.passfile and manager.passfile and \
|
||||
server.passfile == manager.passfile:
|
||||
is_pgpass = True
|
||||
return make_json_response(
|
||||
success=1,
|
||||
data=dict({'is_pgpass': is_pgpass}),
|
||||
)
|
||||
except Exception as e:
|
||||
current_app.logger.error(
|
||||
'Cannot able to fetch pgpass status'
|
||||
)
|
||||
return internal_server_error(errormsg=str(e))
|
||||
|
||||
ServerNode.register_node_view(blueprint)
|
||||
|
||||
@@ -365,7 +365,9 @@ define('pgadmin.node.server', [
|
||||
i = input.item || t.selected(),
|
||||
d = i && i.length == 1 ? t.itemData(i) : undefined,
|
||||
node = d && pgBrowser.Nodes[d._type],
|
||||
url = obj.generate_url(i, 'change_password', d, true);
|
||||
url = obj.generate_url(i, 'change_password', d, true),
|
||||
is_pgpass_file_used = false,
|
||||
check_pgpass_url = obj.generate_url(i, 'check_pgpass', d, true);
|
||||
|
||||
if (!d)
|
||||
return false;
|
||||
@@ -387,8 +389,8 @@ define('pgadmin.node.server', [
|
||||
type: 'text', disabled: true, control: 'input'
|
||||
},{
|
||||
name: 'password', label: gettext('Current Password'),
|
||||
type: 'password', disabled: false, control: 'input',
|
||||
required: true
|
||||
type: 'password', disabled: function() { return is_pgpass_file_used },
|
||||
control: 'input', required: true
|
||||
},{
|
||||
name: 'newPassword', label: gettext('New Password'),
|
||||
type: 'password', disabled: false, control: 'input',
|
||||
@@ -410,9 +412,11 @@ define('pgadmin.node.server', [
|
||||
setup:function() {
|
||||
return {
|
||||
buttons: [{
|
||||
text: gettext('Ok'), key: 13, className: 'btn btn-primary', attrs:{name:'submit'}
|
||||
},{
|
||||
text: gettext('Cancel'), key: 27, className: 'btn btn-danger', attrs:{name:'cancel'}
|
||||
text: gettext('Ok'), key: 13, className: 'btn btn-primary',
|
||||
attrs:{name:'submit'}
|
||||
},{
|
||||
text: gettext('Cancel'), key: 27, className: 'btn btn-danger',
|
||||
attrs:{name:'cancel'}
|
||||
}],
|
||||
// Set options for dialog
|
||||
options: {
|
||||
@@ -436,15 +440,18 @@ define('pgadmin.node.server', [
|
||||
},
|
||||
prepare: function() {
|
||||
var self = this;
|
||||
// Disable Backup button until user provides Filename
|
||||
// Disable Ok button until user provides input
|
||||
this.__internal.buttons[0].element.disabled = true;
|
||||
var $container = $("<div class='change_password'></div>"),
|
||||
newpasswordmodel = new newPasswordModel({'user_name': self.user_name});
|
||||
|
||||
var view = this.view = new Backform.Form({
|
||||
el: $container,
|
||||
model: newpasswordmodel,
|
||||
fields: passwordChangeFields});
|
||||
var $container = $("<div class='change_password'></div>"),
|
||||
newpasswordmodel = new newPasswordModel(
|
||||
{'user_name': self.user_name}
|
||||
),
|
||||
view = this.view = new Backform.Form({
|
||||
el: $container,
|
||||
model: newpasswordmodel,
|
||||
fields: passwordChangeFields
|
||||
});
|
||||
|
||||
view.render();
|
||||
|
||||
@@ -457,7 +464,9 @@ define('pgadmin.node.server', [
|
||||
newPassword = this.get('newPassword'),
|
||||
confirmPassword = this.get('confirmPassword');
|
||||
|
||||
if (_.isUndefined(password) || _.isNull(password) || password == '' ||
|
||||
// Only check password field if pgpass file is not available
|
||||
if ((!is_pgpass_file_used &&
|
||||
(_.isUndefined(password) || _.isNull(password) || password == '')) ||
|
||||
_.isUndefined(newPassword) || _.isNull(newPassword) || newPassword == '' ||
|
||||
_.isUndefined(confirmPassword) || _.isNull(confirmPassword) || confirmPassword == '') {
|
||||
self.__internal.buttons[0].element.disabled = true;
|
||||
@@ -488,6 +497,16 @@ define('pgadmin.node.server', [
|
||||
data:{'data': JSON.stringify(args) },
|
||||
success: function(res) {
|
||||
if (res.success) {
|
||||
// Notify user to update pgpass file
|
||||
if(is_pgpass_file_used) {
|
||||
alertify.alert(
|
||||
gettext("Change Password"),
|
||||
gettext("Please make sure to disconnect the server"
|
||||
+ " and update the new password in the pgpass file"
|
||||
+ " before performing any other operation")
|
||||
);
|
||||
}
|
||||
|
||||
alertify.success(res.info);
|
||||
self.close();
|
||||
} else {
|
||||
@@ -509,7 +528,26 @@ define('pgadmin.node.server', [
|
||||
});
|
||||
}
|
||||
|
||||
alertify.changeServerPassword(d).resizeTo('40%','52%');
|
||||
// Call to check if server is using pgpass file or not
|
||||
$.ajax({
|
||||
url: check_pgpass_url,
|
||||
method:'GET',
|
||||
success: function(res) {
|
||||
if (res.success && res.data.is_pgpass) {
|
||||
is_pgpass_file_used = true;
|
||||
}
|
||||
alertify.changeServerPassword(d).resizeTo('40%','52%');
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
try {
|
||||
var err = $.parseJSON(xhr.responseText);
|
||||
if (err.success == 0) {
|
||||
alertify.error(err.errormsg);
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user