Added support to connect PostgreSQL servers via Kerberos authentication. Fixes #6158

This commit is contained in:
Khushboo Vashi
2021-05-03 16:10:45 +05:30
committed by Akshay Joshi
parent aa9a4c30d3
commit 72f3730c34
28 changed files with 509 additions and 90 deletions

View File

@@ -253,7 +253,8 @@ class ServerModule(sg.ServerGroupPluginModule):
errmsg=errmsg,
user_id=server.user_id,
user_name=server.username,
shared=server.shared
shared=server.shared,
is_kerberos_conn=bool(server.kerberos_conn),
)
@property
@@ -547,7 +548,8 @@ class ServerNode(PGChildNodeView):
if server.tunnel_password is not None else False,
errmsg=errmsg,
user_name=server.username,
shared=server.shared
shared=server.shared,
is_kerberos_conn=bool(server.kerberos_conn)
)
)
@@ -614,7 +616,8 @@ class ServerNode(PGChildNodeView):
if server.tunnel_password is not None else False,
errmsg=errmsg,
shared=server.shared,
user_name=server.username
user_name=server.username,
is_kerberos_conn=bool(server.kerberos_conn)
),
)
@@ -721,7 +724,8 @@ class ServerNode(PGChildNodeView):
'tunnel_username': 'tunnel_username',
'tunnel_authentication': 'tunnel_authentication',
'tunnel_identity_file': 'tunnel_identity_file',
'shared': 'shared'
'shared': 'shared',
'kerberos_conn': 'kerberos_conn',
}
disp_lbl = {
@@ -985,7 +989,8 @@ class ServerNode(PGChildNodeView):
'tunnel_username': tunnel_username,
'tunnel_identity_file': server.tunnel_identity_file
if server.tunnel_identity_file else None,
'tunnel_authentication': tunnel_authentication
'tunnel_authentication': tunnel_authentication,
'kerberos_conn': bool(server.kerberos_conn),
}
return ajax_response(response)
@@ -1072,7 +1077,8 @@ class ServerNode(PGChildNodeView):
tunnel_authentication=data.get('tunnel_authentication', 0),
tunnel_identity_file=data.get('tunnel_identity_file', None),
shared=data.get('shared', None),
passfile=data.get('passfile', None)
passfile=data.get('passfile', None),
kerberos_conn=1 if data.get('kerberos_conn', False) else 0,
)
db.session.add(server)
db.session.commit()
@@ -1154,7 +1160,8 @@ class ServerNode(PGChildNodeView):
else 'pg',
version=manager.version
if manager and manager.version
else None
else None,
is_kerberos_conn=bool(server.kerberos_conn),
)
)
@@ -1348,7 +1355,7 @@ class ServerNode(PGChildNodeView):
except Exception as e:
current_app.logger.exception(e)
return internal_server_error(errormsg=str(e))
if 'password' not in data:
if 'password' not in data and server.kerberos_conn is False:
conn_passwd = getattr(conn, 'password', None)
if conn_passwd is None and not server.save_password and \
server.passfile is None and server.service is None:
@@ -1400,6 +1407,9 @@ class ServerNode(PGChildNodeView):
"Could not connect to server(#{0}) - '{1}'.\nError: {2}"
.format(server.id, server.name, errmsg)
)
if errmsg.find('Ticket expired') != -1:
return internal_server_error(errmsg)
return self.get_response_for_password(server, 401, True,
True, errmsg)
else:
@@ -1467,6 +1477,7 @@ class ServerNode(PGChildNodeView):
'is_password_saved': bool(server.save_password),
'is_tunnel_password_saved': True
if server.tunnel_password is not None else False,
'is_kerberos_conn': bool(server.kerberos_conn),
}
)

View File

@@ -490,6 +490,7 @@ class DatabaseView(PGChildNodeView):
did, errmsg
)
)
return internal_server_error(errmsg)
else:
current_app.logger.info(

View File

@@ -10,9 +10,10 @@
define('pgadmin.node.database', [
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
'sources/utils', 'sources/pgadmin', 'pgadmin.browser.utils',
'pgadmin.alertifyjs', 'pgadmin.backform', 'pgadmin.browser.collection',
'pgadmin.alertifyjs', 'pgadmin.backform',
'pgadmin.authenticate.kerberos', 'pgadmin.browser.collection',
'pgadmin.browser.server.privilege', 'pgadmin.browser.server.variable',
], function(gettext, url_for, $, _, pgadminUtils, pgAdmin, pgBrowser, Alertify, Backform) {
], function(gettext, url_for, $, _, pgadminUtils, pgAdmin, pgBrowser, Alertify, Backform, Kerberos) {
if (!pgBrowser.Nodes['coll-database']) {
pgBrowser.Nodes['coll-database'] =
@@ -556,24 +557,39 @@ define('pgadmin.node.database', [
onFailure = function(
xhr, status, error, _model, _data, _tree, _item, _status
) {
if (!_status) {
tree.setInode(_item);
tree.addIcon(_item, {icon: 'icon-database-not-connected'});
}
Alertify.pgNotifier('error', xhr, error, function(msg) {
setTimeout(function() {
if (msg == 'CRYPTKEY_SET') {
if (xhr.status != 200 && xhr.responseText.search('Ticket expired') !== -1) {
tree.addIcon(_item, {icon: 'icon-server-connecting'});
let fetchTicket = Kerberos.fetch_ticket();
fetchTicket.then(
function() {
connect_to_database(_model, _data, _tree, _item, _wasConnected);
} else {
Alertify.dlgServerPass(
gettext('Connect to database'),
msg, _model, _data, _tree, _item, _status,
onSuccess, onFailure, onCancel
).resizeTo();
},
function(error) {
tree.setInode(_item);
tree.addIcon(_item, {icon: 'icon-database-not-connected'});
Alertify.pgNotifier(error, xhr, gettext('Connect to database.'));
}
}, 100);
});
);
} else {
if (!_status) {
tree.setInode(_item);
tree.addIcon(_item, {icon: 'icon-database-not-connected'});
}
Alertify.pgNotifier('error', xhr, error, function(msg) {
setTimeout(function() {
if (msg == 'CRYPTKEY_SET') {
connect_to_database(_model, _data, _tree, _item, _wasConnected);
} else {
Alertify.dlgServerPass(
gettext('Connect to database'),
msg, _model, _data, _tree, _item, _status,
onSuccess, onFailure, onCancel
).resizeTo();
}
}, 100);
});
}
},
onSuccess = function(
res, model, _data, _tree, _item, _connected
@@ -640,6 +656,7 @@ define('pgadmin.node.database', [
if (xhr.status === 410) {
error = gettext('Error: Object not found - %s.', error);
}
return onFailure(
xhr, status, error, obj, data, tree, item, wasConnected
);

View File

@@ -13,11 +13,13 @@ define('pgadmin.node.server', [
'pgadmin.server.supported_servers', 'pgadmin.user_management.current_user',
'pgadmin.alertifyjs', 'pgadmin.backform',
'sources/browser/server_groups/servers/model_validation',
'pgadmin.authenticate.kerberos',
'pgadmin.browser.constants',
'pgadmin.browser.server.privilege',
], function(
gettext, url_for, $, _, Backbone, pgAdmin, pgBrowser,
supported_servers, current_user, Alertify, Backform,
modelValidation
modelValidation, Kerberos, pgConst,
) {
if (!pgBrowser.Nodes['server']) {
@@ -904,20 +906,36 @@ define('pgadmin.node.server', [
}
},
}),
},{
id: 'kerberos_conn', label: gettext('Kerberos authentication?'), type: 'switch',
group: gettext('Connection'), 'options': {
'onText': gettext('True'), 'offText': gettext('False'), 'size': 'mini',
}, disabled: function() {
if (current_user['current_auth_source'] != pgConst['KERBEROS'])
return true;
return false;
},
},{
id: 'password', label: gettext('Password'), type: 'password', maxlength: null,
group: gettext('Connection'), control: 'input', mode: ['create'], deps: ['connect_now'],
group: gettext('Connection'), control: 'input', mode: ['create'],
deps: ['connect_now', 'kerberos_conn'],
visible: function(model) {
return model.get('connect_now') && model.isNew();
},
disabled: function(model) {
if (model.get('kerberos_conn'))
return true;
return false;
},
},{
id: 'save_password', controlLabel: gettext('Save password?'),
type: 'checkbox', group: gettext('Connection'), mode: ['create'],
deps: ['connect_now'], visible: function(model) {
deps: ['connect_now', 'kerberos_conn'], visible: function(model) {
return model.get('connect_now') && model.isNew();
},
disabled: function() {
if (!current_user.allow_save_password)
disabled: function(model) {
if (!current_user.allow_save_password || model.get('kerberos_conn'))
return true;
return false;
@@ -1279,19 +1297,32 @@ define('pgadmin.node.server', [
}
}
Alertify.pgNotifier('error', xhr, error, function(msg) {
setTimeout(function() {
if (msg == 'CRYPTKEY_SET') {
if (xhr.status != 200 && xhr.responseText.search('Ticket expired') !== -1) {
tree.addIcon(_item, {icon: 'icon-server-connecting'});
let fetchTicket = Kerberos.fetch_ticket();
fetchTicket.then(
function() {
connect_to_server(_node, _data, _tree, _item, _wasConnected);
} else {
Alertify.dlgServerPass(
gettext('Connect to Server'),
msg, _node, _data, _tree, _item, _wasConnected
).resizeTo();
},
function() {
tree.addIcon(_item, {icon: 'icon-server-not-connected'});
Alertify.pgNotifier('Connection error', xhr, gettext('Connect to server.'));
}
}, 100);
});
);
} else {
Alertify.pgNotifier('error', xhr, error, function(msg) {
setTimeout(function() {
if (msg == 'CRYPTKEY_SET') {
connect_to_server(_node, _data, _tree, _item, _wasConnected);
} else {
Alertify.dlgServerPass(
gettext('Connect to Server'),
msg, _node, _data, _tree, _item, _wasConnected
).resizeTo();
}
}, 100);
});
}
},
onSuccess = function(res, node, _data, _tree, _item, _wasConnected) {
if (res && res.data) {