public inbox for [email protected]  
help / color / mirror / Atom feed
[pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
32+ messages / 6 participants
[nested] [flat]

* [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2020-12-22 10:14  Khushboo Vashi <[email protected]>
  0 siblings, 2 replies; 32+ messages in thread

From: Khushboo Vashi @ 2020-12-22 10:14 UTC (permalink / raw)
  To: pgadmin-hackers

Hi,

Please find the attached patch to support Kerberos Authentication in
pgAdmin RM 5457.

The patch introduces a new pluggable option for Kerberos authentication,
using SPNEGO to forward kerberos tickets through a browser which will
bypass the login page entirely if the Kerberos Authentication succeeds.

The complete setup of the Kerberos Server + pgAdmin Server + Client is
documented in a separate file and attached.

This patch also includes the small fix related to logging #5829

Thanks,
Khushboo


Attachments:

  [application/octet-stream] RM_5457.patch (25.8K, 3-RM_5457.patch)
  download | inline diff:
diff --git a/requirements.txt b/requirements.txt
index 0fe9c88bd..4675a0b94 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -42,3 +42,4 @@ bcrypt<=3.1.7;
 cryptography<=3.0;
 sshtunnel>=0.1.5
 ldap3>=2.5.1
+gssapi>=1.6.11
diff --git a/web/config.py b/web/config.py
index 086083a52..b8b3714ab 100644
--- a/web/config.py
+++ b/web/config.py
@@ -535,7 +535,7 @@ ENHANCED_COOKIE_PROTECTION = True
 ##########################################################################
 
 # Default setting is internal
-# External Supported Sources: ldap
+# External Supported Sources: ldap, kerberos
 # Multiple authentication can be achieved by setting this parameter to
 # ['ldap', 'internal']. pgAdmin will authenticate the user with ldap first,
 # in case of failure internal authentication will be done.
@@ -618,6 +618,26 @@ LDAP_CA_CERT_FILE = ''
 LDAP_CERT_FILE = ''
 LDAP_KEY_FILE = ''
 
+
+##########################################################################
+# Kerberos Configuration
+##########################################################################
+
+KRB_APP_HOST_NAME = DEFAULT_SERVER
+
+# If the default_keytab_name is not set in krb5.conf or
+# the KRB_KTNAME environment variable is not set then, explicitly set
+# the Keytab file
+
+KRB_KTNAME = '<KRB5_KEYTAB_FILE>'
+
+# After kerberos authentication, user will be added into the SQLite database
+# automatically, if set to True.
+# Set it to False, if user should not be added automatically,
+# in this case Admin has to add the user manually in the SQLite database.
+
+KRB_AUTO_CREATE_USER = True
+
 ##########################################################################
 # Local config settings
 ##########################################################################
diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py
index 8e0eb99d3..5586875df 100644
--- a/web/pgAdmin4.py
+++ b/web/pgAdmin4.py
@@ -97,15 +97,19 @@ if config.SERVER_MODE:
 
 # Authentication sources
 app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
-app.PGADMIN_SUPPORTED_AUTH_SOURCE = ['internal', 'ldap']
+app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
+app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
+
+app.PGADMIN_SUPPORTED_AUTH_SOURCE = [app.PGADMIN_DEFAULT_AUTH_SOURCE,
+                                     app.PGADMIN_LDAP_AUTH_SOURCE,
+                                     app.PGADMIN_KERBEROS_AUTH_SOURCE
+                                     ]
+
 if len(config.AUTHENTICATION_SOURCES) > 0:
     app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
 else:
     app.PGADMIN_EXTERNAL_AUTH_SOURCE = app.PGADMIN_DEFAULT_AUTH_SOURCE
 
-app.logger.debug(
-    "Authentication Source: %s" % app.PGADMIN_DEFAULT_AUTH_SOURCE)
-
 # Start the web server. The port number should have already been set by the
 # runtime if we're running in desktop mode, otherwise we'll just use the
 # Flask default.
diff --git a/web/pgAdmin4.wsgi b/web/pgAdmin4.wsgi
index 4ed2d7860..693f688ae 100644
--- a/web/pgAdmin4.wsgi
+++ b/web/pgAdmin4.wsgi
@@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
 
 import config
 
+
+config.AUTHENTICATION_SOURCES = ['kerberos']
+config.KERBEROS_AUTO_CREATE_USER = True
+
 # When running it as a WSGI application, directory for the configuration file
 # must present.
 if not os.path.exists(os.path.dirname(config.SQLITE_PATH)):
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index 223c2053a..5dc5a1e60 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -674,6 +674,7 @@ def create_app(app_name=None):
 
         # Check the auth key is valid, if it's set, and we're not in server
         # mode, and it's not a help file request.
+
         if not config.SERVER_MODE and app.PGADMIN_INT_KEY != '' and ((
             'key' not in request.args or
             request.args['key'] != app.PGADMIN_INT_KEY) and
@@ -695,11 +696,19 @@ def create_app(app_name=None):
                 )
                 abort(401)
             login_user(user)
+        elif config.SERVER_MODE and\
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE ==\
+                app.PGADMIN_KERBEROS_AUTH_SOURCE and \
+                not current_user.is_authenticated and \
+                request.endpoint in ('redirects.index', 'security.login'):
+            return authenticate.login()
 
         # if the server is restarted the in memory key will be lost
         # but the user session may still be active. Logout the user
         # to get the key again when login
         if config.SERVER_MODE and current_user.is_authenticated and \
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE != \
+                app.PGADMIN_KERBEROS_AUTH_SOURCE and \
                 current_app.keyManager.get() is None and \
                 request.endpoint not in ('security.login', 'security.logout'):
             logout_user()
diff --git a/web/pgadmin/authenticate/__init__.py b/web/pgadmin/authenticate/__init__.py
index 5284e0c52..898daf0b1 100644
--- a/web/pgadmin/authenticate/__init__.py
+++ b/web/pgadmin/authenticate/__init__.py
@@ -11,7 +11,7 @@
 
 import flask
 import pickle
-from flask import current_app, flash
+from flask import current_app, flash, Response, request, url_for
 from flask_babelex import gettext
 from flask_security import current_user
 from flask_security.views import _security, _ctx
@@ -56,15 +56,24 @@ def login():
     if status:
         # Login the user
         status, msg = auth_obj.login()
+        current_auth_obj = auth_obj.as_dict()
         if not status:
+            if current_auth_obj['current_source'] ==\
+                    current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
+                return flask.redirect('{0}?next={1}'.format(url_for(
+                    'browser.kerberos_login'), url_for('browser.index')))
+
             flash(gettext(msg), 'danger')
             return flask.redirect(get_post_logout_redirect())
 
-        session['_auth_source_manager_obj'] = auth_obj.as_dict()
+        session['_auth_source_manager_obj'] = current_auth_obj
         return flask.redirect(get_post_login_redirect())
 
+    elif isinstance(msg, Response):
+        return msg
     flash(gettext(msg), 'danger')
-    return flask.redirect(get_post_logout_redirect())
+    response = flask.redirect(get_post_logout_redirect())
+    return response
 
 
 class AuthSourceManager():
@@ -75,6 +84,7 @@ class AuthSourceManager():
         self.auth_sources = sources
         self.source = None
         self.source_friendly_name = None
+        self.current_source = None
 
     def as_dict(self):
         """
@@ -84,9 +94,17 @@ class AuthSourceManager():
         res = dict()
         res['source_friendly_name'] = self.source_friendly_name
         res['auth_sources'] = self.auth_sources
+        res['current_source'] = self.current_source
 
         return res
 
+    def set_current_source(self, source):
+        self.current_source = source
+
+    @property
+    def get_current_source(self, source):
+        return self.current_source
+
     def set_source(self, source):
         self.source = source
 
@@ -115,9 +133,34 @@ class AuthSourceManager():
         msg = None
         for src in self.auth_sources:
             source = get_auth_sources(src)
+            current_app.logger.debug(
+                "Authentication initiated via source: %s" %
+                source.get_source_name())
+
+            # if self.form.data['email'] and self.form.data['password'] and \
+            #         source.get_source_name() ==\
+            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
+            #     continue
+
             status, msg = source.authenticate(self.form)
+
+            # When server sends Unauthorized header to get the ticket over HTTP
+            # OR When kerberos authentication failed while accessing pgadmin,
+            # we need to break the loop as no need to authenticate further
+            # even if the authentication sources set to multiple
+            if not status:
+                if (hasattr(msg, 'status') and
+                    msg.status == '401 UNAUTHORIZED') or\
+                        (source.get_source_name() ==
+                         current_app.PGADMIN_KERBEROS_AUTH_SOURCE and
+                         request.method == 'GET'):
+                    break
+
             if status:
                 self.set_source(source)
+                self.set_current_source(source.get_source_name())
+                if msg is not None and 'username' in msg:
+                    self.form._fields['email'].data = msg['username']
                 return status, msg
         return status, msg
 
@@ -125,6 +168,9 @@ class AuthSourceManager():
         status, msg = self.source.login(self.form)
         if status:
             self.set_source_friendly_name(self.source.get_friendly_name())
+            current_app.logger.debug(
+                "Authentication and Login successfully done via source : %s" %
+                self.source.get_source_name())
         return status, msg
 
 
diff --git a/web/pgadmin/authenticate/internal.py b/web/pgadmin/authenticate/internal.py
index 105e78c4e..34361d6fd 100644
--- a/web/pgadmin/authenticate/internal.py
+++ b/web/pgadmin/authenticate/internal.py
@@ -31,7 +31,11 @@ class BaseAuthentication(object):
         'INVALID_EMAIL': gettext('Email/Username is not valid')
     }
 
-    @abstractproperty
+    @abstractmethod
+    def get_source_name(self):
+        pass
+
+    @abstractmethod
     def get_friendly_name(self):
         pass
 
@@ -82,6 +86,9 @@ class BaseAuthentication(object):
 
 class InternalAuthentication(BaseAuthentication):
 
+    def get_source_name(self):
+        return current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+
     def get_friendly_name(self):
         return gettext("internal")
 
diff --git a/web/pgadmin/authenticate/kerberos.py b/web/pgadmin/authenticate/kerberos.py
new file mode 100644
index 000000000..9be5e0825
--- /dev/null
+++ b/web/pgadmin/authenticate/kerberos.py
@@ -0,0 +1,137 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the Spnego/Kerberos authentication."""
+
+import base64
+import gssapi
+from os import environ
+
+from werkzeug.datastructures import Headers
+from flask_babelex import gettext
+from flask import Flask, request, Response, session,\
+    current_app, render_template, flash
+
+import config
+from pgadmin.model import User, ServerGroup, db, Role
+from pgadmin.tools.user_management import create_user
+
+from flask_security.views import _security, _commit, _ctx
+from werkzeug.datastructures import MultiDict
+
+from .internal import BaseAuthentication
+
+
+# Set the Kerberos config file
+if config.KRB_KTNAME and config.KRB_KTNAME != '<KRB5_KEYTAB_FILE>':
+    environ['KRB5_KTNAME'] = config.KRB_KTNAME
+
+
+class KERBEROSAuthentication(BaseAuthentication):
+
+    def get_source_name(self):
+        return current_app.PGADMIN_KERBEROS_AUTH_SOURCE
+
+    def get_friendly_name(self):
+        return gettext("kerberos")
+
+    def validate(self, form):
+        return True
+
+    def authenticate(self, frm):
+        retval = [True, None]
+        negotiate = False
+        headers = Headers()
+        authorization = request.headers.get("Authorization", None)
+        form_class = _security.login_form
+
+        if request.json:
+            form = form_class(MultiDict(request.json))
+        else:
+            form = form_class()
+
+        try:
+            if authorization is not None:
+                auth_header = authorization.split()
+                if auth_header[0] == 'Negotiate':
+                    status, negotiate = self.negotiate_start(auth_header[1])
+
+                    if status:
+                        # Saving the first 15 characters of the kerberos key
+                        # to encrypt/decrypt database password
+                        session['kerberos_key'] = auth_header[1][0:15]
+                        # Create user
+                        retval = self.__auto_create_user(
+                            str(negotiate.initiator_name))
+                    elif isinstance(negotiate, Exception):
+                        flash(gettext(negotiate), 'danger')
+                        retval = [status,
+                                  Response(render_template(
+                                      "security/login_user.html",
+                                      login_user_form=form))]
+                    else:
+                        headers.add('WWW-Authenticate', 'Negotiate ' +
+                                    str(base64.b64encode(negotiate), 'utf-8'))
+                        return False, Response("Success", 200, headers)
+            else:
+                flash(gettext("Kerberos authentication failed."
+                              " Couldn't find kerberos ticket."), 'danger')
+                headers.add('WWW-Authenticate', 'Negotiate')
+                retval = [False,
+                          Response(render_template(
+                              "security/login_user.html",
+                              login_user_form=form), 401, headers)]
+        finally:
+            if negotiate is not False:
+                self.negotiate_end(negotiate)
+        return retval
+
+    def negotiate_start(self, in_token):
+        svc_princ = gssapi.Name('HTTP@%s' % config.KRB_APP_HOST_NAME,
+                                name_type=gssapi.NameType.hostbased_service)
+        cname = svc_princ.canonicalize(gssapi.MechType.kerberos)
+
+        try:
+            server_creds = gssapi.Credentials(usage='accept', name=cname)
+            context = gssapi.SecurityContext(creds=server_creds)
+            out_token = context.step(base64.b64decode(in_token))
+        except Exception as e:
+            current_app.logger.exception(e)
+            return False, e
+
+        if out_token and not context.complete:
+            return False, out_token
+        if context.complete:
+            return True, context
+        else:
+            return False, None
+
+    def negotiate_end(self, context):
+        # Free gss_cred_id_t
+        del_creds = getattr(context, 'delegated_creds', None)
+        if del_creds:
+            deleg_creds = context.delegated_creds
+            del(deleg_creds)
+
+    def __auto_create_user(self, username):
+        """Add the ldap user to the internal SQLite database."""
+        username = str(username)
+        if config.KRB_AUTO_CREATE_USER:
+            user = User.query.filter_by(
+                username=username).first()
+            if user is None:
+                return create_user({
+                    'username': username,
+                    'email': username,
+                    'role': 2,
+                    'active': True,
+                    'auth_source': 'kerberos'
+                })
+
+        return True, {'username': username}
diff --git a/web/pgadmin/authenticate/ldap.py b/web/pgadmin/authenticate/ldap.py
index 2cdca8605..7c10143c0 100644
--- a/web/pgadmin/authenticate/ldap.py
+++ b/web/pgadmin/authenticate/ldap.py
@@ -31,6 +31,9 @@ ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
 class LDAPAuthentication(BaseAuthentication):
     """Ldap Authentication Class"""
 
+    def get_source_name(self):
+        return current_app.PGADMIN_LDAP_AUTH_SOURCE
+
     def get_friendly_name(self):
         return gettext("ldap")
 
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 77120cd59..dd4807b51 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -29,7 +29,7 @@ from flask_security.recoverable import reset_password_token_status, \
     generate_reset_password_token, update_password
 from flask_security.signals import reset_password_instructions_sent
 from flask_security.utils import config_value, do_flash, get_url, \
-    get_message, slash_url_suffix, login_user, send_mail
+    get_message, slash_url_suffix, login_user, send_mail, logout_user
 from flask_security.views import _security, _commit, _ctx
 from werkzeug.datastructures import MultiDict
 
@@ -280,7 +280,10 @@ class BrowserModule(PgAdminModule):
                 'browser.check_master_password',
                 'browser.set_master_password',
                 'browser.reset_master_password',
-                'browser.lock_layout']
+                'browser.lock_layout',
+                'browser.kerberos_logout',
+                'browser.kerberos_login',
+                ]
 
 
 blueprint = BrowserModule(MODULE_NAME, __name__)
@@ -539,6 +542,11 @@ class BrowserPluginModule(PgAdminModule):
 
 
 def _get_logout_url():
+    if session['_auth_source_manager_obj']['current_source'] == \
+            current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
+        return '{0}?next={1}'.format(url_for(
+            'browser.kerberos_logout'), url_for(BROWSER_INDEX))
+
     return '{0}?next={1}'.format(
         url_for('security.logout'), url_for(BROWSER_INDEX))
 
@@ -623,6 +631,28 @@ def check_browser_upgrade():
         flash(msg, 'warning')
 
 
[email protected]("/kerberos_login",
+                 endpoint="kerberos_login", methods=["GET"])
[email protected]
+def kerberos_login():
+    logout_user()
+    return Response(render_template(
+        MODULE_NAME + "/kerberos_login.html",
+        login_url=url_for('security.login'),
+    ))
+
+
[email protected]("/kerberos_logout",
+                 endpoint="kerberos_logout", methods=["GET"])
[email protected]
+def kerberos_logout():
+    logout_user()
+    return Response(render_template(
+        MODULE_NAME + "/kerberos_logout.html",
+        login_url=url_for('security.login'),
+    ))
+
+
 @blueprint.route("/")
 @pgCSRFProtect.exempt
 @login_required
diff --git a/web/pgadmin/browser/templates/browser/kerberos_login.html b/web/pgadmin/browser/templates/browser/kerberos_login.html
new file mode 100644
index 000000000..c112e3196
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_login.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Login Failed.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/templates/browser/kerberos_logout.html b/web/pgadmin/browser/templates/browser/kerberos_logout.html
new file mode 100644
index 000000000..430dc6f25
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_logout.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Logged out successfully.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/tests/test_kerberos_with_mocking.py b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
new file mode 100644
index 000000000..50caa71e9
--- /dev/null
+++ b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
@@ -0,0 +1,106 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import config as app_config
+from pgadmin.utils.route import BaseTestGenerator
+from regression.python_test_utils import test_utils as utils
+from pgadmin.authenticate.registry import AuthSourceRegistry
+from unittest.mock import patch, MagicMock
+
+
+class KerberosLoginMockTestCase(BaseTestGenerator):
+    """
+    This class checks Spnego/Kerberos login functionality by mocking
+    HTTP negotiate authentication.
+    """
+
+    scenarios = [
+        ('Spnego/Kerberos Authentication: Test Unauthorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            username='[email protected]',
+            password='PASSWORD',
+            flag=1
+        )),
+        ('Spnego/Kerberos Authentication: Test Authorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            username='[email protected]',
+            password='PASSWORD',
+            flag=2
+        ))
+    ]
+
+    @classmethod
+    def setUpClass(cls):
+        """
+        We need to logout the test client as we are testing
+        spnego/kerberos login scenarios.
+        """
+        cls.tester.logout()
+
+    def setUp(self):
+        app_config.AUTHENTICATION_SOURCES = self.auth_source
+
+    def runTest(self):
+        """This function checks spnego/kerberos login functionality."""
+        if self.flag == 1:
+            self.test_unauthorized()
+        elif self.flag == 2:
+            if app_config.SERVER_MODE is False:
+                self.skipTest(
+                    "Can not run Kerberos Authentication in the Desktop mode."
+                )
+
+            self.test_authorized()
+
+    def test_unauthorized(self):
+        """
+        Ensure that when client sends the first request,
+        the Negotiate request is sent.
+        """
+        res = self.tester.login(self.username, self.password, True)
+        self.assertEqual(res.status_code, 401)
+        self.assertEqual(res.headers.get('www-authenticate'), 'Negotiate')
+
+    def test_authorized(self):
+        """
+        Ensure that when the client sends an correct authorization token,
+        they receive a 200 OK response and the user principal is extracted and
+        passed on to the routed method.
+        """
+
+        class delCrads:
+            def __init__(self):
+                self.initiator_name = '[email protected]'
+        del_crads = delCrads()
+
+        AuthSourceRegistry.registry['kerberos'].negotiate_start = MagicMock(
+            return_value=[True, del_crads])
+        res = self.tester.login(self.username,
+                                self.password,
+                                True,
+                                headers={'Authorization': 'Negotiate CTOKEN'}
+                                )
+        self.assertEqual(res.status_code, 200)
+        respdata = 'Gravatar image for %s' % self.username
+        self.assertTrue(respdata in res.data.decode('utf8'))
+
+    def tearDown(self):
+        self.tester.logout()
+
+    @classmethod
+    def tearDownClass(cls):
+        """
+        We need to again login the test client as soon as test scenarios
+        finishes.
+        """
+        cls.tester.logout()
+        app_config.AUTHENTICATION_SOURCES = ['internal']
+        utils.login_tester_account(cls.tester)
diff --git a/web/pgadmin/utils/master_password.py b/web/pgadmin/utils/master_password.py
index 759bf36e0..be655bef2 100644
--- a/web/pgadmin/utils/master_password.py
+++ b/web/pgadmin/utils/master_password.py
@@ -1,5 +1,5 @@
 import config
-from flask import current_app
+from flask import current_app, session
 from flask_login import current_user
 from pgadmin.model import db, User, Server
 from pgadmin.utils.crypto import encrypt, decrypt
@@ -32,6 +32,11 @@ def get_crypt_key():
     elif config.MASTER_PASSWORD_REQUIRED \
             and not config.SERVER_MODE and enc_key is None:
         return False, None
+    elif config.SERVER_MODE and \
+            session['_auth_source_manager_obj']['source_friendly_name']\
+            == current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
+        return True, session['kerberos_key'] if 'kerberos_key' in session \
+            else None
     else:
         return True, enc_key
 
diff --git a/web/regression/python_test_utils/csrf_test_client.py b/web/regression/python_test_utils/csrf_test_client.py
index ad3396790..d1adfdc54 100644
--- a/web/regression/python_test_utils/csrf_test_client.py
+++ b/web/regression/python_test_utils/csrf_test_client.py
@@ -101,7 +101,8 @@ class TestClient(testing.FlaskClient):
 
             return csrf_token
 
-    def login(self, email, password, _follow_redirects=False):
+    def login(self, email, password, _follow_redirects=False,
+              headers=None):
         if config.SERVER_MODE is True:
             res = self.get('/login', follow_redirects=True)
             csrf_token = self.fetch_csrf(res)
@@ -113,7 +114,8 @@ class TestClient(testing.FlaskClient):
                 email=email, password=password,
                 csrf_token=csrf_token,
             ),
-            follow_redirects=_follow_redirects
+            follow_redirects=_follow_redirects,
+            headers=headers
         )
         self.csrf_token = csrf_token
 
diff --git a/web/regression/runtests.py b/web/regression/runtests.py
index a62358fac..a6782f36e 100644
--- a/web/regression/runtests.py
+++ b/web/regression/runtests.py
@@ -119,6 +119,8 @@ app.config['WTF_CSRF_ENABLED'] = True
 # Authentication sources
 app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
 app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
+app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
+app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
 
 app.test_client_class = TestClient
 test_client = app.test_client()
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 000000000..fb57ccd13
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+


  [application/vnd.openxmlformats-officedocument.wordprocessingml.document] GSSAPI Authentication - pgAdmin.docx (10.1K, 4-GSSAPI%20Authentication%20-%20pgAdmin.docx)
  download

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2020-12-22 12:37  Akshay Joshi <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  1 sibling, 1 reply; 32+ messages in thread

From: Akshay Joshi @ 2020-12-22 12:37 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: pgadmin-hackers

Hi Aditya

Can you please do the code review?

On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
[email protected]> wrote:

> Hi,
>
> Please find the attached patch to support Kerberos Authentication in
> pgAdmin RM 5457.
>
> The patch introduces a new pluggable option for Kerberos authentication,
> using SPNEGO to forward kerberos tickets through a browser which will
> bypass the login page entirely if the Kerberos Authentication succeeds.
>
> The complete setup of the Kerberos Server + pgAdmin Server + Client is
> documented in a separate file and attached.
>
> This patch also includes the small fix related to logging #5829
>
> Thanks,
> Khushboo
>


-- 
*Thanks & Regards*
*Akshay Joshi*
*pgAdmin Hacker | Principal Software Architect*
*EDB Postgres <http://edbpostgres.com>*

*Mobile: +91 976-788-8246*


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-01 07:37  Aditya Toshniwal <[email protected]>
  parent: Akshay Joshi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Aditya Toshniwal @ 2021-01-01 07:37 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers

Hi Khushboo,

I've just done the code review. Apart from below, the patch looks good to
me:

1) Move the auth source constants -ldap, kerberos out of app object. They
don't belong there. You can create the constants somewhere else and import
them.

+app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'

+app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'


2) Are we going to make kerberos default for wsgi ?

*--- a/web/pgAdmin4.wsgi*

*+++ b/web/pgAdmin4.wsgi*

@@ -24,6 +24,10 @@ builtins.SERVER_MODE = True



 import config



+

+config.AUTHENTICATION_SOURCES = ['kerberos']

+config.KERBEROS_AUTO_CREATE_USER = True

+


3) Remove the commented code.

+            # if self.form.data['email'] and self.form.data['password']
and \

+            #         source.get_source_name() ==\

+            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:

+            #     continue


4) KERBEROSAuthentication could be KerberosAuthentication

class KERBEROSAuthentication(BaseAuthentication):


5) You can use the constants (ldap, kerberos) you had defined when creating
a user.

+                    'auth_source': 'kerberos'


6) The below URLs belong to the authenticate module. Currently they are in
the browser module. I would also suggest rephrasing the URL from
/kerberos_login to /login/kerberos. Same for logout. Also, even though the
method GET works, we should use the POST method for login and DELETE for
logout.

[email protected]("/kerberos_login",

+                 endpoint="kerberos_login", methods=["GET"])


[email protected]("/kerberos_logout",

+                 endpoint="kerberos_logout", methods=["GET"])



On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <[email protected]>
wrote:

> Hi Aditya
>
> Can you please do the code review?
>
> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
> [email protected]> wrote:
>
>> Hi,
>>
>> Please find the attached patch to support Kerberos Authentication in
>> pgAdmin RM 5457.
>>
>> The patch introduces a new pluggable option for Kerberos authentication,
>> using SPNEGO to forward kerberos tickets through a browser which will
>> bypass the login page entirely if the Kerberos Authentication succeeds.
>>
>> The complete setup of the Kerberos Server + pgAdmin Server + Client is
>> documented in a separate file and attached.
>>
>> This patch also includes the small fix related to logging #5829
>>
>> Thanks,
>> Khushboo
>>
>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
> *pgAdmin Hacker | Principal Software Architect*
> *EDB Postgres <http://edbpostgres.com>*
>
> *Mobile: +91 976-788-8246*
>


-- 
Thanks,
Aditya Toshniwal
pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
<http://edbpostgres.com;
"Don't Complain about Heat, Plant a TREE"


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-02 15:41  Stephen Frost <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  1 sibling, 1 reply; 32+ messages in thread

From: Stephen Frost @ 2021-01-02 15:41 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: pgadmin-hackers

Greetings,

* Khushboo Vashi ([email protected]) wrote:
> Please find the attached patch to support Kerberos Authentication in
> pgAdmin RM 5457.
> 
> The patch introduces a new pluggable option for Kerberos authentication,
> using SPNEGO to forward kerberos tickets through a browser which will
> bypass the login page entirely if the Kerberos Authentication succeeds.

I've taken a (very short) look at this as it's certainly something that
I'm interested in and glad to see work is being done on it.

I notice that 'delegated_creds' is being set but it's unclear to me how
they're actually being used (if at all), which is a very important part
of Kerberos.

What's commonly done with mod_auth_kerb/mod_auth_gss is that the
delegated credentials are stored on the filesystem in a temporary
directory and then an environment variable is set to signal to libpq /
the Kerberos libraries that the delegated credentials can be found in
the temporary file.  I don't see any of that happening in this patch- is
that already handled in some way?  If not, what's the plan for making
that work?  Also important is to make sure that this approach will work
for constrainted delegation implementations.

Thanks!

Stephen


Attachments:

  [application/pgp-signature] signature.asc (819B, 2-signature.asc)
  download

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-02 15:56  Dave Page <[email protected]>
  parent: Stephen Frost <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-02 15:56 UTC (permalink / raw)
  To: Stephen Frost <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers

Hi Stephen

On Sat, 2 Jan 2021 at 15:41, Stephen Frost <[email protected]> wrote:

> Greetings,
>
> * Khushboo Vashi ([email protected]) wrote:
> > Please find the attached patch to support Kerberos Authentication in
> > pgAdmin RM 5457.
> >
> > The patch introduces a new pluggable option for Kerberos authentication,
> > using SPNEGO to forward kerberos tickets through a browser which will
> > bypass the login page entirely if the Kerberos Authentication succeeds.
>
> I've taken a (very short) look at this as it's certainly something that
> I'm interested in and glad to see work is being done on it.
>
> I notice that 'delegated_creds' is being set but it's unclear to me how
> they're actually being used (if at all), which is a very important part
> of Kerberos.
>
> What's commonly done with mod_auth_kerb/mod_auth_gss is that the
> delegated credentials are stored on the filesystem in a temporary
> directory and then an environment variable is set to signal to libpq /
> the Kerberos libraries that the delegated credentials can be found in
> the temporary file.  I don't see any of that happening in this patch- is
> that already handled in some way?  If not, what's the plan for making
> that work?  Also important is to make sure that this approach will work
> for constrainted delegation implementations.


Phase 1 of this project (which this patch aims to implement) is to handle
Kerberos logins to pgAdmin when running in server mode (as we’ve already
done for LDAP, except KRB authenticated users don’t see a login page of
course). Phase 2 will add support for logging into the PostgreSQL servers -
I believe that is where we’ll need to handle delegated credentials, correct?

> --
-- 
Dave Page
https://pgsnake.blogspot.com

EDB Postgres
https://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-02 15:59  Stephen Frost <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Stephen Frost @ 2021-01-02 15:59 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers

Greetings Dave!

* Dave Page ([email protected]) wrote:
> On Sat, 2 Jan 2021 at 15:41, Stephen Frost <[email protected]> wrote:
> > * Khushboo Vashi ([email protected]) wrote:
> > > Please find the attached patch to support Kerberos Authentication in
> > > pgAdmin RM 5457.
> > >
> > > The patch introduces a new pluggable option for Kerberos authentication,
> > > using SPNEGO to forward kerberos tickets through a browser which will
> > > bypass the login page entirely if the Kerberos Authentication succeeds.
> >
> > I've taken a (very short) look at this as it's certainly something that
> > I'm interested in and glad to see work is being done on it.
> >
> > I notice that 'delegated_creds' is being set but it's unclear to me how
> > they're actually being used (if at all), which is a very important part
> > of Kerberos.
> >
> > What's commonly done with mod_auth_kerb/mod_auth_gss is that the
> > delegated credentials are stored on the filesystem in a temporary
> > directory and then an environment variable is set to signal to libpq /
> > the Kerberos libraries that the delegated credentials can be found in
> > the temporary file.  I don't see any of that happening in this patch- is
> > that already handled in some way?  If not, what's the plan for making
> > that work?  Also important is to make sure that this approach will work
> > for constrainted delegation implementations.
> 
> Phase 1 of this project (which this patch aims to implement) is to handle
> Kerberos logins to pgAdmin when running in server mode (as we’ve already
> done for LDAP, except KRB authenticated users don’t see a login page of
> course). Phase 2 will add support for logging into the PostgreSQL servers -
> I believe that is where we’ll need to handle delegated credentials, correct?

Yes, though I sure hope there isn't a plan to release just 'phase 1'
since that would imply that the user is still sending their password to
pgAdmin in some form that pgAdmin then turns around and impersonates the
user, basically completely against how Kerberos auth should be working
in this kind of a intermediate service arrangement.

In other words, if just 'phase 1' is released, it'd probably be CVE
worthy right out of the gate...

Thanks,

Stephen


Attachments:

  [application/pgp-signature] signature.asc (819B, 2-signature.asc)
  download

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-02 16:21  Dave Page <[email protected]>
  parent: Stephen Frost <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-02 16:21 UTC (permalink / raw)
  To: Stephen Frost <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers

Hi

On Sat, 2 Jan 2021 at 15:59, Stephen Frost <[email protected]> wrote:

> Greetings Dave!
>
> * Dave Page ([email protected]) wrote:
> > On Sat, 2 Jan 2021 at 15:41, Stephen Frost <[email protected]> wrote:
> > > * Khushboo Vashi ([email protected]) wrote:
> > > > Please find the attached patch to support Kerberos Authentication in
> > > > pgAdmin RM 5457.
> > > >
> > > > The patch introduces a new pluggable option for Kerberos
> authentication,
> > > > using SPNEGO to forward kerberos tickets through a browser which will
> > > > bypass the login page entirely if the Kerberos Authentication
> succeeds.
> > >
> > > I've taken a (very short) look at this as it's certainly something that
> > > I'm interested in and glad to see work is being done on it.
> > >
> > > I notice that 'delegated_creds' is being set but it's unclear to me how
> > > they're actually being used (if at all), which is a very important part
> > > of Kerberos.
> > >
> > > What's commonly done with mod_auth_kerb/mod_auth_gss is that the
> > > delegated credentials are stored on the filesystem in a temporary
> > > directory and then an environment variable is set to signal to libpq /
> > > the Kerberos libraries that the delegated credentials can be found in
> > > the temporary file.  I don't see any of that happening in this patch-
> is
> > > that already handled in some way?  If not, what's the plan for making
> > > that work?  Also important is to make sure that this approach will work
> > > for constrainted delegation implementations.
> >
> > Phase 1 of this project (which this patch aims to implement) is to handle
> > Kerberos logins to pgAdmin when running in server mode (as we’ve already
> > done for LDAP, except KRB authenticated users don’t see a login page of
> > course). Phase 2 will add support for logging into the PostgreSQL
> servers -
> > I believe that is where we’ll need to handle delegated credentials,
> correct?
>
> Yes, though I sure hope there isn't a plan to release just 'phase 1'
> since that would imply that the user is still sending their password to
> pgAdmin in some form that pgAdmin then turns around and impersonates the
> user, basically completely against how Kerberos auth should be working
> in this kind of a intermediate service arrangement.
>
> In other words, if just 'phase 1' is released, it'd probably be CVE
> worthy right out of the gate...


It wouldn’t impersonate the user at all, it would just work as it does now,
requiring the user to supply a username/password for scram/md5/ldap etc, or
a cert for SSL auth. Connection to a PostgreSQL server which required gss
or sspi simply wouldn’t work (unless the service account under which the
pgAdmin server is running has a valid ticket through other means).

> --
-- 
Dave Page
https://pgsnake.blogspot.com

EDB Postgres
https://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-03 17:31  Stephen Frost <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 2 replies; 32+ messages in thread

From: Stephen Frost @ 2021-01-03 17:31 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers

Greetings,

* Dave Page ([email protected]) wrote:
> On Sat, 2 Jan 2021 at 15:59, Stephen Frost <[email protected]> wrote:
> > * Dave Page ([email protected]) wrote:
> > > On Sat, 2 Jan 2021 at 15:41, Stephen Frost <[email protected]> wrote:
> > > > * Khushboo Vashi ([email protected]) wrote:
> > > > > Please find the attached patch to support Kerberos Authentication in
> > > > > pgAdmin RM 5457.
> > > > >
> > > > > The patch introduces a new pluggable option for Kerberos
> > authentication,
> > > > > using SPNEGO to forward kerberos tickets through a browser which will
> > > > > bypass the login page entirely if the Kerberos Authentication
> > succeeds.
> > > >
> > > > I've taken a (very short) look at this as it's certainly something that
> > > > I'm interested in and glad to see work is being done on it.
> > > >
> > > > I notice that 'delegated_creds' is being set but it's unclear to me how
> > > > they're actually being used (if at all), which is a very important part
> > > > of Kerberos.
> > > >
> > > > What's commonly done with mod_auth_kerb/mod_auth_gss is that the
> > > > delegated credentials are stored on the filesystem in a temporary
> > > > directory and then an environment variable is set to signal to libpq /
> > > > the Kerberos libraries that the delegated credentials can be found in
> > > > the temporary file.  I don't see any of that happening in this patch-
> > is
> > > > that already handled in some way?  If not, what's the plan for making
> > > > that work?  Also important is to make sure that this approach will work
> > > > for constrainted delegation implementations.
> > >
> > > Phase 1 of this project (which this patch aims to implement) is to handle
> > > Kerberos logins to pgAdmin when running in server mode (as we’ve already
> > > done for LDAP, except KRB authenticated users don’t see a login page of
> > > course). Phase 2 will add support for logging into the PostgreSQL
> > servers -
> > > I believe that is where we’ll need to handle delegated credentials,
> > correct?
> >
> > Yes, though I sure hope there isn't a plan to release just 'phase 1'
> > since that would imply that the user is still sending their password to
> > pgAdmin in some form that pgAdmin then turns around and impersonates the
> > user, basically completely against how Kerberos auth should be working
> > in this kind of a intermediate service arrangement.
> >
> > In other words, if just 'phase 1' is released, it'd probably be CVE
> > worthy right out of the gate...
> 
> It wouldn’t impersonate the user at all, it would just work as it does now,
> requiring the user to supply a username/password for scram/md5/ldap etc, or
> a cert for SSL auth. Connection to a PostgreSQL server which required gss
> or sspi simply wouldn’t work (unless the service account under which the
> pgAdmin server is running has a valid ticket through other means).

That *is* impersonating the user..

Kerberized services really should *not* be accepting a cleartext
password to use to authenticate as the user against another service,
which is why I'd strongly recommend against releasing with just
'phase 1' done.. or at least heavily caveat'ing it that this isn't
actually real Kerberos support but is just an intermediate step that no
one should really deploy...

Thanks,

Stephen


Attachments:

  [application/pgp-signature] signature.asc (819B, 2-signature.asc)
  download

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-04 11:32  Dave Page <[email protected]>
  parent: Stephen Frost <[email protected]>
  1 sibling, 0 replies; 32+ messages in thread

From: Dave Page @ 2021-01-04 11:32 UTC (permalink / raw)
  To: Stephen Frost <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; pgadmin-hackers

On Sun, 3 Jan 2021 at 17:31, Stephen Frost <[email protected]> wrote:

> Greetings,
>
> * Dave Page ([email protected]) wrote:
> > On Sat, 2 Jan 2021 at 15:59, Stephen Frost <[email protected]> wrote:
> > > * Dave Page ([email protected]) wrote:
> > > > On Sat, 2 Jan 2021 at 15:41, Stephen Frost <[email protected]>
> wrote:
> > > > > * Khushboo Vashi ([email protected]) wrote:
> > > > > > Please find the attached patch to support Kerberos
> Authentication in
> > > > > > pgAdmin RM 5457.
> > > > > >
> > > > > > The patch introduces a new pluggable option for Kerberos
> > > authentication,
> > > > > > using SPNEGO to forward kerberos tickets through a browser which
> will
> > > > > > bypass the login page entirely if the Kerberos Authentication
> > > succeeds.
> > > > >
> > > > > I've taken a (very short) look at this as it's certainly something
> that
> > > > > I'm interested in and glad to see work is being done on it.
> > > > >
> > > > > I notice that 'delegated_creds' is being set but it's unclear to
> me how
> > > > > they're actually being used (if at all), which is a very important
> part
> > > > > of Kerberos.
> > > > >
> > > > > What's commonly done with mod_auth_kerb/mod_auth_gss is that the
> > > > > delegated credentials are stored on the filesystem in a temporary
> > > > > directory and then an environment variable is set to signal to
> libpq /
> > > > > the Kerberos libraries that the delegated credentials can be found
> in
> > > > > the temporary file.  I don't see any of that happening in this
> patch-
> > > is
> > > > > that already handled in some way?  If not, what's the plan for
> making
> > > > > that work?  Also important is to make sure that this approach will
> work
> > > > > for constrainted delegation implementations.
> > > >
> > > > Phase 1 of this project (which this patch aims to implement) is to
> handle
> > > > Kerberos logins to pgAdmin when running in server mode (as we’ve
> already
> > > > done for LDAP, except KRB authenticated users don’t see a login page
> of
> > > > course). Phase 2 will add support for logging into the PostgreSQL
> > > servers -
> > > > I believe that is where we’ll need to handle delegated credentials,
> > > correct?
> > >
> > > Yes, though I sure hope there isn't a plan to release just 'phase 1'
> > > since that would imply that the user is still sending their password to
> > > pgAdmin in some form that pgAdmin then turns around and impersonates
> the
> > > user, basically completely against how Kerberos auth should be working
> > > in this kind of a intermediate service arrangement.
> > >
> > > In other words, if just 'phase 1' is released, it'd probably be CVE
> > > worthy right out of the gate...
> >
> > It wouldn’t impersonate the user at all, it would just work as it does
> now,
> > requiring the user to supply a username/password for scram/md5/ldap etc,
> or
> > a cert for SSL auth. Connection to a PostgreSQL server which required gss
> > or sspi simply wouldn’t work (unless the service account under which the
> > pgAdmin server is running has a valid ticket through other means).
>
> That *is* impersonating the user..
>
> Kerberized services really should *not* be accepting a cleartext
> password to use to authenticate as the user against another service,
> which is why I'd strongly recommend against releasing with just
> 'phase 1' done.. or at least heavily caveat'ing it that this isn't
> actually real Kerberos support but is just an intermediate step that no
> one should really deploy...


By that argument, one should not be able to login to a kerberised SSH
server and then use a mail client to access Gmail (or for that matter, the
web interface), neither should one be able to login to a Postgres server
using Kerberos, and then use a non-kerberised FDW.

Why aren’t those cases CVE worthy?
-- 
-- 
Dave Page
https://pgsnake.blogspot.com

EDB Postgres
https://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-11 13:15  Magnus Hagander <[email protected]>
  parent: Stephen Frost <[email protected]>
  1 sibling, 1 reply; 32+ messages in thread

From: Magnus Hagander @ 2021-01-11 13:15 UTC (permalink / raw)
  To: Stephen Frost <[email protected]>; +Cc: Dave Page <[email protected]>; Khushboo Vashi <[email protected]>; pgadmin-hackers

On Sun, Jan 3, 2021 at 6:31 PM Stephen Frost <[email protected]> wrote:
>
> Greetings,
>
> * Dave Page ([email protected]) wrote:
> > On Sat, 2 Jan 2021 at 15:59, Stephen Frost <[email protected]> wrote:
> > > * Dave Page ([email protected]) wrote:
> > > > On Sat, 2 Jan 2021 at 15:41, Stephen Frost <[email protected]> wrote:
> > > > > * Khushboo Vashi ([email protected]) wrote:
> > > > > > Please find the attached patch to support Kerberos Authentication in
> > > > > > pgAdmin RM 5457.
> > > > > >
> > > > > > The patch introduces a new pluggable option for Kerberos
> > > authentication,
> > > > > > using SPNEGO to forward kerberos tickets through a browser which will
> > > > > > bypass the login page entirely if the Kerberos Authentication
> > > succeeds.
> > > > >
> > > > > I've taken a (very short) look at this as it's certainly something that
> > > > > I'm interested in and glad to see work is being done on it.
> > > > >
> > > > > I notice that 'delegated_creds' is being set but it's unclear to me how
> > > > > they're actually being used (if at all), which is a very important part
> > > > > of Kerberos.
> > > > >
> > > > > What's commonly done with mod_auth_kerb/mod_auth_gss is that the
> > > > > delegated credentials are stored on the filesystem in a temporary
> > > > > directory and then an environment variable is set to signal to libpq /
> > > > > the Kerberos libraries that the delegated credentials can be found in
> > > > > the temporary file.  I don't see any of that happening in this patch-
> > > is
> > > > > that already handled in some way?  If not, what's the plan for making
> > > > > that work?  Also important is to make sure that this approach will work
> > > > > for constrainted delegation implementations.
> > > >
> > > > Phase 1 of this project (which this patch aims to implement) is to handle
> > > > Kerberos logins to pgAdmin when running in server mode (as we’ve already
> > > > done for LDAP, except KRB authenticated users don’t see a login page of
> > > > course). Phase 2 will add support for logging into the PostgreSQL
> > > servers -
> > > > I believe that is where we’ll need to handle delegated credentials,
> > > correct?
> > >
> > > Yes, though I sure hope there isn't a plan to release just 'phase 1'
> > > since that would imply that the user is still sending their password to
> > > pgAdmin in some form that pgAdmin then turns around and impersonates the
> > > user, basically completely against how Kerberos auth should be working
> > > in this kind of a intermediate service arrangement.
> > >
> > > In other words, if just 'phase 1' is released, it'd probably be CVE
> > > worthy right out of the gate...
> >
> > It wouldn’t impersonate the user at all, it would just work as it does now,
> > requiring the user to supply a username/password for scram/md5/ldap etc, or
> > a cert for SSL auth. Connection to a PostgreSQL server which required gss
> > or sspi simply wouldn’t work (unless the service account under which the
> > pgAdmin server is running has a valid ticket through other means).
>
> That *is* impersonating the user..
>
> Kerberized services really should *not* be accepting a cleartext
> password to use to authenticate as the user against another service,
> which is why I'd strongly recommend against releasing with just
> 'phase 1' done.. or at least heavily caveat'ing it that this isn't
> actually real Kerberos support but is just an intermediate step that no
> one should really deploy...

AIUI that's not what's being proposed.

Correct me if I'm wrong, but I think what's said is that this phase would:

1. Allow kerberos login *to pgadmin*.
2. Do exactly *nothing* to logins to the database server.

So per (2) logins to the db server would work exactly the same as it
does today, and bear no connection to the actual KRB login at all.

One question around that though -- when I click "save password" on a
database connection in pgadmin, it gets stored on the pgadmin server.
Isn't the key used to encrypt that derived from my password?  If I'm
logging into pgadmin without a password (using kerberos),what would
that key be derived from?

-- 
 Magnus Hagander
 Me: https://www.hagander.net/
 Work: https://www.redpill-linpro.com/





^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-11 13:21  Dave Page <[email protected]>
  parent: Magnus Hagander <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-11 13:21 UTC (permalink / raw)
  To: Magnus Hagander <[email protected]>; +Cc: Stephen Frost <[email protected]>; Khushboo Vashi <[email protected]>; pgadmin-hackers

On Mon, Jan 11, 2021 at 1:15 PM Magnus Hagander <[email protected]> wrote:

> On Sun, Jan 3, 2021 at 6:31 PM Stephen Frost <[email protected]> wrote:
> >
> > Greetings,
> >
> > * Dave Page ([email protected]) wrote:
> > > On Sat, 2 Jan 2021 at 15:59, Stephen Frost <[email protected]> wrote:
> > > > * Dave Page ([email protected]) wrote:
> > > > > On Sat, 2 Jan 2021 at 15:41, Stephen Frost <[email protected]>
> wrote:
> > > > > > * Khushboo Vashi ([email protected]) wrote:
> > > > > > > Please find the attached patch to support Kerberos
> Authentication in
> > > > > > > pgAdmin RM 5457.
> > > > > > >
> > > > > > > The patch introduces a new pluggable option for Kerberos
> > > > authentication,
> > > > > > > using SPNEGO to forward kerberos tickets through a browser
> which will
> > > > > > > bypass the login page entirely if the Kerberos Authentication
> > > > succeeds.
> > > > > >
> > > > > > I've taken a (very short) look at this as it's certainly
> something that
> > > > > > I'm interested in and glad to see work is being done on it.
> > > > > >
> > > > > > I notice that 'delegated_creds' is being set but it's unclear to
> me how
> > > > > > they're actually being used (if at all), which is a very
> important part
> > > > > > of Kerberos.
> > > > > >
> > > > > > What's commonly done with mod_auth_kerb/mod_auth_gss is that the
> > > > > > delegated credentials are stored on the filesystem in a temporary
> > > > > > directory and then an environment variable is set to signal to
> libpq /
> > > > > > the Kerberos libraries that the delegated credentials can be
> found in
> > > > > > the temporary file.  I don't see any of that happening in this
> patch-
> > > > is
> > > > > > that already handled in some way?  If not, what's the plan for
> making
> > > > > > that work?  Also important is to make sure that this approach
> will work
> > > > > > for constrainted delegation implementations.
> > > > >
> > > > > Phase 1 of this project (which this patch aims to implement) is to
> handle
> > > > > Kerberos logins to pgAdmin when running in server mode (as we’ve
> already
> > > > > done for LDAP, except KRB authenticated users don’t see a login
> page of
> > > > > course). Phase 2 will add support for logging into the PostgreSQL
> > > > servers -
> > > > > I believe that is where we’ll need to handle delegated credentials,
> > > > correct?
> > > >
> > > > Yes, though I sure hope there isn't a plan to release just 'phase 1'
> > > > since that would imply that the user is still sending their password
> to
> > > > pgAdmin in some form that pgAdmin then turns around and impersonates
> the
> > > > user, basically completely against how Kerberos auth should be
> working
> > > > in this kind of a intermediate service arrangement.
> > > >
> > > > In other words, if just 'phase 1' is released, it'd probably be CVE
> > > > worthy right out of the gate...
> > >
> > > It wouldn’t impersonate the user at all, it would just work as it does
> now,
> > > requiring the user to supply a username/password for scram/md5/ldap
> etc, or
> > > a cert for SSL auth. Connection to a PostgreSQL server which required
> gss
> > > or sspi simply wouldn’t work (unless the service account under which
> the
> > > pgAdmin server is running has a valid ticket through other means).
> >
> > That *is* impersonating the user..
> >
> > Kerberized services really should *not* be accepting a cleartext
> > password to use to authenticate as the user against another service,
> > which is why I'd strongly recommend against releasing with just
> > 'phase 1' done.. or at least heavily caveat'ing it that this isn't
> > actually real Kerberos support but is just an intermediate step that no
> > one should really deploy...
>
> AIUI that's not what's being proposed.
>
> Correct me if I'm wrong, but I think what's said is that this phase would:
>
> 1. Allow kerberos login *to pgadmin*.
> 2. Do exactly *nothing* to logins to the database server.
>
> So per (2) logins to the db server would work exactly the same as it
> does today, and bear no connection to the actual KRB login at all.
>

Correct.


>
> One question around that though -- when I click "save password" on a
> database connection in pgadmin, it gets stored on the pgadmin server.
> Isn't the key used to encrypt that derived from my password?  If I'm
> logging into pgadmin without a password (using kerberos),what would
> that key be derived from?
>

Also correct - and right now, the plan is to disable password saving if
logged in using Kerberos.

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-11 16:50  Stephen Frost <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Stephen Frost @ 2021-01-11 16:50 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Khushboo Vashi <[email protected]>; pgadmin-hackers

Greetings,

* Dave Page ([email protected]) wrote:
> On Mon, Jan 11, 2021 at 1:15 PM Magnus Hagander <[email protected]> wrote:
> > One question around that though -- when I click "save password" on a
> > database connection in pgadmin, it gets stored on the pgadmin server.
> > Isn't the key used to encrypt that derived from my password?  If I'm
> > logging into pgadmin without a password (using kerberos),what would
> > that key be derived from?
> 
> Also correct - and right now, the plan is to disable password saving if
> logged in using Kerberos.

Disable password *saving*, or disable password *using*?

If you're saying that, when Kerberos is enabled, users will never be
prompted to provide a password because password-based auth has been
disabled, then perhaps that's reasonable.  I don't know how useful such
a pgadmin setup would be, but at least it wouldn't be violating one of
the core values that using Kerberos brings.

If you're saying that this is just disabling password *saving*, then
that implies that if someone actually wants to use pgadmin to, uh, log
into a PostgreSQL server which is configured for md5 or SCRAM auth or
LDAP based auth that the way that'll work is that pgadmin will prompt
the user for a password, which the user will provide and which will
then be sent from the client to the pgadmin system in the clear, and
which pgadmin will turn around and use to log into PG with, right?

It's the latter than I'm concerned with because it just wouldn't be
appropriate for a Kerberized service which is set up to use Kerberos to
then prompt the user for a password.

In any case, I have a really hard time seeing this as being something
that it'd be good for the pgAdmin team to publish as "we now have
Kerberos support!" because, either way, it doesn't seem like it would be
usable in a secure manner in a Kerberized environment.  Once "phase 2"
is done (which hopefully will include both traditional credential
delegating and constrainted delegation support...), then it'll be a game
changer imv and something that everyone should be shouting from the
rooftops about and I'll be right there cheering it on too..

Thanks,

Stephen


Attachments:

  [application/pgp-signature] signature.asc (819B, 2-signature.asc)
  download

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-11 16:59  Dave Page <[email protected]>
  parent: Stephen Frost <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-11 16:59 UTC (permalink / raw)
  To: Stephen Frost <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Khushboo Vashi <[email protected]>; pgadmin-hackers

On Mon, Jan 11, 2021 at 4:50 PM Stephen Frost <[email protected]> wrote:

> Greetings,
>
> * Dave Page ([email protected]) wrote:
> > On Mon, Jan 11, 2021 at 1:15 PM Magnus Hagander <[email protected]>
> wrote:
> > > One question around that though -- when I click "save password" on a
> > > database connection in pgadmin, it gets stored on the pgadmin server.
> > > Isn't the key used to encrypt that derived from my password?  If I'm
> > > logging into pgadmin without a password (using kerberos),what would
> > > that key be derived from?
> >
> > Also correct - and right now, the plan is to disable password saving if
> > logged in using Kerberos.
>
> Disable password *saving*, or disable password *using*?
>

I'm pretty sure I wrote "saving".


>
> If you're saying that, when Kerberos is enabled, users will never be
> prompted to provide a password because password-based auth has been
> disabled, then perhaps that's reasonable.  I don't know how useful such
> a pgadmin setup would be, but at least it wouldn't be violating one of
> the core values that using Kerberos brings.
>
> If you're saying that this is just disabling password *saving*, then
> that implies that if someone actually wants to use pgadmin to, uh, log
> into a PostgreSQL server which is configured for md5 or SCRAM auth or
> LDAP based auth that the way that'll work is that pgadmin will prompt
> the user for a password, which the user will provide and which will
> then be sent from the client to the pgadmin system in the clear, and
> which pgadmin will turn around and use to log into PG with, right?
>

Yes.


>
> It's the latter than I'm concerned with because it just wouldn't be
> appropriate for a Kerberized service which is set up to use Kerberos to
> then prompt the user for a password.
>

Well you never answered my previous question about that. Why is it
appropriate for an FDW to do that, but not pgAdmin? Or for a user on a
kerberised machine to use a web browser to access a non-kerberised site? Or
frankly pretty much anything outside of a windows domain or kerberos
environment that a user inside the environment might want to use?

You basically seem to be saying that once a user logs into something using
Kerberos, *everything* else they login to from there must also be done
using Kerberos - which clearly will not be the case in the vast majority of
deployments.

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-11 17:42  Stephen Frost <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Stephen Frost @ 2021-01-11 17:42 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Khushboo Vashi <[email protected]>; pgadmin-hackers

Greetings,

* Dave Page ([email protected]) wrote:
> On Mon, Jan 11, 2021 at 4:50 PM Stephen Frost <[email protected]> wrote:
> > If you're saying that, when Kerberos is enabled, users will never be
> > prompted to provide a password because password-based auth has been
> > disabled, then perhaps that's reasonable.  I don't know how useful such
> > a pgadmin setup would be, but at least it wouldn't be violating one of
> > the core values that using Kerberos brings.
> >
> > If you're saying that this is just disabling password *saving*, then
> > that implies that if someone actually wants to use pgadmin to, uh, log
> > into a PostgreSQL server which is configured for md5 or SCRAM auth or
> > LDAP based auth that the way that'll work is that pgadmin will prompt
> > the user for a password, which the user will provide and which will
> > then be sent from the client to the pgadmin system in the clear, and
> > which pgadmin will turn around and use to log into PG with, right?
> 
> Yes.

Alright, glad I wasn't completely misunderstanding something.

> > It's the latter than I'm concerned with because it just wouldn't be
> > appropriate for a Kerberized service which is set up to use Kerberos to
> > then prompt the user for a password.
> 
> Well you never answered my previous question about that. Why is it
> appropriate for an FDW to do that, but not pgAdmin? Or for a user on a
> kerberised machine to use a web browser to access a non-kerberised site? Or
> frankly pretty much anything outside of a windows domain or kerberos
> environment that a user inside the environment might want to use?

Pretty sure I didn't say it was appropriate for an FDW to do that, it
really isn't, but FDWs are also a side feature of the overall product,
not a core component, and you have to be granted specific rights to be
able to use an FDW.

Accessing systems outside of the Kerberized environment is obviously a
different situation as you *can't* use the Kerberos credentials- and,
hopefully, everyone is using password managers and has a distinct and
different password for every service they do use outside of the
Kerberized environment.  When you're talking about a set of systems
which live inside of the Kerberized environment, however, it's simply
not sensible to ask the user to provide their *domain-level* credentials
which an attacker could use to log in as that user to the entire domain
and have complete access over their account and that's exactly what is
likely to end up being the case here because the only way to set this up
would be Kerberos for pgAdmin and LDAP for PG- at least until delegated
credentials are implemented.

> You basically seem to be saying that once a user logs into something using
> Kerberos, *everything* else they login to from there must also be done
> using Kerberos - which clearly will not be the case in the vast majority of
> deployments.

Everything else they login to from there in the same Kerberized
environment absolutely should be done using Kerberos delegated
credentials.  That's the point of Kerberos delegation.  Are you modeling
this approach based on some existing system which accepts Kerberos
logins but then *doesn't* allow use of delegated credentials to log into
other Kerberized systems from there?  Surely SSH works great with
delegated credentials, as does any website that uses mod_auth_kerb or
mod_auth_gss, or IIS..

I sure hope that the vast majority of deployments where pgAdmin is set
up with Kerberos will be using Kerberos for logging into PG with
delegated credentials, and further, that we will be *strongly*
encouraging that as otherwise you might as well use LDAP auth for all of
it and accept that any compromise of the web server or of PG will result
in complete compromise of any user's account who accesses the system.

I don't understand all this push-back.

The intent is to do the 'phase 2', right?  And it hopefully will happen
in relatively short order, no?  At least, I'd think it would make sense,
while people have developer environments set up and working with
Kerberos to go ahead and get that part done.  All I'm saying is that the
'phase 1' part really shouldn't be independently released, or if it is,
it should be *heavily* caveated that it is strongly discouraged for
people to run it in an environment where pgadmin and PG are in the same
Kerberized environment because it's not possible to set that up, with
just phase 1 done, in a manner which would avoid the pgadmin and PG
servers seeing the user's password.

Thanks,

Stephen


Attachments:

  [application/pgp-signature] signature.asc (819B, 2-signature.asc)
  download

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-12 09:08  Dave Page <[email protected]>
  parent: Stephen Frost <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-12 09:08 UTC (permalink / raw)
  To: Stephen Frost <[email protected]>; +Cc: Magnus Hagander <[email protected]>; Khushboo Vashi <[email protected]>; pgadmin-hackers

Hi

On Mon, Jan 11, 2021 at 5:42 PM Stephen Frost <[email protected]> wrote:

>
> Accessing systems outside of the Kerberized environment is obviously a
> different situation as you *can't* use the Kerberos credentials- and,
> hopefully, everyone is using password managers and has a distinct and
> different password for every service they do use outside of the
> Kerberized environment.  When you're talking about a set of systems
> which live inside of the Kerberized environment, however, it's simply
> not sensible to ask the user to provide their *domain-level* credentials
> which an attacker could use to log in as that user to the entire domain
> and have complete access over their account and that's exactly what is
> likely to end up being the case here because the only way to set this up
> would be Kerberos for pgAdmin and LDAP for PG- at least until delegated
> credentials are implemented.
>

Which is no worse than the current situation - in fact it's arguably better
because there's one less system that isn't Kerberised.

Don't forget, you (as the system administrator) also have the choice of
whether or not to use Kerberos. If you're not happy to have the pgAdmin
authentication be kerberised whilst the database server access is not, then
don't enable Kerberos until phase 2 is complete.


>
> > You basically seem to be saying that once a user logs into something
> using
> > Kerberos, *everything* else they login to from there must also be done
> > using Kerberos - which clearly will not be the case in the vast majority
> of
> > deployments.
>
> Everything else they login to from there in the same Kerberized
> environment absolutely should be done using Kerberos delegated
> credentials.  That's the point of Kerberos delegation.  Are you modeling
> this approach based on some existing system which accepts Kerberos
> logins but then *doesn't* allow use of delegated credentials to log into
> other Kerberized systems from there?  Surely SSH works great with
> delegated credentials, as does any website that uses mod_auth_kerb or
> mod_auth_gss, or IIS..
>
> I sure hope that the vast majority of deployments where pgAdmin is set
> up with Kerberos will be using Kerberos for logging into PG with
> delegated credentials, and further, that we will be *strongly*
> encouraging that as otherwise you might as well use LDAP auth for all of
> it and accept that any compromise of the web server or of PG will result
> in complete compromise of any user's account who accesses the system.
>

I suspect that may not be the case, or at least most people will be working
in mixed environments, e.g. Kerberos on their local network with
non-Kerberised RDS servers for example. This is certainly something I've
seen in the field many times.


>
> I don't understand all this push-back.
>

There are benefits for some users with phase one alone, so I don't see (and
still don't) a need to hold it back. It also potentially allows us to get
feedback on things that don't work as expected earlier, to minimise any
re-work that might be required. Don't forget that pgAdmin releases monthly
(except around EOY for obvious reasons), and incrementally releases and
adds features, unlike PostgreSQL.


>
> The intent is to do the 'phase 2', right?  And it hopefully will happen
> in relatively short order, no?  At least, I'd think it would make sense,
> while people have developer environments set up and working with
> Kerberos to go ahead and get that part done.  All I'm saying is that the
> 'phase 1' part really shouldn't be independently released, or if it is,
> it should be *heavily* caveated that it is strongly discouraged for
> people to run it in an environment where pgadmin and PG are in the same
> Kerberized environment because it's not possible to set that up, with
> just phase 1 done, in a manner which would avoid the pgadmin and PG
> servers seeing the user's password.
>

Phase 2 is scheduled to be done immediately.

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-12 10:04  Magnus Hagander <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 0 replies; 32+ messages in thread

From: Magnus Hagander @ 2021-01-12 10:04 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Stephen Frost <[email protected]>; Khushboo Vashi <[email protected]>; pgadmin-hackers

On Tue, Jan 12, 2021 at 10:08 AM Dave Page <[email protected]> wrote:
>
> Hi
>
> On Mon, Jan 11, 2021 at 5:42 PM Stephen Frost <[email protected]> wrote:
>>
>>
>> Accessing systems outside of the Kerberized environment is obviously a
>> different situation as you *can't* use the Kerberos credentials- and,
>> hopefully, everyone is using password managers and has a distinct and
>> different password for every service they do use outside of the
>> Kerberized environment.  When you're talking about a set of systems
>> which live inside of the Kerberized environment, however, it's simply
>> not sensible to ask the user to provide their *domain-level* credentials
>> which an attacker could use to log in as that user to the entire domain
>> and have complete access over their account and that's exactly what is
>> likely to end up being the case here because the only way to set this up
>> would be Kerberos for pgAdmin and LDAP for PG- at least until delegated
>> credentials are implemented.
>
>
> Which is no worse than the current situation - in fact it's arguably better because there's one less system that isn't Kerberised.
>
> Don't forget, you (as the system administrator) also have the choice of whether or not to use Kerberos. If you're not happy to have the pgAdmin authentication be kerberised whilst the database server access is not, then don't enable Kerberos until phase 2 is complete.
>
>>
>>
>> > You basically seem to be saying that once a user logs into something using
>> > Kerberos, *everything* else they login to from there must also be done
>> > using Kerberos - which clearly will not be the case in the vast majority of
>> > deployments.
>>
>> Everything else they login to from there in the same Kerberized
>> environment absolutely should be done using Kerberos delegated
>> credentials.  That's the point of Kerberos delegation.  Are you modeling
>> this approach based on some existing system which accepts Kerberos
>> logins but then *doesn't* allow use of delegated credentials to log into
>> other Kerberized systems from there?  Surely SSH works great with
>> delegated credentials, as does any website that uses mod_auth_kerb or
>> mod_auth_gss, or IIS..
>>
>> I sure hope that the vast majority of deployments where pgAdmin is set
>> up with Kerberos will be using Kerberos for logging into PG with
>> delegated credentials, and further, that we will be *strongly*
>> encouraging that as otherwise you might as well use LDAP auth for all of
>> it and accept that any compromise of the web server or of PG will result
>> in complete compromise of any user's account who accesses the system.
>
>
> I suspect that may not be the case, or at least most people will be working in mixed environments, e.g. Kerberos on their local network with non-Kerberised RDS servers for example. This is certainly something I've seen in the field many times.

+1. I can see a lot of cases where people would like to benefit from
the *convenience* of Kerberos login into their pgadmin, and then
continue to use a db connection that does not use Kerberos. There's
many orgs that for example have a policy that says they *must* use
passwords in to the db regardless of Kerbeos. We can argue whether
that's a smart policy or not, but it's very real, and those people
would still be able to benefit from a Kerberos login into pgadmin.

Getting those people to do kerberos into pgadmin and then password
intot he database would be a strong improvement over ldap to pgadmin
and password into the database. Sure, if the ldap password and the db
password is the same the difference isn't that big, but more often
than not the db password is independent.

RDS is a good example of this, but there are definitely plenty of
non-cloud environments who would also benefit fro that.


>> I don't understand all this push-back.
>
>
> There are benefits for some users with phase one alone, so I don't see (and still don't) a need to hold it back. It also potentially allows us to get feedback on things that don't work as expected earlier, to minimise any re-work that might be required. Don't forget that pgAdmin releases monthly (except around EOY for obvious reasons), and incrementally releases and adds features, unlike PostgreSQL.
>
>>
>>
>> The intent is to do the 'phase 2', right?  And it hopefully will happen
>> in relatively short order, no?  At least, I'd think it would make sense,
>> while people have developer environments set up and working with
>> Kerberos to go ahead and get that part done.  All I'm saying is that the
>> 'phase 1' part really shouldn't be independently released, or if it is,
>> it should be *heavily* caveated that it is strongly discouraged for
>> people to run it in an environment where pgadmin and PG are in the same
>> Kerberized environment because it's not possible to set that up, with
>> just phase 1 done, in a manner which would avoid the pgadmin and PG
>> servers seeing the user's password.
>
>
> Phase 2 is scheduled to be done immediately.

\o/


-- 
 Magnus Hagander
 Me: https://www.hagander.net/
 Work: https://www.redpill-linpro.com/





^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-13 09:05  Khushboo Vashi <[email protected]>
  parent: Aditya Toshniwal <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Khushboo Vashi @ 2021-01-13 09:05 UTC (permalink / raw)
  To: Aditya Toshniwal <[email protected]>; +Cc: Akshay Joshi <[email protected]>; pgadmin-hackers

Hi,

Please find the attached updated patch.

Thanks,
Khushboo

On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
[email protected]> wrote:

> Hi Khushboo,
>
> I've just done the code review. Apart from below, the patch looks good to
> me:
>
> 1) Move the auth source constants -ldap, kerberos out of app object. They
> don't belong there. You can create the constants somewhere else and import
> them.
>
> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>
> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>
>
> Done

> 2) Are we going to make kerberos default for wsgi ?
>
> *--- a/web/pgAdmin4.wsgi*
>
> *+++ b/web/pgAdmin4.wsgi*
>
> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>
>
>
>  import config
>
>
>
> +
>
> +config.AUTHENTICATION_SOURCES = ['kerberos']
>
> +config.KERBEROS_AUTO_CREATE_USER = True
>
> +
>
>
> Removed, it was only for testing.

> 3) Remove the commented code.
>
> +            # if self.form.data['email'] and self.form.data['password']
> and \
>
> +            #         source.get_source_name() ==\
>
> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>
> +            #     continue
>
>
> Removed the comment, it is actually the part of the code.

> 4) KERBEROSAuthentication could be KerberosAuthentication
>
> class KERBEROSAuthentication(BaseAuthentication):
>
>
> Done.

> 5) You can use the constants (ldap, kerberos) you had defined when
> creating a user.
>
> +                    'auth_source': 'kerberos'
>
>
> Done.

> 6) The below URLs belong to the authenticate module. Currently they are in
> the browser module. I would also suggest rephrasing the URL from
> /kerberos_login to /login/kerberos. Same for logout.
>
Done the rephrasing as well as moved to the authentication module.


> Also, even though the method GET works, we should use the POST method for
> login and DELETE for logout.
>
Kerberos_login just redirects the page to the actual login, so no need for
the POST method.
I followed the same method for the Logout user we have used for the normal
user.


> [email protected]("/kerberos_login",
>
> +                 endpoint="kerberos_login", methods=["GET"])
>
>
> [email protected]("/kerberos_logout",
>
> +                 endpoint="kerberos_logout", methods=["GET"])
>
>
>
>

> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
> [email protected]> wrote:
>
>> Hi Aditya
>>
>> Can you please do the code review?
>>
>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>> Please find the attached patch to support Kerberos Authentication in
>>> pgAdmin RM 5457.
>>>
>>> The patch introduces a new pluggable option for Kerberos authentication,
>>> using SPNEGO to forward kerberos tickets through a browser which will
>>> bypass the login page entirely if the Kerberos Authentication succeeds.
>>>
>>> The complete setup of the Kerberos Server + pgAdmin Server + Client is
>>> documented in a separate file and attached.
>>>
>>> This patch also includes the small fix related to logging #5829
>>>
>>> Thanks,
>>> Khushboo
>>>
>>
>>
>> --
>> *Thanks & Regards*
>> *Akshay Joshi*
>> *pgAdmin Hacker | Principal Software Architect*
>> *EDB Postgres <http://edbpostgres.com>*
>>
>> *Mobile: +91 976-788-8246*
>>
>
>
> --
> Thanks,
> Aditya Toshniwal
> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
> <http://edbpostgres.com;
> "Don't Complain about Heat, Plant a TREE"
>


Attachments:

  [application/octet-stream] RM_5457_v1.patch (1.4K, 3-RM_5457_v1.patch)
  download | inline diff:
diff --git a/web/pgadmin/static/js/sqleditor/macro.js b/web/pgadmin/static/js/sqleditor/macro.js
index c8f9292f3..da4f3b4c7 100644
--- a/web/pgadmin/static/js/sqleditor/macro.js
+++ b/web/pgadmin/static/js/sqleditor/macro.js
@@ -272,11 +272,12 @@ let MacroDialog = {
                           <a class="dropdown-item" id="btn-manage-macros" href="#" tabindex="0">
                               <span> ${gettext('Manage Macros...')} </span>
                           </a>
-                      </li>
-                      <li class="dropdown-divider"></li>`;
+                      </li>`;
+
+                    let macro_list_tmpl = '';
                     _.each(macros, function(m) {
                       if (m.name) {
-                        str += `<li>
+                        macro_list_tmpl += `<li>
                         <a class="dropdown-item btn-macro" data-macro-id="${m.id}" href="#" tabindex="0">
                             <span> ${_.escape(m.name)} </span>
                             <span> (${m.key_label}) </span>
@@ -285,6 +286,7 @@ let MacroDialog = {
                       }
                     });
 
+                    if (macro_list_tmpl.length > 0) str += '<li class="dropdown-divider"></li>' + macro_list_tmpl;
                     $($.find('div.btn-group.mr-1.user_macros ul.dropdown-menu')).html($(str));
 
                     self.close(); // Close the dialog now


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-14 06:30  Akshay Joshi <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Akshay Joshi @ 2021-01-14 06:30 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: Aditya Toshniwal <[email protected]>; pgadmin-hackers

Hi Khushboo

Seems you have attached the wrong patch. Please send the updated patch.

On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
[email protected]> wrote:

> Hi,
>
> Please find the attached updated patch.
>
> Thanks,
> Khushboo
>
> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
> [email protected]> wrote:
>
>> Hi Khushboo,
>>
>> I've just done the code review. Apart from below, the patch looks good to
>> me:
>>
>> 1) Move the auth source constants -ldap, kerberos out of app object. They
>> don't belong there. You can create the constants somewhere else and import
>> them.
>>
>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>
>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>
>>
>> Done
>
>> 2) Are we going to make kerberos default for wsgi ?
>>
>> *--- a/web/pgAdmin4.wsgi*
>>
>> *+++ b/web/pgAdmin4.wsgi*
>>
>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>
>>
>>
>>  import config
>>
>>
>>
>> +
>>
>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>
>> +config.KERBEROS_AUTO_CREATE_USER = True
>>
>> +
>>
>>
>> Removed, it was only for testing.
>
>> 3) Remove the commented code.
>>
>> +            # if self.form.data['email'] and self.form.data['password']
>> and \
>>
>> +            #         source.get_source_name() ==\
>>
>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>
>> +            #     continue
>>
>>
>> Removed the comment, it is actually the part of the code.
>
>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>
>> class KERBEROSAuthentication(BaseAuthentication):
>>
>>
>> Done.
>
>> 5) You can use the constants (ldap, kerberos) you had defined when
>> creating a user.
>>
>> +                    'auth_source': 'kerberos'
>>
>>
>> Done.
>
>> 6) The below URLs belong to the authenticate module. Currently they are
>> in the browser module. I would also suggest rephrasing the URL from
>> /kerberos_login to /login/kerberos. Same for logout.
>>
> Done the rephrasing as well as moved to the authentication module.
>
>
>> Also, even though the method GET works, we should use the POST method for
>> login and DELETE for logout.
>>
> Kerberos_login just redirects the page to the actual login, so no need for
> the POST method.
> I followed the same method for the Logout user we have used for the normal
> user.
>
>
>> [email protected]("/kerberos_login",
>>
>> +                 endpoint="kerberos_login", methods=["GET"])
>>
>>
>> [email protected]("/kerberos_logout",
>>
>> +                 endpoint="kerberos_logout", methods=["GET"])
>>
>>
>>
>>
>
>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>> [email protected]> wrote:
>>
>>> Hi Aditya
>>>
>>> Can you please do the code review?
>>>
>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>> [email protected]> wrote:
>>>
>>>> Hi,
>>>>
>>>> Please find the attached patch to support Kerberos Authentication in
>>>> pgAdmin RM 5457.
>>>>
>>>> The patch introduces a new pluggable option for Kerberos
>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>> succeeds.
>>>>
>>>> The complete setup of the Kerberos Server + pgAdmin Server + Client is
>>>> documented in a separate file and attached.
>>>>
>>>> This patch also includes the small fix related to logging #5829
>>>>
>>>> Thanks,
>>>> Khushboo
>>>>
>>>
>>>
>>> --
>>> *Thanks & Regards*
>>> *Akshay Joshi*
>>> *pgAdmin Hacker | Principal Software Architect*
>>> *EDB Postgres <http://edbpostgres.com>*
>>>
>>> *Mobile: +91 976-788-8246*
>>>
>>
>>
>> --
>> Thanks,
>> Aditya Toshniwal
>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>> <http://edbpostgres.com;
>> "Don't Complain about Heat, Plant a TREE"
>>
>

-- 
*Thanks & Regards*
*Akshay Joshi*
*pgAdmin Hacker | Principal Software Architect*
*EDB Postgres <http://edbpostgres.com>*

*Mobile: +91 976-788-8246*


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-14 06:47  Khushboo Vashi <[email protected]>
  parent: Akshay Joshi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Khushboo Vashi @ 2021-01-14 06:47 UTC (permalink / raw)
  To: Akshay Joshi <[email protected]>; +Cc: Aditya Toshniwal <[email protected]>; pgadmin-hackers

Hi,

Please find the attached updated patch.

Thanks,
Khushboo

On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <[email protected]>
wrote:

> Hi Khushboo
>
> Seems you have attached the wrong patch. Please send the updated patch.
>
> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
> [email protected]> wrote:
>
>> Hi,
>>
>> Please find the attached updated patch.
>>
>> Thanks,
>> Khushboo
>>
>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>> [email protected]> wrote:
>>
>>> Hi Khushboo,
>>>
>>> I've just done the code review. Apart from below, the patch looks good
>>> to me:
>>>
>>> 1) Move the auth source constants -ldap, kerberos out of app object.
>>> They don't belong there. You can create the constants somewhere else and
>>> import them.
>>>
>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>
>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>
>>>
>>> Done
>>
>>> 2) Are we going to make kerberos default for wsgi ?
>>>
>>> *--- a/web/pgAdmin4.wsgi*
>>>
>>> *+++ b/web/pgAdmin4.wsgi*
>>>
>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>
>>>
>>>
>>>  import config
>>>
>>>
>>>
>>> +
>>>
>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>
>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>
>>> +
>>>
>>>
>>> Removed, it was only for testing.
>>
>>> 3) Remove the commented code.
>>>
>>> +            # if self.form.data['email'] and
>>> self.form.data['password'] and \
>>>
>>> +            #         source.get_source_name() ==\
>>>
>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>
>>> +            #     continue
>>>
>>>
>>> Removed the comment, it is actually the part of the code.
>>
>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>
>>> class KERBEROSAuthentication(BaseAuthentication):
>>>
>>>
>>> Done.
>>
>>> 5) You can use the constants (ldap, kerberos) you had defined when
>>> creating a user.
>>>
>>> +                    'auth_source': 'kerberos'
>>>
>>>
>>> Done.
>>
>>> 6) The below URLs belong to the authenticate module. Currently they are
>>> in the browser module. I would also suggest rephrasing the URL from
>>> /kerberos_login to /login/kerberos. Same for logout.
>>>
>> Done the rephrasing as well as moved to the authentication module.
>>
>>
>>> Also, even though the method GET works, we should use the POST method
>>> for login and DELETE for logout.
>>>
>> Kerberos_login just redirects the page to the actual login, so no need
>> for the POST method.
>> I followed the same method for the Logout user we have used for the
>> normal user.
>>
>>
>>> [email protected]("/kerberos_login",
>>>
>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>
>>>
>>> [email protected]("/kerberos_logout",
>>>
>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>
>>>
>>>
>>>
>>
>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>> [email protected]> wrote:
>>>
>>>> Hi Aditya
>>>>
>>>> Can you please do the code review?
>>>>
>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Please find the attached patch to support Kerberos Authentication in
>>>>> pgAdmin RM 5457.
>>>>>
>>>>> The patch introduces a new pluggable option for Kerberos
>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>> succeeds.
>>>>>
>>>>> The complete setup of the Kerberos Server + pgAdmin Server + Client is
>>>>> documented in a separate file and attached.
>>>>>
>>>>> This patch also includes the small fix related to logging #5829
>>>>>
>>>>> Thanks,
>>>>> Khushboo
>>>>>
>>>>
>>>>
>>>> --
>>>> *Thanks & Regards*
>>>> *Akshay Joshi*
>>>> *pgAdmin Hacker | Principal Software Architect*
>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>
>>>> *Mobile: +91 976-788-8246*
>>>>
>>>
>>>
>>> --
>>> Thanks,
>>> Aditya Toshniwal
>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>> <http://edbpostgres.com;
>>> "Don't Complain about Heat, Plant a TREE"
>>>
>>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
> *pgAdmin Hacker | Principal Software Architect*
> *EDB Postgres <http://edbpostgres.com>*
>
> *Mobile: +91 976-788-8246*
>


Attachments:

  [application/octet-stream] RM_5457_v2.patch (37.7K, 3-RM_5457_v2.patch)
  download | inline diff:
diff --git a/web/config.py b/web/config.py
index 2b314fe69..d02a91380 100644
--- a/web/config.py
+++ b/web/config.py
@@ -535,7 +535,7 @@ ENHANCED_COOKIE_PROTECTION = True
 ##########################################################################
 
 # Default setting is internal
-# External Supported Sources: ldap
+# External Supported Sources: ldap, kerberos
 # Multiple authentication can be achieved by setting this parameter to
 # ['ldap', 'internal']. pgAdmin will authenticate the user with ldap first,
 # in case of failure internal authentication will be done.
@@ -618,6 +618,26 @@ LDAP_CA_CERT_FILE = ''
 LDAP_CERT_FILE = ''
 LDAP_KEY_FILE = ''
 
+
+##########################################################################
+# Kerberos Configuration
+##########################################################################
+
+KRB_APP_HOST_NAME = DEFAULT_SERVER
+
+# If the default_keytab_name is not set in krb5.conf or
+# the KRB_KTNAME environment variable is not set then, explicitly set
+# the Keytab file
+
+KRB_KTNAME = '<KRB5_KEYTAB_FILE>'
+
+# After kerberos authentication, user will be added into the SQLite database
+# automatically, if set to True.
+# Set it to False, if user should not be added automatically,
+# in this case Admin has to add the user manually in the SQLite database.
+
+KRB_AUTO_CREATE_USER = True
+
 ##########################################################################
 # Local config settings
 ##########################################################################
diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py
index ff9c00f50..14afe7dc1 100644
--- a/web/pgAdmin4.py
+++ b/web/pgAdmin4.py
@@ -35,6 +35,9 @@ else:
 import config
 from pgadmin import create_app
 from pgadmin.utils import u_encode, fs_encoding, file_quote
+from pgadmin.utils.constants import INTERNAL, LDAP,\
+    KERBEROS, SUPPORTED_AUTH_SOURCES
+
 # Get the config database schema version. We store this in pgadmin.model
 # as it turns out that putting it in the config files isn't a great idea
 from pgadmin.model import SCHEMA_VERSION
@@ -96,15 +99,11 @@ if config.SERVER_MODE:
     app.wsgi_app = ReverseProxied(app.wsgi_app)
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
-app.PGADMIN_SUPPORTED_AUTH_SOURCE = ['internal', 'ldap']
+
 if len(config.AUTHENTICATION_SOURCES) > 0:
     app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
 else:
-    app.PGADMIN_EXTERNAL_AUTH_SOURCE = app.PGADMIN_DEFAULT_AUTH_SOURCE
-
-app.logger.debug(
-    "Authentication Source: %s" % app.PGADMIN_DEFAULT_AUTH_SOURCE)
+    app.PGADMIN_EXTERNAL_AUTH_SOURCE = INTERNAL
 
 # Start the web server. The port number should have already been set by the
 # runtime if we're running in desktop mode, otherwise we'll just use the
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index dae0b8cd2..a73335371 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -43,6 +43,7 @@ from pgadmin.utils.ajax import internal_server_error, make_json_response
 from pgadmin.utils.csrf import pgCSRFProtect
 from pgadmin import authenticate
 from pgadmin.utils.security_headers import SecurityHeaders
+from pgadmin.utils.constants import KERBEROS
 
 # Explicitly set the mime-types so that a corrupted windows registry will not
 # affect pgAdmin 4 to be load properly. This will avoid the issues that may
@@ -674,6 +675,7 @@ def create_app(app_name=None):
 
         # Check the auth key is valid, if it's set, and we're not in server
         # mode, and it's not a help file request.
+
         if not config.SERVER_MODE and app.PGADMIN_INT_KEY != '' and ((
             'key' not in request.args or
             request.args['key'] != app.PGADMIN_INT_KEY) and
@@ -695,11 +697,19 @@ def create_app(app_name=None):
                 )
                 abort(401)
             login_user(user)
+        elif config.SERVER_MODE and\
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE ==\
+                KERBEROS and \
+                not current_user.is_authenticated and \
+                request.endpoint in ('redirects.index', 'security.login'):
+            return authenticate.login()
 
         # if the server is restarted the in memory key will be lost
         # but the user session may still be active. Logout the user
         # to get the key again when login
         if config.SERVER_MODE and current_user.is_authenticated and \
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE != \
+                KERBEROS and \
                 current_app.keyManager.get() is None and \
                 request.endpoint not in ('security.login', 'security.logout'):
             logout_user()
diff --git a/web/pgadmin/authenticate/__init__.py b/web/pgadmin/authenticate/__init__.py
index 7ede73cd8..1fdb66cf7 100644
--- a/web/pgadmin/authenticate/__init__.py
+++ b/web/pgadmin/authenticate/__init__.py
@@ -11,16 +11,21 @@
 
 import flask
 import pickle
-from flask import current_app, flash
+from flask import current_app, flash, Response, request, url_for,\
+    render_template
 from flask_babelex import gettext
 from flask_security import current_user
 from flask_security.views import _security, _ctx
 from flask_security.utils import config_value, get_post_logout_redirect, \
-    get_post_login_redirect
+    get_post_login_redirect, logout_user
+
 from flask import session
 
 import config
 from pgadmin.utils import PgAdminModule
+from pgadmin.utils.constants import KERBEROS
+from pgadmin.utils.csrf import pgCSRFProtect
+
 from .registry import AuthSourceRegistry
 
 MODULE_NAME = 'authenticate'
@@ -28,12 +33,34 @@ MODULE_NAME = 'authenticate'
 
 class AuthenticateModule(PgAdminModule):
     def get_exposed_url_endpoints(self):
-        return ['authenticate.login']
+        return ['authenticate.login',
+                'authenticate.kerberos_login',
+                'authenticate.kerberos_logout']
 
 
 blueprint = AuthenticateModule(MODULE_NAME, __name__, static_url_path='')
 
 
[email protected]("/login/kerberos",
+                 endpoint="kerberos_login", methods=["GET"])
[email protected]
+def kerberos_login():
+    logout_user()
+    return Response(render_template("browser/kerberos_login.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
[email protected]("/logout/kerberos",
+                 endpoint="kerberos_logout", methods=["GET"])
[email protected]
+def kerberos_logout():
+    logout_user()
+    return Response(render_template("browser/kerberos_logout.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
 @blueprint.route('/login', endpoint='login', methods=['GET', 'POST'])
 def login():
     """
@@ -56,15 +83,24 @@ def login():
     if status:
         # Login the user
         status, msg = auth_obj.login()
+        current_auth_obj = auth_obj.as_dict()
         if not status:
+            if current_auth_obj['current_source'] ==\
+                    KERBEROS:
+                return flask.redirect('{0}?next={1}'.format(url_for(
+                    'authenticate.kerberos_login'), url_for('browser.index')))
+
             flash(gettext(msg), 'danger')
             return flask.redirect(get_post_logout_redirect())
 
-        session['_auth_source_manager_obj'] = auth_obj.as_dict()
+        session['_auth_source_manager_obj'] = current_auth_obj
         return flask.redirect(get_post_login_redirect())
 
+    elif isinstance(msg, Response):
+        return msg
     flash(gettext(msg), 'danger')
-    return flask.redirect(get_post_logout_redirect())
+    response = flask.redirect(get_post_logout_redirect())
+    return response
 
 
 class AuthSourceManager():
@@ -75,6 +111,7 @@ class AuthSourceManager():
         self.auth_sources = sources
         self.source = None
         self.source_friendly_name = None
+        self.current_source = None
 
     def as_dict(self):
         """
@@ -84,9 +121,17 @@ class AuthSourceManager():
         res = dict()
         res['source_friendly_name'] = self.source_friendly_name
         res['auth_sources'] = self.auth_sources
+        res['current_source'] = self.current_source
 
         return res
 
+    def set_current_source(self, source):
+        self.current_source = source
+
+    @property
+    def get_current_source(self, source):
+        return self.current_source
+
     def set_source(self, source):
         self.source = source
 
@@ -115,9 +160,33 @@ class AuthSourceManager():
         msg = None
         for src in self.auth_sources:
             source = get_auth_sources(src)
+            current_app.logger.debug(
+                "Authentication initiated via source: %s" %
+                source.get_source_name())
+
+            if self.form.data['email'] and self.form.data['password'] and \
+                    source.get_source_name() == KERBEROS:
+                continue
+
             status, msg = source.authenticate(self.form)
+
+            # When server sends Unauthorized header to get the ticket over HTTP
+            # OR When kerberos authentication failed while accessing pgadmin,
+            # we need to break the loop as no need to authenticate further
+            # even if the authentication sources set to multiple
+            if not status:
+                if (hasattr(msg, 'status') and
+                    msg.status == '401 UNAUTHORIZED') or\
+                        (source.get_source_name() ==
+                         KERBEROS and
+                         request.method == 'GET'):
+                    break
+
             if status:
                 self.set_source(source)
+                self.set_current_source(source.get_source_name())
+                if msg is not None and 'username' in msg:
+                    self.form._fields['email'].data = msg['username']
                 return status, msg
         return status, msg
 
@@ -125,6 +194,9 @@ class AuthSourceManager():
         status, msg = self.source.login(self.form)
         if status:
             self.set_source_friendly_name(self.source.get_friendly_name())
+            current_app.logger.debug(
+                "Authentication and Login successfully done via source : %s" %
+                self.source.get_source_name())
         return status, msg
 
 
diff --git a/web/pgadmin/authenticate/internal.py b/web/pgadmin/authenticate/internal.py
index 804a487c7..484a7fdca 100644
--- a/web/pgadmin/authenticate/internal.py
+++ b/web/pgadmin/authenticate/internal.py
@@ -18,6 +18,7 @@ from flask_babelex import gettext
 from .registry import AuthSourceRegistry
 from pgadmin.model import User
 from pgadmin.utils.validation_utils import validate_email
+from pgadmin.utils.constants import INTERNAL
 
 
 @six.add_metaclass(AuthSourceRegistry)
@@ -31,7 +32,11 @@ class BaseAuthentication(object):
         'INVALID_EMAIL': gettext('Email/Username is not valid')
     }
 
-    @abstractproperty
+    @abstractmethod
+    def get_source_name(self):
+        pass
+
+    @abstractmethod
     def get_friendly_name(self):
         pass
 
@@ -82,6 +87,9 @@ class BaseAuthentication(object):
 
 class InternalAuthentication(BaseAuthentication):
 
+    def get_source_name(self):
+        return INTERNAL
+
     def get_friendly_name(self):
         return gettext("internal")
 
diff --git a/web/pgadmin/authenticate/kerberos.py b/web/pgadmin/authenticate/kerberos.py
new file mode 100644
index 000000000..629fc7bf7
--- /dev/null
+++ b/web/pgadmin/authenticate/kerberos.py
@@ -0,0 +1,138 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the Spnego/Kerberos authentication."""
+
+import base64
+import gssapi
+from os import environ
+
+from werkzeug.datastructures import Headers
+from flask_babelex import gettext
+from flask import Flask, request, Response, session,\
+    current_app, render_template, flash
+
+import config
+from pgadmin.model import User, ServerGroup, db, Role
+from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import KERBEROS
+
+from flask_security.views import _security, _commit, _ctx
+from werkzeug.datastructures import MultiDict
+
+from .internal import BaseAuthentication
+
+
+# Set the Kerberos config file
+if config.KRB_KTNAME and config.KRB_KTNAME != '<KRB5_KEYTAB_FILE>':
+    environ['KRB5_KTNAME'] = config.KRB_KTNAME
+
+
+class KerberosAuthentication(BaseAuthentication):
+
+    def get_source_name(self):
+        return KERBEROS
+
+    def get_friendly_name(self):
+        return gettext("kerberos")
+
+    def validate(self, form):
+        return True
+
+    def authenticate(self, frm):
+        retval = [True, None]
+        negotiate = False
+        headers = Headers()
+        authorization = request.headers.get("Authorization", None)
+        form_class = _security.login_form
+
+        if request.json:
+            form = form_class(MultiDict(request.json))
+        else:
+            form = form_class()
+
+        try:
+            if authorization is not None:
+                auth_header = authorization.split()
+                if auth_header[0] == 'Negotiate':
+                    status, negotiate = self.negotiate_start(auth_header[1])
+
+                    if status:
+                        # Saving the first 15 characters of the kerberos key
+                        # to encrypt/decrypt database password
+                        session['kerberos_key'] = auth_header[1][0:15]
+                        # Create user
+                        retval = self.__auto_create_user(
+                            str(negotiate.initiator_name))
+                    elif isinstance(negotiate, Exception):
+                        flash(gettext(negotiate), 'danger')
+                        retval = [status,
+                                  Response(render_template(
+                                      "security/login_user.html",
+                                      login_user_form=form))]
+                    else:
+                        headers.add('WWW-Authenticate', 'Negotiate ' +
+                                    str(base64.b64encode(negotiate), 'utf-8'))
+                        return False, Response("Success", 200, headers)
+            else:
+                flash(gettext("Kerberos authentication failed."
+                              " Couldn't find kerberos ticket."), 'danger')
+                headers.add('WWW-Authenticate', 'Negotiate')
+                retval = [False,
+                          Response(render_template(
+                              "security/login_user.html",
+                              login_user_form=form), 401, headers)]
+        finally:
+            if negotiate is not False:
+                self.negotiate_end(negotiate)
+        return retval
+
+    def negotiate_start(self, in_token):
+        svc_princ = gssapi.Name('HTTP@%s' % config.KRB_APP_HOST_NAME,
+                                name_type=gssapi.NameType.hostbased_service)
+        cname = svc_princ.canonicalize(gssapi.MechType.kerberos)
+
+        try:
+            server_creds = gssapi.Credentials(usage='accept', name=cname)
+            context = gssapi.SecurityContext(creds=server_creds)
+            out_token = context.step(base64.b64decode(in_token))
+        except Exception as e:
+            current_app.logger.exception(e)
+            return False, e
+
+        if out_token and not context.complete:
+            return False, out_token
+        if context.complete:
+            return True, context
+        else:
+            return False, None
+
+    def negotiate_end(self, context):
+        # Free gss_cred_id_t
+        del_creds = getattr(context, 'delegated_creds', None)
+        if del_creds:
+            deleg_creds = context.delegated_creds
+            del(deleg_creds)
+
+    def __auto_create_user(self, username):
+        """Add the ldap user to the internal SQLite database."""
+        username = str(username)
+        if config.KRB_AUTO_CREATE_USER:
+            user = User.query.filter_by(
+                username=username).first()
+            if user is None:
+                return create_user({
+                    'username': username,
+                    'email': username,
+                    'role': 2,
+                    'active': True,
+                    'auth_source': KERBEROS
+                })
+
+        return True, {'username': username}
diff --git a/web/pgadmin/authenticate/ldap.py b/web/pgadmin/authenticate/ldap.py
index a9eca110f..2f0f61b7c 100644
--- a/web/pgadmin/authenticate/ldap.py
+++ b/web/pgadmin/authenticate/ldap.py
@@ -23,6 +23,7 @@ from .internal import BaseAuthentication
 from pgadmin.model import User, ServerGroup, db, Role
 from flask import current_app
 from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import LDAP
 
 
 ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
@@ -31,6 +32,9 @@ ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
 class LDAPAuthentication(BaseAuthentication):
     """Ldap Authentication Class"""
 
+    def get_source_name(self):
+        return LDAP
+
     def get_friendly_name(self):
         return gettext("ldap")
 
@@ -151,7 +155,7 @@ class LDAPAuthentication(BaseAuthentication):
                     'email': user_email,
                     'role': 2,
                     'active': True,
-                    'auth_source': 'ldap'
+                    'auth_source': LDAP
                 })
 
         return True, None
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 1bae28f9c..c0ad869a1 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -29,7 +29,7 @@ from flask_security.recoverable import reset_password_token_status, \
     generate_reset_password_token, update_password
 from flask_security.signals import reset_password_instructions_sent
 from flask_security.utils import config_value, do_flash, get_url, \
-    get_message, slash_url_suffix, login_user, send_mail
+    get_message, slash_url_suffix, login_user, send_mail, logout_user
 from flask_security.views import _security, _commit, _ctx
 from werkzeug.datastructures import MultiDict
 
@@ -47,7 +47,8 @@ from pgadmin.utils.master_password import validate_master_password, \
     set_masterpass_check_text, cleanup_master_password, get_crypt_key, \
     set_crypt_key, process_masterpass_disabled
 from pgadmin.model import User
-from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE
+from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE,\
+    INTERNAL, KERBEROS
 
 try:
     from flask_security.views import default_render_json
@@ -280,7 +281,8 @@ class BrowserModule(PgAdminModule):
                 'browser.check_master_password',
                 'browser.set_master_password',
                 'browser.reset_master_password',
-                'browser.lock_layout']
+                'browser.lock_layout'
+                ]
 
 
 blueprint = BrowserModule(MODULE_NAME, __name__)
@@ -539,6 +541,12 @@ class BrowserPluginModule(PgAdminModule):
 
 
 def _get_logout_url():
+    if config.SERVER_MODE and\
+            session['_auth_source_manager_obj']['current_source'] == \
+            KERBEROS:
+        return '{0}?next={1}'.format(url_for(
+            'authenticate.kerberos_logout'), url_for(BROWSER_INDEX))
+
     return '{0}?next={1}'.format(
         url_for('security.logout'), url_for(BROWSER_INDEX))
 
@@ -664,13 +672,18 @@ def index():
     auth_only_internal = False
     auth_source = []
 
+    session['allow_save_password'] = True
+
     if config.SERVER_MODE:
         if len(config.AUTHENTICATION_SOURCES) == 1\
-                and 'internal' in config.AUTHENTICATION_SOURCES:
+                and INTERNAL in config.AUTHENTICATION_SOURCES:
             auth_only_internal = True
         auth_source = session['_auth_source_manager_obj'][
             'source_friendly_name']
 
+        if session['_auth_source_manager_obj']['current_source'] == KERBEROS:
+            session['allow_save_password'] = False
+
     response = Response(render_template(
         MODULE_NAME + "/index.html",
         username=current_user.username,
@@ -1086,7 +1099,7 @@ if hasattr(config, 'SECURITY_RECOVERABLE') and config.SECURITY_RECOVERABLE:
             # Check the Authentication source of the User
             user = User.query.filter_by(
                 email=form.data['email'],
-                auth_source=current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+                auth_source=INTERNAL
             ).first()
 
             if user is None:
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index ecc1281a2..5daef8120 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -10,7 +10,7 @@
 import simplejson as json
 import pgadmin.browser.server_groups as sg
 from flask import render_template, request, make_response, jsonify, \
-    current_app, url_for
+    current_app, url_for, session
 from flask_babelex import gettext
 from flask_security import current_user, login_required
 from pgadmin.browser.server_groups.servers.types import ServerType
@@ -1822,7 +1822,13 @@ class ServerNode(PGChildNodeView):
                     _=gettext,
                     service=server.service,
                     prompt_tunnel_password=prompt_tunnel_password,
-                    prompt_password=prompt_password
+                    prompt_password=prompt_password,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
+                    allow_save_tunnel_password=True if
+                    config.ALLOW_SAVE_TUNNEL_PASSWORD and
+                    session['allow_save_password'] else False
                 )
             )
         else:
@@ -1836,6 +1842,9 @@ class ServerNode(PGChildNodeView):
                     errmsg=errmsg,
                     service=server.service,
                     _=gettext,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
                 )
             )
 
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
index 9b2c425e3..35f4e2a16 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
@@ -19,7 +19,7 @@
             <div class="col-sm-10">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
index 5de642f85..e34a257f2 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
@@ -15,7 +15,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_tunnel_password" name="save_tunnel_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_TUNNEL_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_tunnel_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_tunnel_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
@@ -39,7 +39,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/templates/browser/kerberos_login.html b/web/pgadmin/browser/templates/browser/kerberos_login.html
new file mode 100644
index 000000000..c112e3196
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_login.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Login Failed.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/templates/browser/kerberos_logout.html b/web/pgadmin/browser/templates/browser/kerberos_logout.html
new file mode 100644
index 000000000..430dc6f25
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_logout.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Logged out successfully.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/tests/test_kerberos_with_mocking.py b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
new file mode 100644
index 000000000..f87ce5521
--- /dev/null
+++ b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
@@ -0,0 +1,104 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import config as app_config
+from pgadmin.utils.route import BaseTestGenerator
+from regression.python_test_utils import test_utils as utils
+from pgadmin.authenticate.registry import AuthSourceRegistry
+from unittest.mock import patch, MagicMock
+
+
+class KerberosLoginMockTestCase(BaseTestGenerator):
+    """
+    This class checks Spnego/Kerberos login functionality by mocking
+    HTTP negotiate authentication.
+    """
+
+    scenarios = [
+        ('Spnego/Kerberos Authentication: Test Unauthorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=1
+        )),
+        ('Spnego/Kerberos Authentication: Test Authorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=2
+        ))
+    ]
+
+    @classmethod
+    def setUpClass(cls):
+        """
+        We need to logout the test client as we are testing
+        spnego/kerberos login scenarios.
+        """
+        cls.tester.logout()
+
+    def setUp(self):
+        app_config.AUTHENTICATION_SOURCES = self.auth_source
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'kerberos'
+
+    def runTest(self):
+        """This function checks spnego/kerberos login functionality."""
+        if self.flag == 1:
+            self.test_unauthorized()
+        elif self.flag == 2:
+            if app_config.SERVER_MODE is False:
+                self.skipTest(
+                    "Can not run Kerberos Authentication in the Desktop mode."
+                )
+
+            self.test_authorized()
+
+    def test_unauthorized(self):
+        """
+        Ensure that when client sends the first request,
+        the Negotiate request is sent.
+        """
+        res = self.tester.login(None, None, True)
+        self.assertEqual(res.status_code, 401)
+        self.assertEqual(res.headers.get('www-authenticate'), 'Negotiate')
+
+    def test_authorized(self):
+        """
+        Ensure that when the client sends an correct authorization token,
+        they receive a 200 OK response and the user principal is extracted and
+        passed on to the routed method.
+        """
+
+        class delCrads:
+            def __init__(self):
+                self.initiator_name = '[email protected]'
+        del_crads = delCrads()
+
+        AuthSourceRegistry.registry['kerberos'].negotiate_start = MagicMock(
+            return_value=[True, del_crads])
+        res = self.tester.login(None,
+                                None,
+                                True,
+                                headers={'Authorization': 'Negotiate CTOKEN'}
+                                )
+        self.assertEqual(res.status_code, 200)
+        respdata = 'Gravatar image for %s' % del_crads.initiator_name
+        self.assertTrue(respdata in res.data.decode('utf8'))
+
+    def tearDown(self):
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
+        self.tester.logout()
+
+    @classmethod
+    def tearDownClass(cls):
+        """
+        We need to again login the test client as soon as test scenarios
+        finishes.
+        """
+        cls.tester.logout()
+        app_config.AUTHENTICATION_SOURCES = ['internal']
+        utils.login_tester_account(cls.tester)
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index 2405a498d..05ed998c6 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -25,7 +25,7 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_json_response, bad_request, \
     internal_server_error, unauthorized
 
-from config import PG_DEFAULT_DRIVER
+from config import PG_DEFAULT_DRIVER, ALLOW_SAVE_PASSWORD
 from pgadmin.model import Server, User
 from pgadmin.utils.driver import get_driver
 from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost
@@ -402,6 +402,9 @@ def _init_query_tool(trans_id, connect, sgid, sid, did, **kwargs):
                             username=user,
                             errmsg=msg,
                             _=gettext,
+                            allow_save_password=True if
+                            ALLOW_SAVE_PASSWORD and
+                            session['allow_save_password'] else False,
                         )
                     ), '', ''
                 else:
diff --git a/web/pgadmin/tools/user_management/__init__.py b/web/pgadmin/tools/user_management/__init__.py
index 8641130c4..ce280a3d2 100644
--- a/web/pgadmin/tools/user_management/__init__.py
+++ b/web/pgadmin/tools/user_management/__init__.py
@@ -13,7 +13,7 @@ import simplejson as json
 import re
 
 from flask import render_template, request, \
-    url_for, Response, abort, current_app
+    url_for, Response, abort, current_app, session
 from flask_babelex import gettext as _
 from flask_security import login_required, roles_required, current_user
 from flask_security.utils import encrypt_password
@@ -24,7 +24,8 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_response as ajax_response, \
     make_json_response, bad_request, internal_server_error, forbidden
 from pgadmin.utils.csrf import pgCSRFProtect
-from pgadmin.utils.constants import MIMETYPE_APP_JS
+from pgadmin.utils.constants import MIMETYPE_APP_JS, INTERNAL,\
+    SUPPORTED_AUTH_SOURCES, KERBEROS
 from pgadmin.utils.validation_utils import validate_email
 from pgadmin.model import db, Role, User, UserPreference, Server, \
     ServerGroup, Process, Setting
@@ -167,11 +168,13 @@ def current_user_info():
                 config.SERVER_MODE is True
                 else 'postgres'
             ),
-            allow_save_password='true' if config.ALLOW_SAVE_PASSWORD
+            allow_save_password='true' if
+            config.ALLOW_SAVE_PASSWORD and session['allow_save_password']
             else 'false',
-            allow_save_tunnel_password='true'
-            if config.ALLOW_SAVE_TUNNEL_PASSWORD else 'false',
-            auth_sources=config.AUTHENTICATION_SOURCES,
+            allow_save_tunnel_password='true' if
+            config.ALLOW_SAVE_TUNNEL_PASSWORD and session[
+                'allow_save_password'] else 'false',
+            auth_sources=config.AUTHENTICATION_SOURCES
         ),
         status=200,
         mimetype=MIMETYPE_APP_JS
@@ -254,10 +257,10 @@ def _create_new_user(new_data):
     :return: Return new created user.
     """
     auth_source = new_data['auth_source'] if 'auth_source' in new_data \
-        else current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+        else INTERNAL
     username = new_data['username'] if \
         'username' in new_data and auth_source != \
-        current_app.PGADMIN_DEFAULT_AUTH_SOURCE else new_data['email']
+        INTERNAL else new_data['email']
     email = new_data['email'] if 'email' in new_data else None
     password = new_data['password'] if 'password' in new_data else None
 
@@ -279,7 +282,7 @@ def _create_new_user(new_data):
 
 def create_user(data):
     if 'auth_source' in data and data['auth_source'] != \
-            current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+            INTERNAL:
         req_params = ('username', 'role', 'active', 'auth_source')
     else:
         req_params = ('email', 'role', 'active', 'newPassword',
@@ -380,7 +383,7 @@ def update(uid):
     )
 
     # Username and email can not be changed for internal users
-    if usr.auth_source == current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+    if usr.auth_source == INTERNAL:
         non_editable_params = ('username', 'email')
 
         for f in non_editable_params:
@@ -463,7 +466,7 @@ def role(rid):
 )
 def auth_sources():
     sources = []
-    for source in current_app.PGADMIN_SUPPORTED_AUTH_SOURCE:
+    for source in SUPPORTED_AUTH_SOURCES:
         sources.append({'label': source, 'value': source})
 
     return ajax_response(
diff --git a/web/pgadmin/utils/constants.py b/web/pgadmin/utils/constants.py
index 0a2261f05..5fd942304 100644
--- a/web/pgadmin/utils/constants.py
+++ b/web/pgadmin/utils/constants.py
@@ -47,3 +47,12 @@ ERROR_FETCHING_ROLE_INFORMATION = gettext(
     'Error fetching role information from the database server.')
 
 ERROR_FETCHING_DATA = gettext('Unable to fetch data.')
+
+# Authentication Sources
+INTERNAL = 'internal'
+LDAP = 'ldap'
+KERBEROS = 'kerberos'
+
+SUPPORTED_AUTH_SOURCES = [INTERNAL,
+                          LDAP,
+                          KERBEROS]
diff --git a/web/pgadmin/utils/master_password.py b/web/pgadmin/utils/master_password.py
index 759bf36e0..629eec941 100644
--- a/web/pgadmin/utils/master_password.py
+++ b/web/pgadmin/utils/master_password.py
@@ -1,8 +1,9 @@
 import config
-from flask import current_app
+from flask import current_app, session
 from flask_login import current_user
 from pgadmin.model import db, User, Server
 from pgadmin.utils.crypto import encrypt, decrypt
+from pgadmin.utils.constants import KERBEROS
 
 
 MASTERPASS_CHECK_TEXT = 'ideas are bulletproof'
@@ -32,6 +33,11 @@ def get_crypt_key():
     elif config.MASTER_PASSWORD_REQUIRED \
             and not config.SERVER_MODE and enc_key is None:
         return False, None
+    elif config.SERVER_MODE and \
+            session['_auth_source_manager_obj']['source_friendly_name']\
+            == KERBEROS:
+        return True, session['kerberos_key'] if 'kerberos_key' in session \
+            else None
     else:
         return True, enc_key
 
diff --git a/web/regression/python_test_utils/csrf_test_client.py b/web/regression/python_test_utils/csrf_test_client.py
index 11d2cfca5..ca4120e18 100644
--- a/web/regression/python_test_utils/csrf_test_client.py
+++ b/web/regression/python_test_utils/csrf_test_client.py
@@ -101,7 +101,8 @@ class TestClient(testing.FlaskClient):
 
             return csrf_token
 
-    def login(self, email, password, _follow_redirects=False):
+    def login(self, email, password, _follow_redirects=False,
+              headers=None):
         if config.SERVER_MODE is True:
             res = self.get('/login', follow_redirects=True)
             csrf_token = self.fetch_csrf(res)
@@ -113,7 +114,8 @@ class TestClient(testing.FlaskClient):
                 email=email, password=password,
                 csrf_token=csrf_token,
             ),
-            follow_redirects=_follow_redirects
+            follow_redirects=_follow_redirects,
+            headers=headers
         )
         self.csrf_token = csrf_token
 
diff --git a/web/regression/runtests.py b/web/regression/runtests.py
index 3328ed3f6..9b794e41f 100644
--- a/web/regression/runtests.py
+++ b/web/regression/runtests.py
@@ -117,9 +117,9 @@ if config.SERVER_MODE is True:
 app.config['WTF_CSRF_ENABLED'] = True
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
 app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
 
+
 app.test_client_class = TestClient
 test_client = app.test_client()
 test_client.setApp(app)


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-14 08:12  Khushboo Vashi <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Khushboo Vashi @ 2021-01-14 08:12 UTC (permalink / raw)
  To: Akshay Joshi <[email protected]>; +Cc: Aditya Toshniwal <[email protected]>; pgadmin-hackers

Hi,

Please ignore my previous patch, attached the updated one.

Thanks,
Khushboo

On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
[email protected]> wrote:

> Hi,
>
> Please find the attached updated patch.
>
> Thanks,
> Khushboo
>
> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
> [email protected]> wrote:
>
>> Hi Khushboo
>>
>> Seems you have attached the wrong patch. Please send the updated patch.
>>
>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>> Please find the attached updated patch.
>>>
>>> Thanks,
>>> Khushboo
>>>
>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>> [email protected]> wrote:
>>>
>>>> Hi Khushboo,
>>>>
>>>> I've just done the code review. Apart from below, the patch looks good
>>>> to me:
>>>>
>>>> 1) Move the auth source constants -ldap, kerberos out of app object.
>>>> They don't belong there. You can create the constants somewhere else and
>>>> import them.
>>>>
>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>
>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>
>>>>
>>>> Done
>>>
>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>
>>>> *--- a/web/pgAdmin4.wsgi*
>>>>
>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>
>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>
>>>>
>>>>
>>>>  import config
>>>>
>>>>
>>>>
>>>> +
>>>>
>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>
>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>
>>>> +
>>>>
>>>>
>>>> Removed, it was only for testing.
>>>
>>>> 3) Remove the commented code.
>>>>
>>>> +            # if self.form.data['email'] and
>>>> self.form.data['password'] and \
>>>>
>>>> +            #         source.get_source_name() ==\
>>>>
>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>
>>>> +            #     continue
>>>>
>>>>
>>>> Removed the comment, it is actually the part of the code.
>>>
>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>
>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>
>>>>
>>>> Done.
>>>
>>>> 5) You can use the constants (ldap, kerberos) you had defined when
>>>> creating a user.
>>>>
>>>> +                    'auth_source': 'kerberos'
>>>>
>>>>
>>>> Done.
>>>
>>>> 6) The below URLs belong to the authenticate module. Currently they are
>>>> in the browser module. I would also suggest rephrasing the URL from
>>>> /kerberos_login to /login/kerberos. Same for logout.
>>>>
>>> Done the rephrasing as well as moved to the authentication module.
>>>
>>>
>>>> Also, even though the method GET works, we should use the POST method
>>>> for login and DELETE for logout.
>>>>
>>> Kerberos_login just redirects the page to the actual login, so no need
>>> for the POST method.
>>> I followed the same method for the Logout user we have used for the
>>> normal user.
>>>
>>>
>>>> [email protected]("/kerberos_login",
>>>>
>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>
>>>>
>>>> [email protected]("/kerberos_logout",
>>>>
>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>
>>>>
>>>>
>>>>
>>>
>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi Aditya
>>>>>
>>>>> Can you please do the code review?
>>>>>
>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Please find the attached patch to support Kerberos Authentication in
>>>>>> pgAdmin RM 5457.
>>>>>>
>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>> succeeds.
>>>>>>
>>>>>> The complete setup of the Kerberos Server + pgAdmin Server + Client
>>>>>> is documented in a separate file and attached.
>>>>>>
>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>
>>>>>> Thanks,
>>>>>> Khushboo
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> *Thanks & Regards*
>>>>> *Akshay Joshi*
>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>
>>>>> *Mobile: +91 976-788-8246*
>>>>>
>>>>
>>>>
>>>> --
>>>> Thanks,
>>>> Aditya Toshniwal
>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>> <http://edbpostgres.com;
>>>> "Don't Complain about Heat, Plant a TREE"
>>>>
>>>
>>
>> --
>> *Thanks & Regards*
>> *Akshay Joshi*
>> *pgAdmin Hacker | Principal Software Architect*
>> *EDB Postgres <http://edbpostgres.com>*
>>
>> *Mobile: +91 976-788-8246*
>>
>


Attachments:

  [application/octet-stream] RM_5457_v3.patch (37.9K, 3-RM_5457_v3.patch)
  download | inline diff:
diff --git a/requirements.txt b/requirements.txt
index f391c08df..25acb5332 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -43,3 +43,4 @@ cryptography<=3.0;
 sshtunnel>=0.1.5
 ldap3>=2.5.1
 Flask-BabelEx>=0.9.4
+gssapi>=1.6.11
diff --git a/web/config.py b/web/config.py
index 2b314fe69..d02a91380 100644
--- a/web/config.py
+++ b/web/config.py
@@ -535,7 +535,7 @@ ENHANCED_COOKIE_PROTECTION = True
 ##########################################################################
 
 # Default setting is internal
-# External Supported Sources: ldap
+# External Supported Sources: ldap, kerberos
 # Multiple authentication can be achieved by setting this parameter to
 # ['ldap', 'internal']. pgAdmin will authenticate the user with ldap first,
 # in case of failure internal authentication will be done.
@@ -618,6 +618,26 @@ LDAP_CA_CERT_FILE = ''
 LDAP_CERT_FILE = ''
 LDAP_KEY_FILE = ''
 
+
+##########################################################################
+# Kerberos Configuration
+##########################################################################
+
+KRB_APP_HOST_NAME = DEFAULT_SERVER
+
+# If the default_keytab_name is not set in krb5.conf or
+# the KRB_KTNAME environment variable is not set then, explicitly set
+# the Keytab file
+
+KRB_KTNAME = '<KRB5_KEYTAB_FILE>'
+
+# After kerberos authentication, user will be added into the SQLite database
+# automatically, if set to True.
+# Set it to False, if user should not be added automatically,
+# in this case Admin has to add the user manually in the SQLite database.
+
+KRB_AUTO_CREATE_USER = True
+
 ##########################################################################
 # Local config settings
 ##########################################################################
diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py
index ff9c00f50..14afe7dc1 100644
--- a/web/pgAdmin4.py
+++ b/web/pgAdmin4.py
@@ -35,6 +35,9 @@ else:
 import config
 from pgadmin import create_app
 from pgadmin.utils import u_encode, fs_encoding, file_quote
+from pgadmin.utils.constants import INTERNAL, LDAP,\
+    KERBEROS, SUPPORTED_AUTH_SOURCES
+
 # Get the config database schema version. We store this in pgadmin.model
 # as it turns out that putting it in the config files isn't a great idea
 from pgadmin.model import SCHEMA_VERSION
@@ -96,15 +99,11 @@ if config.SERVER_MODE:
     app.wsgi_app = ReverseProxied(app.wsgi_app)
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
-app.PGADMIN_SUPPORTED_AUTH_SOURCE = ['internal', 'ldap']
+
 if len(config.AUTHENTICATION_SOURCES) > 0:
     app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
 else:
-    app.PGADMIN_EXTERNAL_AUTH_SOURCE = app.PGADMIN_DEFAULT_AUTH_SOURCE
-
-app.logger.debug(
-    "Authentication Source: %s" % app.PGADMIN_DEFAULT_AUTH_SOURCE)
+    app.PGADMIN_EXTERNAL_AUTH_SOURCE = INTERNAL
 
 # Start the web server. The port number should have already been set by the
 # runtime if we're running in desktop mode, otherwise we'll just use the
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index dae0b8cd2..a73335371 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -43,6 +43,7 @@ from pgadmin.utils.ajax import internal_server_error, make_json_response
 from pgadmin.utils.csrf import pgCSRFProtect
 from pgadmin import authenticate
 from pgadmin.utils.security_headers import SecurityHeaders
+from pgadmin.utils.constants import KERBEROS
 
 # Explicitly set the mime-types so that a corrupted windows registry will not
 # affect pgAdmin 4 to be load properly. This will avoid the issues that may
@@ -674,6 +675,7 @@ def create_app(app_name=None):
 
         # Check the auth key is valid, if it's set, and we're not in server
         # mode, and it's not a help file request.
+
         if not config.SERVER_MODE and app.PGADMIN_INT_KEY != '' and ((
             'key' not in request.args or
             request.args['key'] != app.PGADMIN_INT_KEY) and
@@ -695,11 +697,19 @@ def create_app(app_name=None):
                 )
                 abort(401)
             login_user(user)
+        elif config.SERVER_MODE and\
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE ==\
+                KERBEROS and \
+                not current_user.is_authenticated and \
+                request.endpoint in ('redirects.index', 'security.login'):
+            return authenticate.login()
 
         # if the server is restarted the in memory key will be lost
         # but the user session may still be active. Logout the user
         # to get the key again when login
         if config.SERVER_MODE and current_user.is_authenticated and \
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE != \
+                KERBEROS and \
                 current_app.keyManager.get() is None and \
                 request.endpoint not in ('security.login', 'security.logout'):
             logout_user()
diff --git a/web/pgadmin/authenticate/__init__.py b/web/pgadmin/authenticate/__init__.py
index 7ede73cd8..1fdb66cf7 100644
--- a/web/pgadmin/authenticate/__init__.py
+++ b/web/pgadmin/authenticate/__init__.py
@@ -11,16 +11,21 @@
 
 import flask
 import pickle
-from flask import current_app, flash
+from flask import current_app, flash, Response, request, url_for,\
+    render_template
 from flask_babelex import gettext
 from flask_security import current_user
 from flask_security.views import _security, _ctx
 from flask_security.utils import config_value, get_post_logout_redirect, \
-    get_post_login_redirect
+    get_post_login_redirect, logout_user
+
 from flask import session
 
 import config
 from pgadmin.utils import PgAdminModule
+from pgadmin.utils.constants import KERBEROS
+from pgadmin.utils.csrf import pgCSRFProtect
+
 from .registry import AuthSourceRegistry
 
 MODULE_NAME = 'authenticate'
@@ -28,12 +33,34 @@ MODULE_NAME = 'authenticate'
 
 class AuthenticateModule(PgAdminModule):
     def get_exposed_url_endpoints(self):
-        return ['authenticate.login']
+        return ['authenticate.login',
+                'authenticate.kerberos_login',
+                'authenticate.kerberos_logout']
 
 
 blueprint = AuthenticateModule(MODULE_NAME, __name__, static_url_path='')
 
 
[email protected]("/login/kerberos",
+                 endpoint="kerberos_login", methods=["GET"])
[email protected]
+def kerberos_login():
+    logout_user()
+    return Response(render_template("browser/kerberos_login.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
[email protected]("/logout/kerberos",
+                 endpoint="kerberos_logout", methods=["GET"])
[email protected]
+def kerberos_logout():
+    logout_user()
+    return Response(render_template("browser/kerberos_logout.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
 @blueprint.route('/login', endpoint='login', methods=['GET', 'POST'])
 def login():
     """
@@ -56,15 +83,24 @@ def login():
     if status:
         # Login the user
         status, msg = auth_obj.login()
+        current_auth_obj = auth_obj.as_dict()
         if not status:
+            if current_auth_obj['current_source'] ==\
+                    KERBEROS:
+                return flask.redirect('{0}?next={1}'.format(url_for(
+                    'authenticate.kerberos_login'), url_for('browser.index')))
+
             flash(gettext(msg), 'danger')
             return flask.redirect(get_post_logout_redirect())
 
-        session['_auth_source_manager_obj'] = auth_obj.as_dict()
+        session['_auth_source_manager_obj'] = current_auth_obj
         return flask.redirect(get_post_login_redirect())
 
+    elif isinstance(msg, Response):
+        return msg
     flash(gettext(msg), 'danger')
-    return flask.redirect(get_post_logout_redirect())
+    response = flask.redirect(get_post_logout_redirect())
+    return response
 
 
 class AuthSourceManager():
@@ -75,6 +111,7 @@ class AuthSourceManager():
         self.auth_sources = sources
         self.source = None
         self.source_friendly_name = None
+        self.current_source = None
 
     def as_dict(self):
         """
@@ -84,9 +121,17 @@ class AuthSourceManager():
         res = dict()
         res['source_friendly_name'] = self.source_friendly_name
         res['auth_sources'] = self.auth_sources
+        res['current_source'] = self.current_source
 
         return res
 
+    def set_current_source(self, source):
+        self.current_source = source
+
+    @property
+    def get_current_source(self, source):
+        return self.current_source
+
     def set_source(self, source):
         self.source = source
 
@@ -115,9 +160,33 @@ class AuthSourceManager():
         msg = None
         for src in self.auth_sources:
             source = get_auth_sources(src)
+            current_app.logger.debug(
+                "Authentication initiated via source: %s" %
+                source.get_source_name())
+
+            if self.form.data['email'] and self.form.data['password'] and \
+                    source.get_source_name() == KERBEROS:
+                continue
+
             status, msg = source.authenticate(self.form)
+
+            # When server sends Unauthorized header to get the ticket over HTTP
+            # OR When kerberos authentication failed while accessing pgadmin,
+            # we need to break the loop as no need to authenticate further
+            # even if the authentication sources set to multiple
+            if not status:
+                if (hasattr(msg, 'status') and
+                    msg.status == '401 UNAUTHORIZED') or\
+                        (source.get_source_name() ==
+                         KERBEROS and
+                         request.method == 'GET'):
+                    break
+
             if status:
                 self.set_source(source)
+                self.set_current_source(source.get_source_name())
+                if msg is not None and 'username' in msg:
+                    self.form._fields['email'].data = msg['username']
                 return status, msg
         return status, msg
 
@@ -125,6 +194,9 @@ class AuthSourceManager():
         status, msg = self.source.login(self.form)
         if status:
             self.set_source_friendly_name(self.source.get_friendly_name())
+            current_app.logger.debug(
+                "Authentication and Login successfully done via source : %s" %
+                self.source.get_source_name())
         return status, msg
 
 
diff --git a/web/pgadmin/authenticate/internal.py b/web/pgadmin/authenticate/internal.py
index 804a487c7..484a7fdca 100644
--- a/web/pgadmin/authenticate/internal.py
+++ b/web/pgadmin/authenticate/internal.py
@@ -18,6 +18,7 @@ from flask_babelex import gettext
 from .registry import AuthSourceRegistry
 from pgadmin.model import User
 from pgadmin.utils.validation_utils import validate_email
+from pgadmin.utils.constants import INTERNAL
 
 
 @six.add_metaclass(AuthSourceRegistry)
@@ -31,7 +32,11 @@ class BaseAuthentication(object):
         'INVALID_EMAIL': gettext('Email/Username is not valid')
     }
 
-    @abstractproperty
+    @abstractmethod
+    def get_source_name(self):
+        pass
+
+    @abstractmethod
     def get_friendly_name(self):
         pass
 
@@ -82,6 +87,9 @@ class BaseAuthentication(object):
 
 class InternalAuthentication(BaseAuthentication):
 
+    def get_source_name(self):
+        return INTERNAL
+
     def get_friendly_name(self):
         return gettext("internal")
 
diff --git a/web/pgadmin/authenticate/kerberos.py b/web/pgadmin/authenticate/kerberos.py
new file mode 100644
index 000000000..629fc7bf7
--- /dev/null
+++ b/web/pgadmin/authenticate/kerberos.py
@@ -0,0 +1,138 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the Spnego/Kerberos authentication."""
+
+import base64
+import gssapi
+from os import environ
+
+from werkzeug.datastructures import Headers
+from flask_babelex import gettext
+from flask import Flask, request, Response, session,\
+    current_app, render_template, flash
+
+import config
+from pgadmin.model import User, ServerGroup, db, Role
+from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import KERBEROS
+
+from flask_security.views import _security, _commit, _ctx
+from werkzeug.datastructures import MultiDict
+
+from .internal import BaseAuthentication
+
+
+# Set the Kerberos config file
+if config.KRB_KTNAME and config.KRB_KTNAME != '<KRB5_KEYTAB_FILE>':
+    environ['KRB5_KTNAME'] = config.KRB_KTNAME
+
+
+class KerberosAuthentication(BaseAuthentication):
+
+    def get_source_name(self):
+        return KERBEROS
+
+    def get_friendly_name(self):
+        return gettext("kerberos")
+
+    def validate(self, form):
+        return True
+
+    def authenticate(self, frm):
+        retval = [True, None]
+        negotiate = False
+        headers = Headers()
+        authorization = request.headers.get("Authorization", None)
+        form_class = _security.login_form
+
+        if request.json:
+            form = form_class(MultiDict(request.json))
+        else:
+            form = form_class()
+
+        try:
+            if authorization is not None:
+                auth_header = authorization.split()
+                if auth_header[0] == 'Negotiate':
+                    status, negotiate = self.negotiate_start(auth_header[1])
+
+                    if status:
+                        # Saving the first 15 characters of the kerberos key
+                        # to encrypt/decrypt database password
+                        session['kerberos_key'] = auth_header[1][0:15]
+                        # Create user
+                        retval = self.__auto_create_user(
+                            str(negotiate.initiator_name))
+                    elif isinstance(negotiate, Exception):
+                        flash(gettext(negotiate), 'danger')
+                        retval = [status,
+                                  Response(render_template(
+                                      "security/login_user.html",
+                                      login_user_form=form))]
+                    else:
+                        headers.add('WWW-Authenticate', 'Negotiate ' +
+                                    str(base64.b64encode(negotiate), 'utf-8'))
+                        return False, Response("Success", 200, headers)
+            else:
+                flash(gettext("Kerberos authentication failed."
+                              " Couldn't find kerberos ticket."), 'danger')
+                headers.add('WWW-Authenticate', 'Negotiate')
+                retval = [False,
+                          Response(render_template(
+                              "security/login_user.html",
+                              login_user_form=form), 401, headers)]
+        finally:
+            if negotiate is not False:
+                self.negotiate_end(negotiate)
+        return retval
+
+    def negotiate_start(self, in_token):
+        svc_princ = gssapi.Name('HTTP@%s' % config.KRB_APP_HOST_NAME,
+                                name_type=gssapi.NameType.hostbased_service)
+        cname = svc_princ.canonicalize(gssapi.MechType.kerberos)
+
+        try:
+            server_creds = gssapi.Credentials(usage='accept', name=cname)
+            context = gssapi.SecurityContext(creds=server_creds)
+            out_token = context.step(base64.b64decode(in_token))
+        except Exception as e:
+            current_app.logger.exception(e)
+            return False, e
+
+        if out_token and not context.complete:
+            return False, out_token
+        if context.complete:
+            return True, context
+        else:
+            return False, None
+
+    def negotiate_end(self, context):
+        # Free gss_cred_id_t
+        del_creds = getattr(context, 'delegated_creds', None)
+        if del_creds:
+            deleg_creds = context.delegated_creds
+            del(deleg_creds)
+
+    def __auto_create_user(self, username):
+        """Add the ldap user to the internal SQLite database."""
+        username = str(username)
+        if config.KRB_AUTO_CREATE_USER:
+            user = User.query.filter_by(
+                username=username).first()
+            if user is None:
+                return create_user({
+                    'username': username,
+                    'email': username,
+                    'role': 2,
+                    'active': True,
+                    'auth_source': KERBEROS
+                })
+
+        return True, {'username': username}
diff --git a/web/pgadmin/authenticate/ldap.py b/web/pgadmin/authenticate/ldap.py
index a9eca110f..2f0f61b7c 100644
--- a/web/pgadmin/authenticate/ldap.py
+++ b/web/pgadmin/authenticate/ldap.py
@@ -23,6 +23,7 @@ from .internal import BaseAuthentication
 from pgadmin.model import User, ServerGroup, db, Role
 from flask import current_app
 from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import LDAP
 
 
 ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
@@ -31,6 +32,9 @@ ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
 class LDAPAuthentication(BaseAuthentication):
     """Ldap Authentication Class"""
 
+    def get_source_name(self):
+        return LDAP
+
     def get_friendly_name(self):
         return gettext("ldap")
 
@@ -151,7 +155,7 @@ class LDAPAuthentication(BaseAuthentication):
                     'email': user_email,
                     'role': 2,
                     'active': True,
-                    'auth_source': 'ldap'
+                    'auth_source': LDAP
                 })
 
         return True, None
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 1bae28f9c..c0ad869a1 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -29,7 +29,7 @@ from flask_security.recoverable import reset_password_token_status, \
     generate_reset_password_token, update_password
 from flask_security.signals import reset_password_instructions_sent
 from flask_security.utils import config_value, do_flash, get_url, \
-    get_message, slash_url_suffix, login_user, send_mail
+    get_message, slash_url_suffix, login_user, send_mail, logout_user
 from flask_security.views import _security, _commit, _ctx
 from werkzeug.datastructures import MultiDict
 
@@ -47,7 +47,8 @@ from pgadmin.utils.master_password import validate_master_password, \
     set_masterpass_check_text, cleanup_master_password, get_crypt_key, \
     set_crypt_key, process_masterpass_disabled
 from pgadmin.model import User
-from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE
+from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE,\
+    INTERNAL, KERBEROS
 
 try:
     from flask_security.views import default_render_json
@@ -280,7 +281,8 @@ class BrowserModule(PgAdminModule):
                 'browser.check_master_password',
                 'browser.set_master_password',
                 'browser.reset_master_password',
-                'browser.lock_layout']
+                'browser.lock_layout'
+                ]
 
 
 blueprint = BrowserModule(MODULE_NAME, __name__)
@@ -539,6 +541,12 @@ class BrowserPluginModule(PgAdminModule):
 
 
 def _get_logout_url():
+    if config.SERVER_MODE and\
+            session['_auth_source_manager_obj']['current_source'] == \
+            KERBEROS:
+        return '{0}?next={1}'.format(url_for(
+            'authenticate.kerberos_logout'), url_for(BROWSER_INDEX))
+
     return '{0}?next={1}'.format(
         url_for('security.logout'), url_for(BROWSER_INDEX))
 
@@ -664,13 +672,18 @@ def index():
     auth_only_internal = False
     auth_source = []
 
+    session['allow_save_password'] = True
+
     if config.SERVER_MODE:
         if len(config.AUTHENTICATION_SOURCES) == 1\
-                and 'internal' in config.AUTHENTICATION_SOURCES:
+                and INTERNAL in config.AUTHENTICATION_SOURCES:
             auth_only_internal = True
         auth_source = session['_auth_source_manager_obj'][
             'source_friendly_name']
 
+        if session['_auth_source_manager_obj']['current_source'] == KERBEROS:
+            session['allow_save_password'] = False
+
     response = Response(render_template(
         MODULE_NAME + "/index.html",
         username=current_user.username,
@@ -1086,7 +1099,7 @@ if hasattr(config, 'SECURITY_RECOVERABLE') and config.SECURITY_RECOVERABLE:
             # Check the Authentication source of the User
             user = User.query.filter_by(
                 email=form.data['email'],
-                auth_source=current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+                auth_source=INTERNAL
             ).first()
 
             if user is None:
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index ecc1281a2..5daef8120 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -10,7 +10,7 @@
 import simplejson as json
 import pgadmin.browser.server_groups as sg
 from flask import render_template, request, make_response, jsonify, \
-    current_app, url_for
+    current_app, url_for, session
 from flask_babelex import gettext
 from flask_security import current_user, login_required
 from pgadmin.browser.server_groups.servers.types import ServerType
@@ -1822,7 +1822,13 @@ class ServerNode(PGChildNodeView):
                     _=gettext,
                     service=server.service,
                     prompt_tunnel_password=prompt_tunnel_password,
-                    prompt_password=prompt_password
+                    prompt_password=prompt_password,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
+                    allow_save_tunnel_password=True if
+                    config.ALLOW_SAVE_TUNNEL_PASSWORD and
+                    session['allow_save_password'] else False
                 )
             )
         else:
@@ -1836,6 +1842,9 @@ class ServerNode(PGChildNodeView):
                     errmsg=errmsg,
                     service=server.service,
                     _=gettext,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
                 )
             )
 
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
index 9b2c425e3..35f4e2a16 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
@@ -19,7 +19,7 @@
             <div class="col-sm-10">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
index 5de642f85..e34a257f2 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
@@ -15,7 +15,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_tunnel_password" name="save_tunnel_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_TUNNEL_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_tunnel_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_tunnel_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
@@ -39,7 +39,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/templates/browser/kerberos_login.html b/web/pgadmin/browser/templates/browser/kerberos_login.html
new file mode 100644
index 000000000..c112e3196
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_login.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Login Failed.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/templates/browser/kerberos_logout.html b/web/pgadmin/browser/templates/browser/kerberos_logout.html
new file mode 100644
index 000000000..430dc6f25
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_logout.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Logged out successfully.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/tests/test_kerberos_with_mocking.py b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
new file mode 100644
index 000000000..f87ce5521
--- /dev/null
+++ b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
@@ -0,0 +1,104 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import config as app_config
+from pgadmin.utils.route import BaseTestGenerator
+from regression.python_test_utils import test_utils as utils
+from pgadmin.authenticate.registry import AuthSourceRegistry
+from unittest.mock import patch, MagicMock
+
+
+class KerberosLoginMockTestCase(BaseTestGenerator):
+    """
+    This class checks Spnego/Kerberos login functionality by mocking
+    HTTP negotiate authentication.
+    """
+
+    scenarios = [
+        ('Spnego/Kerberos Authentication: Test Unauthorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=1
+        )),
+        ('Spnego/Kerberos Authentication: Test Authorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=2
+        ))
+    ]
+
+    @classmethod
+    def setUpClass(cls):
+        """
+        We need to logout the test client as we are testing
+        spnego/kerberos login scenarios.
+        """
+        cls.tester.logout()
+
+    def setUp(self):
+        app_config.AUTHENTICATION_SOURCES = self.auth_source
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'kerberos'
+
+    def runTest(self):
+        """This function checks spnego/kerberos login functionality."""
+        if self.flag == 1:
+            self.test_unauthorized()
+        elif self.flag == 2:
+            if app_config.SERVER_MODE is False:
+                self.skipTest(
+                    "Can not run Kerberos Authentication in the Desktop mode."
+                )
+
+            self.test_authorized()
+
+    def test_unauthorized(self):
+        """
+        Ensure that when client sends the first request,
+        the Negotiate request is sent.
+        """
+        res = self.tester.login(None, None, True)
+        self.assertEqual(res.status_code, 401)
+        self.assertEqual(res.headers.get('www-authenticate'), 'Negotiate')
+
+    def test_authorized(self):
+        """
+        Ensure that when the client sends an correct authorization token,
+        they receive a 200 OK response and the user principal is extracted and
+        passed on to the routed method.
+        """
+
+        class delCrads:
+            def __init__(self):
+                self.initiator_name = '[email protected]'
+        del_crads = delCrads()
+
+        AuthSourceRegistry.registry['kerberos'].negotiate_start = MagicMock(
+            return_value=[True, del_crads])
+        res = self.tester.login(None,
+                                None,
+                                True,
+                                headers={'Authorization': 'Negotiate CTOKEN'}
+                                )
+        self.assertEqual(res.status_code, 200)
+        respdata = 'Gravatar image for %s' % del_crads.initiator_name
+        self.assertTrue(respdata in res.data.decode('utf8'))
+
+    def tearDown(self):
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
+        self.tester.logout()
+
+    @classmethod
+    def tearDownClass(cls):
+        """
+        We need to again login the test client as soon as test scenarios
+        finishes.
+        """
+        cls.tester.logout()
+        app_config.AUTHENTICATION_SOURCES = ['internal']
+        utils.login_tester_account(cls.tester)
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index 2405a498d..05ed998c6 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -25,7 +25,7 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_json_response, bad_request, \
     internal_server_error, unauthorized
 
-from config import PG_DEFAULT_DRIVER
+from config import PG_DEFAULT_DRIVER, ALLOW_SAVE_PASSWORD
 from pgadmin.model import Server, User
 from pgadmin.utils.driver import get_driver
 from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost
@@ -402,6 +402,9 @@ def _init_query_tool(trans_id, connect, sgid, sid, did, **kwargs):
                             username=user,
                             errmsg=msg,
                             _=gettext,
+                            allow_save_password=True if
+                            ALLOW_SAVE_PASSWORD and
+                            session['allow_save_password'] else False,
                         )
                     ), '', ''
                 else:
diff --git a/web/pgadmin/tools/user_management/__init__.py b/web/pgadmin/tools/user_management/__init__.py
index 8641130c4..ce280a3d2 100644
--- a/web/pgadmin/tools/user_management/__init__.py
+++ b/web/pgadmin/tools/user_management/__init__.py
@@ -13,7 +13,7 @@ import simplejson as json
 import re
 
 from flask import render_template, request, \
-    url_for, Response, abort, current_app
+    url_for, Response, abort, current_app, session
 from flask_babelex import gettext as _
 from flask_security import login_required, roles_required, current_user
 from flask_security.utils import encrypt_password
@@ -24,7 +24,8 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_response as ajax_response, \
     make_json_response, bad_request, internal_server_error, forbidden
 from pgadmin.utils.csrf import pgCSRFProtect
-from pgadmin.utils.constants import MIMETYPE_APP_JS
+from pgadmin.utils.constants import MIMETYPE_APP_JS, INTERNAL,\
+    SUPPORTED_AUTH_SOURCES, KERBEROS
 from pgadmin.utils.validation_utils import validate_email
 from pgadmin.model import db, Role, User, UserPreference, Server, \
     ServerGroup, Process, Setting
@@ -167,11 +168,13 @@ def current_user_info():
                 config.SERVER_MODE is True
                 else 'postgres'
             ),
-            allow_save_password='true' if config.ALLOW_SAVE_PASSWORD
+            allow_save_password='true' if
+            config.ALLOW_SAVE_PASSWORD and session['allow_save_password']
             else 'false',
-            allow_save_tunnel_password='true'
-            if config.ALLOW_SAVE_TUNNEL_PASSWORD else 'false',
-            auth_sources=config.AUTHENTICATION_SOURCES,
+            allow_save_tunnel_password='true' if
+            config.ALLOW_SAVE_TUNNEL_PASSWORD and session[
+                'allow_save_password'] else 'false',
+            auth_sources=config.AUTHENTICATION_SOURCES
         ),
         status=200,
         mimetype=MIMETYPE_APP_JS
@@ -254,10 +257,10 @@ def _create_new_user(new_data):
     :return: Return new created user.
     """
     auth_source = new_data['auth_source'] if 'auth_source' in new_data \
-        else current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+        else INTERNAL
     username = new_data['username'] if \
         'username' in new_data and auth_source != \
-        current_app.PGADMIN_DEFAULT_AUTH_SOURCE else new_data['email']
+        INTERNAL else new_data['email']
     email = new_data['email'] if 'email' in new_data else None
     password = new_data['password'] if 'password' in new_data else None
 
@@ -279,7 +282,7 @@ def _create_new_user(new_data):
 
 def create_user(data):
     if 'auth_source' in data and data['auth_source'] != \
-            current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+            INTERNAL:
         req_params = ('username', 'role', 'active', 'auth_source')
     else:
         req_params = ('email', 'role', 'active', 'newPassword',
@@ -380,7 +383,7 @@ def update(uid):
     )
 
     # Username and email can not be changed for internal users
-    if usr.auth_source == current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+    if usr.auth_source == INTERNAL:
         non_editable_params = ('username', 'email')
 
         for f in non_editable_params:
@@ -463,7 +466,7 @@ def role(rid):
 )
 def auth_sources():
     sources = []
-    for source in current_app.PGADMIN_SUPPORTED_AUTH_SOURCE:
+    for source in SUPPORTED_AUTH_SOURCES:
         sources.append({'label': source, 'value': source})
 
     return ajax_response(
diff --git a/web/pgadmin/utils/constants.py b/web/pgadmin/utils/constants.py
index 0a2261f05..5fd942304 100644
--- a/web/pgadmin/utils/constants.py
+++ b/web/pgadmin/utils/constants.py
@@ -47,3 +47,12 @@ ERROR_FETCHING_ROLE_INFORMATION = gettext(
     'Error fetching role information from the database server.')
 
 ERROR_FETCHING_DATA = gettext('Unable to fetch data.')
+
+# Authentication Sources
+INTERNAL = 'internal'
+LDAP = 'ldap'
+KERBEROS = 'kerberos'
+
+SUPPORTED_AUTH_SOURCES = [INTERNAL,
+                          LDAP,
+                          KERBEROS]
diff --git a/web/pgadmin/utils/master_password.py b/web/pgadmin/utils/master_password.py
index 759bf36e0..629eec941 100644
--- a/web/pgadmin/utils/master_password.py
+++ b/web/pgadmin/utils/master_password.py
@@ -1,8 +1,9 @@
 import config
-from flask import current_app
+from flask import current_app, session
 from flask_login import current_user
 from pgadmin.model import db, User, Server
 from pgadmin.utils.crypto import encrypt, decrypt
+from pgadmin.utils.constants import KERBEROS
 
 
 MASTERPASS_CHECK_TEXT = 'ideas are bulletproof'
@@ -32,6 +33,11 @@ def get_crypt_key():
     elif config.MASTER_PASSWORD_REQUIRED \
             and not config.SERVER_MODE and enc_key is None:
         return False, None
+    elif config.SERVER_MODE and \
+            session['_auth_source_manager_obj']['source_friendly_name']\
+            == KERBEROS:
+        return True, session['kerberos_key'] if 'kerberos_key' in session \
+            else None
     else:
         return True, enc_key
 
diff --git a/web/regression/python_test_utils/csrf_test_client.py b/web/regression/python_test_utils/csrf_test_client.py
index 11d2cfca5..ca4120e18 100644
--- a/web/regression/python_test_utils/csrf_test_client.py
+++ b/web/regression/python_test_utils/csrf_test_client.py
@@ -101,7 +101,8 @@ class TestClient(testing.FlaskClient):
 
             return csrf_token
 
-    def login(self, email, password, _follow_redirects=False):
+    def login(self, email, password, _follow_redirects=False,
+              headers=None):
         if config.SERVER_MODE is True:
             res = self.get('/login', follow_redirects=True)
             csrf_token = self.fetch_csrf(res)
@@ -113,7 +114,8 @@ class TestClient(testing.FlaskClient):
                 email=email, password=password,
                 csrf_token=csrf_token,
             ),
-            follow_redirects=_follow_redirects
+            follow_redirects=_follow_redirects,
+            headers=headers
         )
         self.csrf_token = csrf_token
 
diff --git a/web/regression/runtests.py b/web/regression/runtests.py
index 3328ed3f6..9b794e41f 100644
--- a/web/regression/runtests.py
+++ b/web/regression/runtests.py
@@ -117,9 +117,9 @@ if config.SERVER_MODE is True:
 app.config['WTF_CSRF_ENABLED'] = True
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
 app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
 
+
 app.test_client_class = TestClient
 test_client = app.test_client()
 test_client.setApp(app)


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-14 08:18  Akshay Joshi <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Akshay Joshi @ 2021-01-14 08:18 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: Aditya Toshniwal <[email protected]>; pgadmin-hackers

Thanks, patch applied.

On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
[email protected]> wrote:

> Hi,
>
> Please ignore my previous patch, attached the updated one.
>
> Thanks,
> Khushboo
>
> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
> [email protected]> wrote:
>
>> Hi,
>>
>> Please find the attached updated patch.
>>
>> Thanks,
>> Khushboo
>>
>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>> [email protected]> wrote:
>>
>>> Hi Khushboo
>>>
>>> Seems you have attached the wrong patch. Please send the updated patch.
>>>
>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>> [email protected]> wrote:
>>>
>>>> Hi,
>>>>
>>>> Please find the attached updated patch.
>>>>
>>>> Thanks,
>>>> Khushboo
>>>>
>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi Khushboo,
>>>>>
>>>>> I've just done the code review. Apart from below, the patch looks good
>>>>> to me:
>>>>>
>>>>> 1) Move the auth source constants -ldap, kerberos out of app object.
>>>>> They don't belong there. You can create the constants somewhere else and
>>>>> import them.
>>>>>
>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>
>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>
>>>>>
>>>>> Done
>>>>
>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>
>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>
>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>
>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>
>>>>>
>>>>>
>>>>>  import config
>>>>>
>>>>>
>>>>>
>>>>> +
>>>>>
>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>
>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>
>>>>> +
>>>>>
>>>>>
>>>>> Removed, it was only for testing.
>>>>
>>>>> 3) Remove the commented code.
>>>>>
>>>>> +            # if self.form.data['email'] and
>>>>> self.form.data['password'] and \
>>>>>
>>>>> +            #         source.get_source_name() ==\
>>>>>
>>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>
>>>>> +            #     continue
>>>>>
>>>>>
>>>>> Removed the comment, it is actually the part of the code.
>>>>
>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>
>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>
>>>>>
>>>>> Done.
>>>>
>>>>> 5) You can use the constants (ldap, kerberos) you had defined when
>>>>> creating a user.
>>>>>
>>>>> +                    'auth_source': 'kerberos'
>>>>>
>>>>>
>>>>> Done.
>>>>
>>>>> 6) The below URLs belong to the authenticate module. Currently they
>>>>> are in the browser module. I would also suggest rephrasing the URL from
>>>>> /kerberos_login to /login/kerberos. Same for logout.
>>>>>
>>>> Done the rephrasing as well as moved to the authentication module.
>>>>
>>>>
>>>>> Also, even though the method GET works, we should use the POST method
>>>>> for login and DELETE for logout.
>>>>>
>>>> Kerberos_login just redirects the page to the actual login, so no need
>>>> for the POST method.
>>>> I followed the same method for the Logout user we have used for the
>>>> normal user.
>>>>
>>>>
>>>>> [email protected]("/kerberos_login",
>>>>>
>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>
>>>>>
>>>>> [email protected]("/kerberos_logout",
>>>>>
>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi Aditya
>>>>>>
>>>>>> Can you please do the code review?
>>>>>>
>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Please find the attached patch to support Kerberos Authentication in
>>>>>>> pgAdmin RM 5457.
>>>>>>>
>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>> succeeds.
>>>>>>>
>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server + Client
>>>>>>> is documented in a separate file and attached.
>>>>>>>
>>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Khushboo
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> *Thanks & Regards*
>>>>>> *Akshay Joshi*
>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>
>>>>>> *Mobile: +91 976-788-8246*
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Thanks,
>>>>> Aditya Toshniwal
>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>> <http://edbpostgres.com;
>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>
>>>>
>>>
>>> --
>>> *Thanks & Regards*
>>> *Akshay Joshi*
>>> *pgAdmin Hacker | Principal Software Architect*
>>> *EDB Postgres <http://edbpostgres.com>*
>>>
>>> *Mobile: +91 976-788-8246*
>>>
>>

-- 
*Thanks & Regards*
*Akshay Joshi*
*pgAdmin Hacker | Principal Software Architect*
*EDB Postgres <http://edbpostgres.com>*

*Mobile: +91 976-788-8246*


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-14 16:04  Dave Page <[email protected]>
  parent: Akshay Joshi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-14 16:04 UTC (permalink / raw)
  To: Akshay Joshi <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

Hi Khushboo,

As you know, this has been rolled back as the buildfarm blew up. I think
there are a number of TODOs that need to be addressed, given that the
gssapi Python module is dependent on MIT Kerberos:

In the patch:

- Linux packages will need the additional dependencies to be declared in
the RPM/DEBs.
- The setup scripts for Linux will need to have the -dev packages added as
appropriate.
- The various READMEs that describe how to build packages will need to be
updated.
- The Dockerfile will need to be modified to add the required packages.
- The Windows build will need to be updated so the installer ships
additional required DLLs.
- Are there any additional macOS dependencies? If so, they need to be
handled.

In the buildfarm:

- All Linux build VMs need to be updated with the additional dependencies.
- On Windows, we need to figure out how to build/ship KfW. It's a pain to
build, which we would typically do ourselves to ensure we're consistently
using the same buildchain. If we do build it ourselves:
  - Will the Python package find it during it's build?
  - We'll need to create a Jenkins job to perform the build.
- Is any work required on macOS, or does it ship with everything that's
needed? If not, we'll need to build it, and create the Jenkins job.

One final thought: on Windows/macOS, can we force a binary installation
from PIP (pip install --only-binary=gssapi gssapi)? If so, will that
include the required libraries, as psycopg2-binary does?


On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <[email protected]>
wrote:

> Thanks, patch applied.
>
> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
> [email protected]> wrote:
>
>> Hi,
>>
>> Please ignore my previous patch, attached the updated one.
>>
>> Thanks,
>> Khushboo
>>
>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>> Please find the attached updated patch.
>>>
>>> Thanks,
>>> Khushboo
>>>
>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>> [email protected]> wrote:
>>>
>>>> Hi Khushboo
>>>>
>>>> Seems you have attached the wrong patch. Please send the updated patch.
>>>>
>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Please find the attached updated patch.
>>>>>
>>>>> Thanks,
>>>>> Khushboo
>>>>>
>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi Khushboo,
>>>>>>
>>>>>> I've just done the code review. Apart from below, the patch looks
>>>>>> good to me:
>>>>>>
>>>>>> 1) Move the auth source constants -ldap, kerberos out of app object.
>>>>>> They don't belong there. You can create the constants somewhere else and
>>>>>> import them.
>>>>>>
>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>
>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>
>>>>>>
>>>>>> Done
>>>>>
>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>
>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>
>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>
>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>
>>>>>>
>>>>>>
>>>>>>  import config
>>>>>>
>>>>>>
>>>>>>
>>>>>> +
>>>>>>
>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>
>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>
>>>>>> +
>>>>>>
>>>>>>
>>>>>> Removed, it was only for testing.
>>>>>
>>>>>> 3) Remove the commented code.
>>>>>>
>>>>>> +            # if self.form.data['email'] and
>>>>>> self.form.data['password'] and \
>>>>>>
>>>>>> +            #         source.get_source_name() ==\
>>>>>>
>>>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>
>>>>>> +            #     continue
>>>>>>
>>>>>>
>>>>>> Removed the comment, it is actually the part of the code.
>>>>>
>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>
>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>
>>>>>>
>>>>>> Done.
>>>>>
>>>>>> 5) You can use the constants (ldap, kerberos) you had defined when
>>>>>> creating a user.
>>>>>>
>>>>>> +                    'auth_source': 'kerberos'
>>>>>>
>>>>>>
>>>>>> Done.
>>>>>
>>>>>> 6) The below URLs belong to the authenticate module. Currently they
>>>>>> are in the browser module. I would also suggest rephrasing the URL from
>>>>>> /kerberos_login to /login/kerberos. Same for logout.
>>>>>>
>>>>> Done the rephrasing as well as moved to the authentication module.
>>>>>
>>>>>
>>>>>> Also, even though the method GET works, we should use the POST method
>>>>>> for login and DELETE for logout.
>>>>>>
>>>>> Kerberos_login just redirects the page to the actual login, so no need
>>>>> for the POST method.
>>>>> I followed the same method for the Logout user we have used for the
>>>>> normal user.
>>>>>
>>>>>
>>>>>> [email protected]("/kerberos_login",
>>>>>>
>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>
>>>>>>
>>>>>> [email protected]("/kerberos_logout",
>>>>>>
>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi Aditya
>>>>>>>
>>>>>>> Can you please do the code review?
>>>>>>>
>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Please find the attached patch to support Kerberos Authentication
>>>>>>>> in pgAdmin RM 5457.
>>>>>>>>
>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>> succeeds.
>>>>>>>>
>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server + Client
>>>>>>>> is documented in a separate file and attached.
>>>>>>>>
>>>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Khushboo
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> *Thanks & Regards*
>>>>>>> *Akshay Joshi*
>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>
>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Thanks,
>>>>>> Aditya Toshniwal
>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>> <http://edbpostgres.com;
>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>
>>>>>
>>>>
>>>> --
>>>> *Thanks & Regards*
>>>> *Akshay Joshi*
>>>> *pgAdmin Hacker | Principal Software Architect*
>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>
>>>> *Mobile: +91 976-788-8246*
>>>>
>>>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
> *pgAdmin Hacker | Principal Software Architect*
> *EDB Postgres <http://edbpostgres.com>*
>
> *Mobile: +91 976-788-8246*
>


-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-14 16:34  Dave Page <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-14 16:34 UTC (permalink / raw)
  To: Akshay Joshi <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

FYI, I did a quick test (and browse of PyPI):

- On Windows, it seems there is a binary wheel available:

(gssapi) C:\Users\dpage>pip install gssapi
Collecting gssapi
  Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
     |████████████████████████████████| 670 kB 3.3 MB/s
Collecting decorator
  Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
Installing collected packages: decorator, gssapi
Successfully installed decorator-4.4.2 gssapi-1.6.12

- On macOS, the wheel is built by pip, but it doesn't seem to have any
additional binary dependencies.

This should simplify things a lot - we just need to ensure the build
scripts use the binary package on Windows, and install the build deps on
the Linux/Docker environments (and update the package builds with the
additional dependencies of course).


On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:

> Hi Khushboo,
>
> As you know, this has been rolled back as the buildfarm blew up. I think
> there are a number of TODOs that need to be addressed, given that the
> gssapi Python module is dependent on MIT Kerberos:
>
> In the patch:
>
> - Linux packages will need the additional dependencies to be declared in
> the RPM/DEBs.
> - The setup scripts for Linux will need to have the -dev packages added as
> appropriate.
> - The various READMEs that describe how to build packages will need to be
> updated.
> - The Dockerfile will need to be modified to add the required packages.
> - The Windows build will need to be updated so the installer ships
> additional required DLLs.
> - Are there any additional macOS dependencies? If so, they need to be
> handled.
>
> In the buildfarm:
>
> - All Linux build VMs need to be updated with the additional dependencies.
> - On Windows, we need to figure out how to build/ship KfW. It's a pain to
> build, which we would typically do ourselves to ensure we're consistently
> using the same buildchain. If we do build it ourselves:
>   - Will the Python package find it during it's build?
>   - We'll need to create a Jenkins job to perform the build.
> - Is any work required on macOS, or does it ship with everything that's
> needed? If not, we'll need to build it, and create the Jenkins job.
>
> One final thought: on Windows/macOS, can we force a binary installation
> from PIP (pip install --only-binary=gssapi gssapi)? If so, will that
> include the required libraries, as psycopg2-binary does?
>
>
> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
> [email protected]> wrote:
>
>> Thanks, patch applied.
>>
>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>> Please ignore my previous patch, attached the updated one.
>>>
>>> Thanks,
>>> Khushboo
>>>
>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>> [email protected]> wrote:
>>>
>>>> Hi,
>>>>
>>>> Please find the attached updated patch.
>>>>
>>>> Thanks,
>>>> Khushboo
>>>>
>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi Khushboo
>>>>>
>>>>> Seems you have attached the wrong patch. Please send the updated patch.
>>>>>
>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Please find the attached updated patch.
>>>>>>
>>>>>> Thanks,
>>>>>> Khushboo
>>>>>>
>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi Khushboo,
>>>>>>>
>>>>>>> I've just done the code review. Apart from below, the patch looks
>>>>>>> good to me:
>>>>>>>
>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app object.
>>>>>>> They don't belong there. You can create the constants somewhere else and
>>>>>>> import them.
>>>>>>>
>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>
>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>
>>>>>>>
>>>>>>> Done
>>>>>>
>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>
>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>
>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>
>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>  import config
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> +
>>>>>>>
>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>
>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>
>>>>>>> +
>>>>>>>
>>>>>>>
>>>>>>> Removed, it was only for testing.
>>>>>>
>>>>>>> 3) Remove the commented code.
>>>>>>>
>>>>>>> +            # if self.form.data['email'] and
>>>>>>> self.form.data['password'] and \
>>>>>>>
>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>
>>>>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>
>>>>>>> +            #     continue
>>>>>>>
>>>>>>>
>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>
>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>
>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>
>>>>>>>
>>>>>>> Done.
>>>>>>
>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined when
>>>>>>> creating a user.
>>>>>>>
>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>
>>>>>>>
>>>>>>> Done.
>>>>>>
>>>>>>> 6) The below URLs belong to the authenticate module. Currently they
>>>>>>> are in the browser module. I would also suggest rephrasing the URL from
>>>>>>> /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>
>>>>>> Done the rephrasing as well as moved to the authentication module.
>>>>>>
>>>>>>
>>>>>>> Also, even though the method GET works, we should use the POST
>>>>>>> method for login and DELETE for logout.
>>>>>>>
>>>>>> Kerberos_login just redirects the page to the actual login, so no
>>>>>> need for the POST method.
>>>>>> I followed the same method for the Logout user we have used for the
>>>>>> normal user.
>>>>>>
>>>>>>
>>>>>>> [email protected]("/kerberos_login",
>>>>>>>
>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>
>>>>>>>
>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>
>>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi Aditya
>>>>>>>>
>>>>>>>> Can you please do the code review?
>>>>>>>>
>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> Please find the attached patch to support Kerberos Authentication
>>>>>>>>> in pgAdmin RM 5457.
>>>>>>>>>
>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>> succeeds.
>>>>>>>>>
>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server +
>>>>>>>>> Client is documented in a separate file and attached.
>>>>>>>>>
>>>>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Khushboo
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> *Thanks & Regards*
>>>>>>>> *Akshay Joshi*
>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>
>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Thanks,
>>>>>>> Aditya Toshniwal
>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>> <http://edbpostgres.com;
>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>
>>>>>>
>>>>>
>>>>> --
>>>>> *Thanks & Regards*
>>>>> *Akshay Joshi*
>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>
>>>>> *Mobile: +91 976-788-8246*
>>>>>
>>>>
>>
>> --
>> *Thanks & Regards*
>> *Akshay Joshi*
>> *pgAdmin Hacker | Principal Software Architect*
>> *EDB Postgres <http://edbpostgres.com>*
>>
>> *Mobile: +91 976-788-8246*
>>
>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EDB: http://www.enterprisedb.com
>
>

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-15 10:18  Dave Page <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-15 10:18 UTC (permalink / raw)
  To: Akshay Joshi <[email protected]>; +Cc: Khushboo Vashi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

And another thought...

Some of the Jenkins QA jobs setup the virtual environment for running tests
themselves. I believe these might actually be the cause of some of the
failures we saw initially with the commit - I'll review those, and ensure
they won't try to build the gssapi module from source on Windows.

On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:

> FYI, I did a quick test (and browse of PyPI):
>
> - On Windows, it seems there is a binary wheel available:
>
> (gssapi) C:\Users\dpage>pip install gssapi
> Collecting gssapi
>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>      |████████████████████████████████| 670 kB 3.3 MB/s
> Collecting decorator
>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
> Installing collected packages: decorator, gssapi
> Successfully installed decorator-4.4.2 gssapi-1.6.12
>
> - On macOS, the wheel is built by pip, but it doesn't seem to have any
> additional binary dependencies.
>
> This should simplify things a lot - we just need to ensure the build
> scripts use the binary package on Windows, and install the build deps on
> the Linux/Docker environments (and update the package builds with the
> additional dependencies of course).
>
>
> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:
>
>> Hi Khushboo,
>>
>> As you know, this has been rolled back as the buildfarm blew up. I think
>> there are a number of TODOs that need to be addressed, given that the
>> gssapi Python module is dependent on MIT Kerberos:
>>
>> In the patch:
>>
>> - Linux packages will need the additional dependencies to be declared in
>> the RPM/DEBs.
>> - The setup scripts for Linux will need to have the -dev packages added
>> as appropriate.
>> - The various READMEs that describe how to build packages will need to be
>> updated.
>> - The Dockerfile will need to be modified to add the required packages.
>> - The Windows build will need to be updated so the installer ships
>> additional required DLLs.
>> - Are there any additional macOS dependencies? If so, they need to be
>> handled.
>>
>> In the buildfarm:
>>
>> - All Linux build VMs need to be updated with the additional dependencies.
>> - On Windows, we need to figure out how to build/ship KfW. It's a pain to
>> build, which we would typically do ourselves to ensure we're consistently
>> using the same buildchain. If we do build it ourselves:
>>   - Will the Python package find it during it's build?
>>   - We'll need to create a Jenkins job to perform the build.
>> - Is any work required on macOS, or does it ship with everything that's
>> needed? If not, we'll need to build it, and create the Jenkins job.
>>
>> One final thought: on Windows/macOS, can we force a binary installation
>> from PIP (pip install --only-binary=gssapi gssapi)? If so, will that
>> include the required libraries, as psycopg2-binary does?
>>
>>
>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>> [email protected]> wrote:
>>
>>> Thanks, patch applied.
>>>
>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>> [email protected]> wrote:
>>>
>>>> Hi,
>>>>
>>>> Please ignore my previous patch, attached the updated one.
>>>>
>>>> Thanks,
>>>> Khushboo
>>>>
>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Please find the attached updated patch.
>>>>>
>>>>> Thanks,
>>>>> Khushboo
>>>>>
>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi Khushboo
>>>>>>
>>>>>> Seems you have attached the wrong patch. Please send the updated
>>>>>> patch.
>>>>>>
>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Please find the attached updated patch.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Khushboo
>>>>>>>
>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi Khushboo,
>>>>>>>>
>>>>>>>> I've just done the code review. Apart from below, the patch looks
>>>>>>>> good to me:
>>>>>>>>
>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>> somewhere else and import them.
>>>>>>>>
>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>
>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>
>>>>>>>>
>>>>>>>> Done
>>>>>>>
>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>
>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>
>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>
>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>  import config
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> +
>>>>>>>>
>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>
>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>
>>>>>>>> +
>>>>>>>>
>>>>>>>>
>>>>>>>> Removed, it was only for testing.
>>>>>>>
>>>>>>>> 3) Remove the commented code.
>>>>>>>>
>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>> self.form.data['password'] and \
>>>>>>>>
>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>
>>>>>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>
>>>>>>>> +            #     continue
>>>>>>>>
>>>>>>>>
>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>
>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>
>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>
>>>>>>>>
>>>>>>>> Done.
>>>>>>>
>>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined when
>>>>>>>> creating a user.
>>>>>>>>
>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>
>>>>>>>>
>>>>>>>> Done.
>>>>>>>
>>>>>>>> 6) The below URLs belong to the authenticate module. Currently they
>>>>>>>> are in the browser module. I would also suggest rephrasing the URL from
>>>>>>>> /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>
>>>>>>> Done the rephrasing as well as moved to the authentication module.
>>>>>>>
>>>>>>>
>>>>>>>> Also, even though the method GET works, we should use the POST
>>>>>>>> method for login and DELETE for logout.
>>>>>>>>
>>>>>>> Kerberos_login just redirects the page to the actual login, so no
>>>>>>> need for the POST method.
>>>>>>> I followed the same method for the Logout user we have used for the
>>>>>>> normal user.
>>>>>>>
>>>>>>>
>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>
>>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>>
>>>>>>>>
>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>
>>>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi Aditya
>>>>>>>>>
>>>>>>>>> Can you please do the code review?
>>>>>>>>>
>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Please find the attached patch to support Kerberos Authentication
>>>>>>>>>> in pgAdmin RM 5457.
>>>>>>>>>>
>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>> succeeds.
>>>>>>>>>>
>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server +
>>>>>>>>>> Client is documented in a separate file and attached.
>>>>>>>>>>
>>>>>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Khushboo
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> *Thanks & Regards*
>>>>>>>>> *Akshay Joshi*
>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>
>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> Thanks,
>>>>>>>> Aditya Toshniwal
>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>> <http://edbpostgres.com;
>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> --
>>>>>> *Thanks & Regards*
>>>>>> *Akshay Joshi*
>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>
>>>>>> *Mobile: +91 976-788-8246*
>>>>>>
>>>>>
>>>
>>> --
>>> *Thanks & Regards*
>>> *Akshay Joshi*
>>> *pgAdmin Hacker | Principal Software Architect*
>>> *EDB Postgres <http://edbpostgres.com>*
>>>
>>> *Mobile: +91 976-788-8246*
>>>
>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EDB: http://www.enterprisedb.com
>>
>>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EDB: http://www.enterprisedb.com
>
>

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 07:30  Khushboo Vashi <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Khushboo Vashi @ 2021-01-18 07:30 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

Hi,

Please find the attached updated patch with the below changes:

- Dependencies are added into Linux packages in the RPM/DEBs.
- Dev packages are added in the setup scripts for Linux.
- The required packages are added in the Dockerfile.
- Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
requirements.txt.
- krb5 libs are not bundled with the Desktop packages, so added the gssapi
dependency into the try/catch block.
- .dockerignore is introduced to ignore unwanted files/folders like
node_modules etc., which will make the docker build fast. (By Ashesh Vashi)

Thanks,
Khushboo

On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:

> And another thought...
>
> Some of the Jenkins QA jobs setup the virtual environment for running
> tests themselves. I believe these might actually be the cause of some of
> the failures we saw initially with the commit - I'll review those, and
> ensure they won't try to build the gssapi module from source on Windows.
>
> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:
>
>> FYI, I did a quick test (and browse of PyPI):
>>
>> - On Windows, it seems there is a binary wheel available:
>>
>> (gssapi) C:\Users\dpage>pip install gssapi
>> Collecting gssapi
>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>      |████████████████████████████████| 670 kB 3.3 MB/s
>> Collecting decorator
>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>> Installing collected packages: decorator, gssapi
>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>
>> - On macOS, the wheel is built by pip, but it doesn't seem to have any
>> additional binary dependencies.
>>
>> This should simplify things a lot - we just need to ensure the build
>> scripts use the binary package on Windows, and install the build deps on
>> the Linux/Docker environments (and update the package builds with the
>> additional dependencies of course).
>>
>>
>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:
>>
>>> Hi Khushboo,
>>>
>>> As you know, this has been rolled back as the buildfarm blew up. I think
>>> there are a number of TODOs that need to be addressed, given that the
>>> gssapi Python module is dependent on MIT Kerberos:
>>>
>>> In the patch:
>>>
>>> - Linux packages will need the additional dependencies to be declared in
>>> the RPM/DEBs.
>>> - The setup scripts for Linux will need to have the -dev packages added
>>> as appropriate.
>>> - The various READMEs that describe how to build packages will need to
>>> be updated.
>>> - The Dockerfile will need to be modified to add the required packages.
>>> - The Windows build will need to be updated so the installer ships
>>> additional required DLLs.
>>> - Are there any additional macOS dependencies? If so, they need to be
>>> handled.
>>>
>>> In the buildfarm:
>>>
>>> - All Linux build VMs need to be updated with the additional
>>> dependencies.
>>> - On Windows, we need to figure out how to build/ship KfW. It's a pain
>>> to build, which we would typically do ourselves to ensure we're
>>> consistently using the same buildchain. If we do build it ourselves:
>>>   - Will the Python package find it during it's build?
>>>   - We'll need to create a Jenkins job to perform the build.
>>> - Is any work required on macOS, or does it ship with everything that's
>>> needed? If not, we'll need to build it, and create the Jenkins job.
>>>
>>> One final thought: on Windows/macOS, can we force a binary installation
>>> from PIP (pip install --only-binary=gssapi gssapi)? If so, will that
>>> include the required libraries, as psycopg2-binary does?
>>>
>>>
>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>> [email protected]> wrote:
>>>
>>>> Thanks, patch applied.
>>>>
>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Please ignore my previous patch, attached the updated one.
>>>>>
>>>>> Thanks,
>>>>> Khushboo
>>>>>
>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Please find the attached updated patch.
>>>>>>
>>>>>> Thanks,
>>>>>> Khushboo
>>>>>>
>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi Khushboo
>>>>>>>
>>>>>>> Seems you have attached the wrong patch. Please send the updated
>>>>>>> patch.
>>>>>>>
>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Please find the attached updated patch.
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Khushboo
>>>>>>>>
>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi Khushboo,
>>>>>>>>>
>>>>>>>>> I've just done the code review. Apart from below, the patch looks
>>>>>>>>> good to me:
>>>>>>>>>
>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>>> somewhere else and import them.
>>>>>>>>>
>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>
>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Done
>>>>>>>>
>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>
>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>
>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>
>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>  import config
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> +
>>>>>>>>>
>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>
>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>
>>>>>>>>> +
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Removed, it was only for testing.
>>>>>>>>
>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>
>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>
>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>
>>>>>>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>
>>>>>>>>> +            #     continue
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>
>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>
>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Done.
>>>>>>>>
>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined when
>>>>>>>>> creating a user.
>>>>>>>>>
>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Done.
>>>>>>>>
>>>>>>>>> 6) The below URLs belong to the authenticate module. Currently
>>>>>>>>> they are in the browser module. I would also suggest rephrasing the URL
>>>>>>>>> from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>
>>>>>>>> Done the rephrasing as well as moved to the authentication module.
>>>>>>>>
>>>>>>>>
>>>>>>>>> Also, even though the method GET works, we should use the POST
>>>>>>>>> method for login and DELETE for logout.
>>>>>>>>>
>>>>>>>> Kerberos_login just redirects the page to the actual login, so no
>>>>>>>> need for the POST method.
>>>>>>>> I followed the same method for the Logout user we have used for the
>>>>>>>> normal user.
>>>>>>>>
>>>>>>>>
>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>
>>>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>
>>>>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi Aditya
>>>>>>>>>>
>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>
>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>
>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>> succeeds.
>>>>>>>>>>>
>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server +
>>>>>>>>>>> Client is documented in a separate file and attached.
>>>>>>>>>>>
>>>>>>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Khushboo
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>
>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Thanks,
>>>>>>>>> Aditya Toshniwal
>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> *Thanks & Regards*
>>>>>>> *Akshay Joshi*
>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>
>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>
>>>>>>
>>>>
>>>> --
>>>> *Thanks & Regards*
>>>> *Akshay Joshi*
>>>> *pgAdmin Hacker | Principal Software Architect*
>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>
>>>> *Mobile: +91 976-788-8246*
>>>>
>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EDB: http://www.enterprisedb.com
>>>
>>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EDB: http://www.enterprisedb.com
>>
>>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EDB: http://www.enterprisedb.com
>
>


Attachments:

  [application/octet-stream] RM_5457_v3.patch (41.9K, 3-RM_5457_v3.patch)
  download | inline diff:
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 000000000..4c3d8b0ab
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,6 @@
+.git
+web/node_modules
+web/*.log
+web/regression
+web/**/tests/
+.DS_Store
diff --git a/Dockerfile b/Dockerfile
index 6632e88ac..fe92f8d93 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -157,11 +157,15 @@ RUN apk add --no-cache --virtual \
         build-base \
         postgresql-dev \
         libffi-dev \
+        krb5-dev \
+        e2fsprogs-dev \
+        krb5-server-ldap \
         linux-headers && \
     apk add \
         postfix \
         postgresql-client \
         postgresql-libs \
+        krb5-libs \
         shadow \
         sudo \
         libcap && \
diff --git a/pkg/debian/build.sh b/pkg/debian/build.sh
index 6e4718b0f..810e9c868 100755
--- a/pkg/debian/build.sh
+++ b/pkg/debian/build.sh
@@ -76,7 +76,7 @@ cat << EOF > "${WEBROOT}/DEBIAN/control"
 Package: ${APP_NAME}-web
 Version: ${APP_LONG_VERSION}
 Architecture: all
-Depends: ${APP_NAME}-server, apache2, libapache2-mod-wsgi-py3
+Depends: ${APP_NAME}-server, apache2, libapache2-mod-wsgi-py3, libgssapi-krb5-2
 Maintainer: pgAdmin Development Team <[email protected]>
 Description: The web interface for pgAdmin, hosted under Apache HTTPD. pgAdmin is the most popular and feature rich Open Source administration and development platform for PostgreSQL, the most advanced Open Source database in the world.
 EOF
diff --git a/pkg/debian/setup.sh b/pkg/debian/setup.sh
index 839132ea2..89ddb7792 100755
--- a/pkg/debian/setup.sh
+++ b/pkg/debian/setup.sh
@@ -30,5 +30,5 @@ apt update
 
 # Install pre-reqs
 echo "Installing build pre-requisites..."
-apt install -y build-essential python3-dev python3-venv python3-sphinx python3-wheel libpq-dev libffi-dev qtbase5-dev qt5-qmake nodejs yarn
+apt install -y build-essential python3-dev python3-venv python3-sphinx python3-wheel libpq-dev libffi-dev qtbase5-dev qt5-qmake nodejs yarn libkrb5-dev
 
diff --git a/pkg/redhat/build.sh b/pkg/redhat/build.sh
index d501946a3..48be6e549 100755
--- a/pkg/redhat/build.sh
+++ b/pkg/redhat/build.sh
@@ -131,9 +131,9 @@ Summary:	The web interface for pgAdmin, hosted under Apache HTTPD.
 License:	PostgreSQL
 URL:		https://www.pgadmin.org/
 %if 0%{?rhel} && 0%{?rhel} == 7
-Requires:	${APP_NAME}-server, httpd, pgadmin4-python3-mod_wsgi
+Requires:	${APP_NAME}-server, httpd, pgadmin4-python3-mod_wsgi, krb5-libs
 %else
-Requires:	${APP_NAME}-server, httpd, python3-mod_wsgi
+Requires:	${APP_NAME}-server, httpd, python3-mod_wsgi, krb5-libs
 %endif
 
 %description
diff --git a/pkg/redhat/setup.sh b/pkg/redhat/setup.sh
index 5ad659498..ffd3f6546 100755
--- a/pkg/redhat/setup.sh
+++ b/pkg/redhat/setup.sh
@@ -35,10 +35,10 @@ echo "Installing build pre-requisites..."
 yum groupinstall -y "Development Tools"
 
 if [ ${OS_VERSION} == 7 ]; then
-    yum install -y expect fakeroot httpd-devel qt5-qtbase-devel postgresql12-devel python3-devel nodejs yarn rpm-build rpm-sign yum-utils
+    yum install -y expect fakeroot httpd-devel qt5-qtbase-devel postgresql12-devel python3-devel nodejs yarn rpm-build rpm-sign yum-utils krb5-devel
     pip3 install sphinx
 else
-    yum install -y expect fakeroot qt5-qtbase-devel postgresql12-devel python3-devel python3-sphinx nodejs yarn rpm-build rpm-sign yum-utils
+    yum install -y expect fakeroot qt5-qtbase-devel postgresql12-devel python3-devel python3-sphinx nodejs yarn rpm-build rpm-sign yum-utils krb5-devel
 fi
 
 # Setup RPM macros for signing
diff --git a/requirements.txt b/requirements.txt
index f391c08df..d58e1ebfd 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -43,3 +43,6 @@ cryptography<=3.0;
 sshtunnel>=0.1.5
 ldap3>=2.5.1
 Flask-BabelEx>=0.9.4
+gssapi>=1.6.11; python_version >= '3.6'
+gssapi==1.6.2; python_version <= '3.5'
+
diff --git a/web/config.py b/web/config.py
index 2b314fe69..d02a91380 100644
--- a/web/config.py
+++ b/web/config.py
@@ -535,7 +535,7 @@ ENHANCED_COOKIE_PROTECTION = True
 ##########################################################################
 
 # Default setting is internal
-# External Supported Sources: ldap
+# External Supported Sources: ldap, kerberos
 # Multiple authentication can be achieved by setting this parameter to
 # ['ldap', 'internal']. pgAdmin will authenticate the user with ldap first,
 # in case of failure internal authentication will be done.
@@ -618,6 +618,26 @@ LDAP_CA_CERT_FILE = ''
 LDAP_CERT_FILE = ''
 LDAP_KEY_FILE = ''
 
+
+##########################################################################
+# Kerberos Configuration
+##########################################################################
+
+KRB_APP_HOST_NAME = DEFAULT_SERVER
+
+# If the default_keytab_name is not set in krb5.conf or
+# the KRB_KTNAME environment variable is not set then, explicitly set
+# the Keytab file
+
+KRB_KTNAME = '<KRB5_KEYTAB_FILE>'
+
+# After kerberos authentication, user will be added into the SQLite database
+# automatically, if set to True.
+# Set it to False, if user should not be added automatically,
+# in this case Admin has to add the user manually in the SQLite database.
+
+KRB_AUTO_CREATE_USER = True
+
 ##########################################################################
 # Local config settings
 ##########################################################################
diff --git a/web/pgAdmin4.py b/web/pgAdmin4.py
index ff9c00f50..14afe7dc1 100644
--- a/web/pgAdmin4.py
+++ b/web/pgAdmin4.py
@@ -35,6 +35,9 @@ else:
 import config
 from pgadmin import create_app
 from pgadmin.utils import u_encode, fs_encoding, file_quote
+from pgadmin.utils.constants import INTERNAL, LDAP,\
+    KERBEROS, SUPPORTED_AUTH_SOURCES
+
 # Get the config database schema version. We store this in pgadmin.model
 # as it turns out that putting it in the config files isn't a great idea
 from pgadmin.model import SCHEMA_VERSION
@@ -96,15 +99,11 @@ if config.SERVER_MODE:
     app.wsgi_app = ReverseProxied(app.wsgi_app)
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
-app.PGADMIN_SUPPORTED_AUTH_SOURCE = ['internal', 'ldap']
+
 if len(config.AUTHENTICATION_SOURCES) > 0:
     app.PGADMIN_EXTERNAL_AUTH_SOURCE = config.AUTHENTICATION_SOURCES[0]
 else:
-    app.PGADMIN_EXTERNAL_AUTH_SOURCE = app.PGADMIN_DEFAULT_AUTH_SOURCE
-
-app.logger.debug(
-    "Authentication Source: %s" % app.PGADMIN_DEFAULT_AUTH_SOURCE)
+    app.PGADMIN_EXTERNAL_AUTH_SOURCE = INTERNAL
 
 # Start the web server. The port number should have already been set by the
 # runtime if we're running in desktop mode, otherwise we'll just use the
diff --git a/web/pgadmin/__init__.py b/web/pgadmin/__init__.py
index dae0b8cd2..a73335371 100644
--- a/web/pgadmin/__init__.py
+++ b/web/pgadmin/__init__.py
@@ -43,6 +43,7 @@ from pgadmin.utils.ajax import internal_server_error, make_json_response
 from pgadmin.utils.csrf import pgCSRFProtect
 from pgadmin import authenticate
 from pgadmin.utils.security_headers import SecurityHeaders
+from pgadmin.utils.constants import KERBEROS
 
 # Explicitly set the mime-types so that a corrupted windows registry will not
 # affect pgAdmin 4 to be load properly. This will avoid the issues that may
@@ -674,6 +675,7 @@ def create_app(app_name=None):
 
         # Check the auth key is valid, if it's set, and we're not in server
         # mode, and it's not a help file request.
+
         if not config.SERVER_MODE and app.PGADMIN_INT_KEY != '' and ((
             'key' not in request.args or
             request.args['key'] != app.PGADMIN_INT_KEY) and
@@ -695,11 +697,19 @@ def create_app(app_name=None):
                 )
                 abort(401)
             login_user(user)
+        elif config.SERVER_MODE and\
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE ==\
+                KERBEROS and \
+                not current_user.is_authenticated and \
+                request.endpoint in ('redirects.index', 'security.login'):
+            return authenticate.login()
 
         # if the server is restarted the in memory key will be lost
         # but the user session may still be active. Logout the user
         # to get the key again when login
         if config.SERVER_MODE and current_user.is_authenticated and \
+                app.PGADMIN_EXTERNAL_AUTH_SOURCE != \
+                KERBEROS and \
                 current_app.keyManager.get() is None and \
                 request.endpoint not in ('security.login', 'security.logout'):
             logout_user()
diff --git a/web/pgadmin/authenticate/__init__.py b/web/pgadmin/authenticate/__init__.py
index 7ede73cd8..1fdb66cf7 100644
--- a/web/pgadmin/authenticate/__init__.py
+++ b/web/pgadmin/authenticate/__init__.py
@@ -11,16 +11,21 @@
 
 import flask
 import pickle
-from flask import current_app, flash
+from flask import current_app, flash, Response, request, url_for,\
+    render_template
 from flask_babelex import gettext
 from flask_security import current_user
 from flask_security.views import _security, _ctx
 from flask_security.utils import config_value, get_post_logout_redirect, \
-    get_post_login_redirect
+    get_post_login_redirect, logout_user
+
 from flask import session
 
 import config
 from pgadmin.utils import PgAdminModule
+from pgadmin.utils.constants import KERBEROS
+from pgadmin.utils.csrf import pgCSRFProtect
+
 from .registry import AuthSourceRegistry
 
 MODULE_NAME = 'authenticate'
@@ -28,12 +33,34 @@ MODULE_NAME = 'authenticate'
 
 class AuthenticateModule(PgAdminModule):
     def get_exposed_url_endpoints(self):
-        return ['authenticate.login']
+        return ['authenticate.login',
+                'authenticate.kerberos_login',
+                'authenticate.kerberos_logout']
 
 
 blueprint = AuthenticateModule(MODULE_NAME, __name__, static_url_path='')
 
 
[email protected]("/login/kerberos",
+                 endpoint="kerberos_login", methods=["GET"])
[email protected]
+def kerberos_login():
+    logout_user()
+    return Response(render_template("browser/kerberos_login.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
[email protected]("/logout/kerberos",
+                 endpoint="kerberos_logout", methods=["GET"])
[email protected]
+def kerberos_logout():
+    logout_user()
+    return Response(render_template("browser/kerberos_logout.html",
+                                    login_url=url_for('security.login'),
+                                    ))
+
+
 @blueprint.route('/login', endpoint='login', methods=['GET', 'POST'])
 def login():
     """
@@ -56,15 +83,24 @@ def login():
     if status:
         # Login the user
         status, msg = auth_obj.login()
+        current_auth_obj = auth_obj.as_dict()
         if not status:
+            if current_auth_obj['current_source'] ==\
+                    KERBEROS:
+                return flask.redirect('{0}?next={1}'.format(url_for(
+                    'authenticate.kerberos_login'), url_for('browser.index')))
+
             flash(gettext(msg), 'danger')
             return flask.redirect(get_post_logout_redirect())
 
-        session['_auth_source_manager_obj'] = auth_obj.as_dict()
+        session['_auth_source_manager_obj'] = current_auth_obj
         return flask.redirect(get_post_login_redirect())
 
+    elif isinstance(msg, Response):
+        return msg
     flash(gettext(msg), 'danger')
-    return flask.redirect(get_post_logout_redirect())
+    response = flask.redirect(get_post_logout_redirect())
+    return response
 
 
 class AuthSourceManager():
@@ -75,6 +111,7 @@ class AuthSourceManager():
         self.auth_sources = sources
         self.source = None
         self.source_friendly_name = None
+        self.current_source = None
 
     def as_dict(self):
         """
@@ -84,9 +121,17 @@ class AuthSourceManager():
         res = dict()
         res['source_friendly_name'] = self.source_friendly_name
         res['auth_sources'] = self.auth_sources
+        res['current_source'] = self.current_source
 
         return res
 
+    def set_current_source(self, source):
+        self.current_source = source
+
+    @property
+    def get_current_source(self, source):
+        return self.current_source
+
     def set_source(self, source):
         self.source = source
 
@@ -115,9 +160,33 @@ class AuthSourceManager():
         msg = None
         for src in self.auth_sources:
             source = get_auth_sources(src)
+            current_app.logger.debug(
+                "Authentication initiated via source: %s" %
+                source.get_source_name())
+
+            if self.form.data['email'] and self.form.data['password'] and \
+                    source.get_source_name() == KERBEROS:
+                continue
+
             status, msg = source.authenticate(self.form)
+
+            # When server sends Unauthorized header to get the ticket over HTTP
+            # OR When kerberos authentication failed while accessing pgadmin,
+            # we need to break the loop as no need to authenticate further
+            # even if the authentication sources set to multiple
+            if not status:
+                if (hasattr(msg, 'status') and
+                    msg.status == '401 UNAUTHORIZED') or\
+                        (source.get_source_name() ==
+                         KERBEROS and
+                         request.method == 'GET'):
+                    break
+
             if status:
                 self.set_source(source)
+                self.set_current_source(source.get_source_name())
+                if msg is not None and 'username' in msg:
+                    self.form._fields['email'].data = msg['username']
                 return status, msg
         return status, msg
 
@@ -125,6 +194,9 @@ class AuthSourceManager():
         status, msg = self.source.login(self.form)
         if status:
             self.set_source_friendly_name(self.source.get_friendly_name())
+            current_app.logger.debug(
+                "Authentication and Login successfully done via source : %s" %
+                self.source.get_source_name())
         return status, msg
 
 
diff --git a/web/pgadmin/authenticate/internal.py b/web/pgadmin/authenticate/internal.py
index 804a487c7..484a7fdca 100644
--- a/web/pgadmin/authenticate/internal.py
+++ b/web/pgadmin/authenticate/internal.py
@@ -18,6 +18,7 @@ from flask_babelex import gettext
 from .registry import AuthSourceRegistry
 from pgadmin.model import User
 from pgadmin.utils.validation_utils import validate_email
+from pgadmin.utils.constants import INTERNAL
 
 
 @six.add_metaclass(AuthSourceRegistry)
@@ -31,7 +32,11 @@ class BaseAuthentication(object):
         'INVALID_EMAIL': gettext('Email/Username is not valid')
     }
 
-    @abstractproperty
+    @abstractmethod
+    def get_source_name(self):
+        pass
+
+    @abstractmethod
     def get_friendly_name(self):
         pass
 
@@ -82,6 +87,9 @@ class BaseAuthentication(object):
 
 class InternalAuthentication(BaseAuthentication):
 
+    def get_source_name(self):
+        return INTERNAL
+
     def get_friendly_name(self):
         return gettext("internal")
 
diff --git a/web/pgadmin/authenticate/kerberos.py b/web/pgadmin/authenticate/kerberos.py
new file mode 100644
index 000000000..01bfb36f2
--- /dev/null
+++ b/web/pgadmin/authenticate/kerberos.py
@@ -0,0 +1,152 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+"""A blueprint module implementing the Spnego/Kerberos authentication."""
+
+import base64
+from os import environ
+
+from werkzeug.datastructures import Headers
+from flask_babelex import gettext
+from flask import Flask, request, Response, session,\
+    current_app, render_template, flash
+
+import config
+from pgadmin.model import User, ServerGroup, db, Role
+from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import KERBEROS
+
+from flask_security.views import _security, _commit, _ctx
+from werkzeug.datastructures import MultiDict
+
+from .internal import BaseAuthentication
+
+try:
+    import gssapi
+    KERBEROS_AUTH_AVAILABLE = True
+except ImportError:
+    # Do not fail at this time, as this could be a desktop mode.
+    # Instead throw the runtime error, when the server attempts
+    # to use this authentication method.
+    KERBEROS_AUTH_AVAILABLE = False
+
+# Set the Kerberos config file
+if config.KRB_KTNAME and config.KRB_KTNAME != '<KRB5_KEYTAB_FILE>':
+    environ['KRB5_KTNAME'] = config.KRB_KTNAME
+
+
+class KerberosAuthentication(BaseAuthentication):
+
+    def get_source_name(self):
+        return KERBEROS
+
+    def get_friendly_name(self):
+        return gettext("kerberos")
+
+    def validate(self, form):
+        return True
+
+    def authenticate(self, frm):
+
+        if KERBEROS_AUTH_AVAILABLE is not True:
+            raise RuntimeError(gettext(
+                "Kerberos authentication can't be used as"
+                " GSSAPI module couldn't be loaded."
+            ))
+
+        retval = [True, None]
+        negotiate = False
+        headers = Headers()
+        authorization = request.headers.get("Authorization", None)
+        form_class = _security.login_form
+
+        if request.json:
+            form = form_class(MultiDict(request.json))
+        else:
+            form = form_class()
+
+        try:
+            if authorization is not None:
+                auth_header = authorization.split()
+                if auth_header[0] == 'Negotiate':
+                    status, negotiate = self.negotiate_start(auth_header[1])
+
+                    if status:
+                        # Saving the first 15 characters of the kerberos key
+                        # to encrypt/decrypt database password
+                        session['kerberos_key'] = auth_header[1][0:15]
+                        # Create user
+                        retval = self.__auto_create_user(
+                            str(negotiate.initiator_name))
+                    elif isinstance(negotiate, Exception):
+                        flash(gettext(negotiate), 'danger')
+                        retval = [status,
+                                  Response(render_template(
+                                      "security/login_user.html",
+                                      login_user_form=form))]
+                    else:
+                        headers.add('WWW-Authenticate', 'Negotiate ' +
+                                    str(base64.b64encode(negotiate), 'utf-8'))
+                        return False, Response("Success", 200, headers)
+            else:
+                flash(gettext("Kerberos authentication failed."
+                              " Couldn't find kerberos ticket."), 'danger')
+                headers.add('WWW-Authenticate', 'Negotiate')
+                retval = [False,
+                          Response(render_template(
+                              "security/login_user.html",
+                              login_user_form=form), 401, headers)]
+        finally:
+            if negotiate is not False:
+                self.negotiate_end(negotiate)
+        return retval
+
+    def negotiate_start(self, in_token):
+        svc_princ = gssapi.Name('HTTP@%s' % config.KRB_APP_HOST_NAME,
+                                name_type=gssapi.NameType.hostbased_service)
+        cname = svc_princ.canonicalize(gssapi.MechType.kerberos)
+
+        try:
+            server_creds = gssapi.Credentials(usage='accept', name=cname)
+            context = gssapi.SecurityContext(creds=server_creds)
+            out_token = context.step(base64.b64decode(in_token))
+        except Exception as e:
+            current_app.logger.exception(e)
+            return False, e
+
+        if out_token and not context.complete:
+            return False, out_token
+        if context.complete:
+            return True, context
+        else:
+            return False, None
+
+    def negotiate_end(self, context):
+        # Free gss_cred_id_t
+        del_creds = getattr(context, 'delegated_creds', None)
+        if del_creds:
+            deleg_creds = context.delegated_creds
+            del(deleg_creds)
+
+    def __auto_create_user(self, username):
+        """Add the ldap user to the internal SQLite database."""
+        username = str(username)
+        if config.KRB_AUTO_CREATE_USER:
+            user = User.query.filter_by(
+                username=username).first()
+            if user is None:
+                return create_user({
+                    'username': username,
+                    'email': username,
+                    'role': 2,
+                    'active': True,
+                    'auth_source': KERBEROS
+                })
+
+        return True, {'username': username}
diff --git a/web/pgadmin/authenticate/ldap.py b/web/pgadmin/authenticate/ldap.py
index a9eca110f..2f0f61b7c 100644
--- a/web/pgadmin/authenticate/ldap.py
+++ b/web/pgadmin/authenticate/ldap.py
@@ -23,6 +23,7 @@ from .internal import BaseAuthentication
 from pgadmin.model import User, ServerGroup, db, Role
 from flask import current_app
 from pgadmin.tools.user_management import create_user
+from pgadmin.utils.constants import LDAP
 
 
 ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
@@ -31,6 +32,9 @@ ERROR_SEARCHING_LDAP_DIRECTORY = "Error searching the LDAP directory: {}"
 class LDAPAuthentication(BaseAuthentication):
     """Ldap Authentication Class"""
 
+    def get_source_name(self):
+        return LDAP
+
     def get_friendly_name(self):
         return gettext("ldap")
 
@@ -151,7 +155,7 @@ class LDAPAuthentication(BaseAuthentication):
                     'email': user_email,
                     'role': 2,
                     'active': True,
-                    'auth_source': 'ldap'
+                    'auth_source': LDAP
                 })
 
         return True, None
diff --git a/web/pgadmin/browser/__init__.py b/web/pgadmin/browser/__init__.py
index 1bae28f9c..c0ad869a1 100644
--- a/web/pgadmin/browser/__init__.py
+++ b/web/pgadmin/browser/__init__.py
@@ -29,7 +29,7 @@ from flask_security.recoverable import reset_password_token_status, \
     generate_reset_password_token, update_password
 from flask_security.signals import reset_password_instructions_sent
 from flask_security.utils import config_value, do_flash, get_url, \
-    get_message, slash_url_suffix, login_user, send_mail
+    get_message, slash_url_suffix, login_user, send_mail, logout_user
 from flask_security.views import _security, _commit, _ctx
 from werkzeug.datastructures import MultiDict
 
@@ -47,7 +47,8 @@ from pgadmin.utils.master_password import validate_master_password, \
     set_masterpass_check_text, cleanup_master_password, get_crypt_key, \
     set_crypt_key, process_masterpass_disabled
 from pgadmin.model import User
-from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE
+from pgadmin.utils.constants import MIMETYPE_APP_JS, PGADMIN_NODE,\
+    INTERNAL, KERBEROS
 
 try:
     from flask_security.views import default_render_json
@@ -280,7 +281,8 @@ class BrowserModule(PgAdminModule):
                 'browser.check_master_password',
                 'browser.set_master_password',
                 'browser.reset_master_password',
-                'browser.lock_layout']
+                'browser.lock_layout'
+                ]
 
 
 blueprint = BrowserModule(MODULE_NAME, __name__)
@@ -539,6 +541,12 @@ class BrowserPluginModule(PgAdminModule):
 
 
 def _get_logout_url():
+    if config.SERVER_MODE and\
+            session['_auth_source_manager_obj']['current_source'] == \
+            KERBEROS:
+        return '{0}?next={1}'.format(url_for(
+            'authenticate.kerberos_logout'), url_for(BROWSER_INDEX))
+
     return '{0}?next={1}'.format(
         url_for('security.logout'), url_for(BROWSER_INDEX))
 
@@ -664,13 +672,18 @@ def index():
     auth_only_internal = False
     auth_source = []
 
+    session['allow_save_password'] = True
+
     if config.SERVER_MODE:
         if len(config.AUTHENTICATION_SOURCES) == 1\
-                and 'internal' in config.AUTHENTICATION_SOURCES:
+                and INTERNAL in config.AUTHENTICATION_SOURCES:
             auth_only_internal = True
         auth_source = session['_auth_source_manager_obj'][
             'source_friendly_name']
 
+        if session['_auth_source_manager_obj']['current_source'] == KERBEROS:
+            session['allow_save_password'] = False
+
     response = Response(render_template(
         MODULE_NAME + "/index.html",
         username=current_user.username,
@@ -1086,7 +1099,7 @@ if hasattr(config, 'SECURITY_RECOVERABLE') and config.SECURITY_RECOVERABLE:
             # Check the Authentication source of the User
             user = User.query.filter_by(
                 email=form.data['email'],
-                auth_source=current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+                auth_source=INTERNAL
             ).first()
 
             if user is None:
diff --git a/web/pgadmin/browser/server_groups/servers/__init__.py b/web/pgadmin/browser/server_groups/servers/__init__.py
index ecc1281a2..5daef8120 100644
--- a/web/pgadmin/browser/server_groups/servers/__init__.py
+++ b/web/pgadmin/browser/server_groups/servers/__init__.py
@@ -10,7 +10,7 @@
 import simplejson as json
 import pgadmin.browser.server_groups as sg
 from flask import render_template, request, make_response, jsonify, \
-    current_app, url_for
+    current_app, url_for, session
 from flask_babelex import gettext
 from flask_security import current_user, login_required
 from pgadmin.browser.server_groups.servers.types import ServerType
@@ -1822,7 +1822,13 @@ class ServerNode(PGChildNodeView):
                     _=gettext,
                     service=server.service,
                     prompt_tunnel_password=prompt_tunnel_password,
-                    prompt_password=prompt_password
+                    prompt_password=prompt_password,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
+                    allow_save_tunnel_password=True if
+                    config.ALLOW_SAVE_TUNNEL_PASSWORD and
+                    session['allow_save_password'] else False
                 )
             )
         else:
@@ -1836,6 +1842,9 @@ class ServerNode(PGChildNodeView):
                     errmsg=errmsg,
                     service=server.service,
                     _=gettext,
+                    allow_save_password=True if
+                    config.ALLOW_SAVE_PASSWORD and
+                    session['allow_save_password'] else False,
                 )
             )
 
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
index 9b2c425e3..35f4e2a16 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/password.html
@@ -19,7 +19,7 @@
             <div class="col-sm-10">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
index 5de642f85..e34a257f2 100644
--- a/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
+++ b/web/pgadmin/browser/server_groups/servers/templates/servers/tunnel_password.html
@@ -15,7 +15,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_tunnel_password" name="save_tunnel_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_TUNNEL_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_tunnel_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_tunnel_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
@@ -39,7 +39,7 @@
             <div class="w-100">
                 <div class="custom-control custom-checkbox">
                     <input class="custom-control-input" id="save_password" name="save_password" type="checkbox"
-                           {% if not config.ALLOW_SAVE_PASSWORD  %}disabled{% endif %}
+                           {% if not allow_save_password  %}disabled{% endif %}
                     >
                     <label class="custom-control-label" for="save_password" class="ml-1">{{ _('Save Password') }}</label>
                 </div>
diff --git a/web/pgadmin/browser/templates/browser/kerberos_login.html b/web/pgadmin/browser/templates/browser/kerberos_login.html
new file mode 100644
index 000000000..c112e3196
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_login.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Login Failed.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/templates/browser/kerberos_logout.html b/web/pgadmin/browser/templates/browser/kerberos_logout.html
new file mode 100644
index 000000000..430dc6f25
--- /dev/null
+++ b/web/pgadmin/browser/templates/browser/kerberos_logout.html
@@ -0,0 +1,16 @@
+{% extends "base.html" %}
+{% block body %}
+<div class="container-fluid change_pass">
+    <div class="row align-items-center h-100">
+        <div class="col-md-5"></div>
+        <div class="col-md-5">
+            <div class="panel-header h4"><i class="app-icon pg-icon-blue" aria-hidden="true"></i> {{ _('%(appname)s', appname=config.APP_NAME) }}</div>
+            <div class="panel-body">
+                <div class="d-block text-color pb-3 h5">{{ _('Logged out successfully.') }}</div>
+                <div><a href="{{ login_url }}">Click here</a> to Login again.</div>
+            </div>
+        </div>
+        <div class="col-md-4"></div>
+    </div>
+</div>
+{% endblock %}
diff --git a/web/pgadmin/browser/tests/test_kerberos_with_mocking.py b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
new file mode 100644
index 000000000..f87ce5521
--- /dev/null
+++ b/web/pgadmin/browser/tests/test_kerberos_with_mocking.py
@@ -0,0 +1,104 @@
+##########################################################################
+#
+# pgAdmin 4 - PostgreSQL Tools
+#
+# Copyright (C) 2013 - 2020, The pgAdmin Development Team
+# This software is released under the PostgreSQL Licence
+#
+##########################################################################
+
+import config as app_config
+from pgadmin.utils.route import BaseTestGenerator
+from regression.python_test_utils import test_utils as utils
+from pgadmin.authenticate.registry import AuthSourceRegistry
+from unittest.mock import patch, MagicMock
+
+
+class KerberosLoginMockTestCase(BaseTestGenerator):
+    """
+    This class checks Spnego/Kerberos login functionality by mocking
+    HTTP negotiate authentication.
+    """
+
+    scenarios = [
+        ('Spnego/Kerberos Authentication: Test Unauthorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=1
+        )),
+        ('Spnego/Kerberos Authentication: Test Authorized', dict(
+            auth_source=['kerberos'],
+            auto_create_user=True,
+            flag=2
+        ))
+    ]
+
+    @classmethod
+    def setUpClass(cls):
+        """
+        We need to logout the test client as we are testing
+        spnego/kerberos login scenarios.
+        """
+        cls.tester.logout()
+
+    def setUp(self):
+        app_config.AUTHENTICATION_SOURCES = self.auth_source
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'kerberos'
+
+    def runTest(self):
+        """This function checks spnego/kerberos login functionality."""
+        if self.flag == 1:
+            self.test_unauthorized()
+        elif self.flag == 2:
+            if app_config.SERVER_MODE is False:
+                self.skipTest(
+                    "Can not run Kerberos Authentication in the Desktop mode."
+                )
+
+            self.test_authorized()
+
+    def test_unauthorized(self):
+        """
+        Ensure that when client sends the first request,
+        the Negotiate request is sent.
+        """
+        res = self.tester.login(None, None, True)
+        self.assertEqual(res.status_code, 401)
+        self.assertEqual(res.headers.get('www-authenticate'), 'Negotiate')
+
+    def test_authorized(self):
+        """
+        Ensure that when the client sends an correct authorization token,
+        they receive a 200 OK response and the user principal is extracted and
+        passed on to the routed method.
+        """
+
+        class delCrads:
+            def __init__(self):
+                self.initiator_name = '[email protected]'
+        del_crads = delCrads()
+
+        AuthSourceRegistry.registry['kerberos'].negotiate_start = MagicMock(
+            return_value=[True, del_crads])
+        res = self.tester.login(None,
+                                None,
+                                True,
+                                headers={'Authorization': 'Negotiate CTOKEN'}
+                                )
+        self.assertEqual(res.status_code, 200)
+        respdata = 'Gravatar image for %s' % del_crads.initiator_name
+        self.assertTrue(respdata in res.data.decode('utf8'))
+
+    def tearDown(self):
+        self.app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
+        self.tester.logout()
+
+    @classmethod
+    def tearDownClass(cls):
+        """
+        We need to again login the test client as soon as test scenarios
+        finishes.
+        """
+        cls.tester.logout()
+        app_config.AUTHENTICATION_SOURCES = ['internal']
+        utils.login_tester_account(cls.tester)
diff --git a/web/pgadmin/tools/datagrid/__init__.py b/web/pgadmin/tools/datagrid/__init__.py
index 2405a498d..05ed998c6 100644
--- a/web/pgadmin/tools/datagrid/__init__.py
+++ b/web/pgadmin/tools/datagrid/__init__.py
@@ -25,7 +25,7 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_json_response, bad_request, \
     internal_server_error, unauthorized
 
-from config import PG_DEFAULT_DRIVER
+from config import PG_DEFAULT_DRIVER, ALLOW_SAVE_PASSWORD
 from pgadmin.model import Server, User
 from pgadmin.utils.driver import get_driver
 from pgadmin.utils.exception import ConnectionLost, SSHTunnelConnectionLost
@@ -402,6 +402,9 @@ def _init_query_tool(trans_id, connect, sgid, sid, did, **kwargs):
                             username=user,
                             errmsg=msg,
                             _=gettext,
+                            allow_save_password=True if
+                            ALLOW_SAVE_PASSWORD and
+                            session['allow_save_password'] else False,
                         )
                     ), '', ''
                 else:
diff --git a/web/pgadmin/tools/user_management/__init__.py b/web/pgadmin/tools/user_management/__init__.py
index 8641130c4..ce280a3d2 100644
--- a/web/pgadmin/tools/user_management/__init__.py
+++ b/web/pgadmin/tools/user_management/__init__.py
@@ -13,7 +13,7 @@ import simplejson as json
 import re
 
 from flask import render_template, request, \
-    url_for, Response, abort, current_app
+    url_for, Response, abort, current_app, session
 from flask_babelex import gettext as _
 from flask_security import login_required, roles_required, current_user
 from flask_security.utils import encrypt_password
@@ -24,7 +24,8 @@ from pgadmin.utils import PgAdminModule
 from pgadmin.utils.ajax import make_response as ajax_response, \
     make_json_response, bad_request, internal_server_error, forbidden
 from pgadmin.utils.csrf import pgCSRFProtect
-from pgadmin.utils.constants import MIMETYPE_APP_JS
+from pgadmin.utils.constants import MIMETYPE_APP_JS, INTERNAL,\
+    SUPPORTED_AUTH_SOURCES, KERBEROS
 from pgadmin.utils.validation_utils import validate_email
 from pgadmin.model import db, Role, User, UserPreference, Server, \
     ServerGroup, Process, Setting
@@ -167,11 +168,13 @@ def current_user_info():
                 config.SERVER_MODE is True
                 else 'postgres'
             ),
-            allow_save_password='true' if config.ALLOW_SAVE_PASSWORD
+            allow_save_password='true' if
+            config.ALLOW_SAVE_PASSWORD and session['allow_save_password']
             else 'false',
-            allow_save_tunnel_password='true'
-            if config.ALLOW_SAVE_TUNNEL_PASSWORD else 'false',
-            auth_sources=config.AUTHENTICATION_SOURCES,
+            allow_save_tunnel_password='true' if
+            config.ALLOW_SAVE_TUNNEL_PASSWORD and session[
+                'allow_save_password'] else 'false',
+            auth_sources=config.AUTHENTICATION_SOURCES
         ),
         status=200,
         mimetype=MIMETYPE_APP_JS
@@ -254,10 +257,10 @@ def _create_new_user(new_data):
     :return: Return new created user.
     """
     auth_source = new_data['auth_source'] if 'auth_source' in new_data \
-        else current_app.PGADMIN_DEFAULT_AUTH_SOURCE
+        else INTERNAL
     username = new_data['username'] if \
         'username' in new_data and auth_source != \
-        current_app.PGADMIN_DEFAULT_AUTH_SOURCE else new_data['email']
+        INTERNAL else new_data['email']
     email = new_data['email'] if 'email' in new_data else None
     password = new_data['password'] if 'password' in new_data else None
 
@@ -279,7 +282,7 @@ def _create_new_user(new_data):
 
 def create_user(data):
     if 'auth_source' in data and data['auth_source'] != \
-            current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+            INTERNAL:
         req_params = ('username', 'role', 'active', 'auth_source')
     else:
         req_params = ('email', 'role', 'active', 'newPassword',
@@ -380,7 +383,7 @@ def update(uid):
     )
 
     # Username and email can not be changed for internal users
-    if usr.auth_source == current_app.PGADMIN_DEFAULT_AUTH_SOURCE:
+    if usr.auth_source == INTERNAL:
         non_editable_params = ('username', 'email')
 
         for f in non_editable_params:
@@ -463,7 +466,7 @@ def role(rid):
 )
 def auth_sources():
     sources = []
-    for source in current_app.PGADMIN_SUPPORTED_AUTH_SOURCE:
+    for source in SUPPORTED_AUTH_SOURCES:
         sources.append({'label': source, 'value': source})
 
     return ajax_response(
diff --git a/web/pgadmin/utils/constants.py b/web/pgadmin/utils/constants.py
index 0a2261f05..5fd942304 100644
--- a/web/pgadmin/utils/constants.py
+++ b/web/pgadmin/utils/constants.py
@@ -47,3 +47,12 @@ ERROR_FETCHING_ROLE_INFORMATION = gettext(
     'Error fetching role information from the database server.')
 
 ERROR_FETCHING_DATA = gettext('Unable to fetch data.')
+
+# Authentication Sources
+INTERNAL = 'internal'
+LDAP = 'ldap'
+KERBEROS = 'kerberos'
+
+SUPPORTED_AUTH_SOURCES = [INTERNAL,
+                          LDAP,
+                          KERBEROS]
diff --git a/web/pgadmin/utils/master_password.py b/web/pgadmin/utils/master_password.py
index 759bf36e0..629eec941 100644
--- a/web/pgadmin/utils/master_password.py
+++ b/web/pgadmin/utils/master_password.py
@@ -1,8 +1,9 @@
 import config
-from flask import current_app
+from flask import current_app, session
 from flask_login import current_user
 from pgadmin.model import db, User, Server
 from pgadmin.utils.crypto import encrypt, decrypt
+from pgadmin.utils.constants import KERBEROS
 
 
 MASTERPASS_CHECK_TEXT = 'ideas are bulletproof'
@@ -32,6 +33,11 @@ def get_crypt_key():
     elif config.MASTER_PASSWORD_REQUIRED \
             and not config.SERVER_MODE and enc_key is None:
         return False, None
+    elif config.SERVER_MODE and \
+            session['_auth_source_manager_obj']['source_friendly_name']\
+            == KERBEROS:
+        return True, session['kerberos_key'] if 'kerberos_key' in session \
+            else None
     else:
         return True, enc_key
 
diff --git a/web/regression/python_test_utils/csrf_test_client.py b/web/regression/python_test_utils/csrf_test_client.py
index 11d2cfca5..ca4120e18 100644
--- a/web/regression/python_test_utils/csrf_test_client.py
+++ b/web/regression/python_test_utils/csrf_test_client.py
@@ -101,7 +101,8 @@ class TestClient(testing.FlaskClient):
 
             return csrf_token
 
-    def login(self, email, password, _follow_redirects=False):
+    def login(self, email, password, _follow_redirects=False,
+              headers=None):
         if config.SERVER_MODE is True:
             res = self.get('/login', follow_redirects=True)
             csrf_token = self.fetch_csrf(res)
@@ -113,7 +114,8 @@ class TestClient(testing.FlaskClient):
                 email=email, password=password,
                 csrf_token=csrf_token,
             ),
-            follow_redirects=_follow_redirects
+            follow_redirects=_follow_redirects,
+            headers=headers
         )
         self.csrf_token = csrf_token
 
diff --git a/web/regression/runtests.py b/web/regression/runtests.py
index 3328ed3f6..9b794e41f 100644
--- a/web/regression/runtests.py
+++ b/web/regression/runtests.py
@@ -117,9 +117,9 @@ if config.SERVER_MODE is True:
 app.config['WTF_CSRF_ENABLED'] = True
 
 # Authentication sources
-app.PGADMIN_DEFAULT_AUTH_SOURCE = 'internal'
 app.PGADMIN_EXTERNAL_AUTH_SOURCE = 'ldap'
 
+
 app.test_client_class = TestClient
 test_client = app.test_client()
 test_client.setApp(app)


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 09:15  Dave Page <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-18 09:15 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

Hi

On Mon, Jan 18, 2021 at 7:30 AM Khushboo Vashi <
[email protected]> wrote:

> Hi,
>
> Please find the attached updated patch with the below changes:
>
> - Dependencies are added into Linux packages in the RPM/DEBs.
> - Dev packages are added in the setup scripts for Linux.
> - The required packages are added in the Dockerfile.
> - Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
> requirements.txt.
>

1.6.9 is the last release that supports Python 3.4+. We should use that
rather than older versions.


> - krb5 libs are not bundled with the Desktop packages, so added the gssapi
> dependency into the try/catch block.
> - .dockerignore is introduced to ignore unwanted files/folders like
> node_modules etc., which will make the docker build fast. (By Ashesh Vashi)
>

Aside from that one comment above, eyeball review of the build changes
looks good.



>
> Thanks,
> Khushboo
>
> On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:
>
>> And another thought...
>>
>> Some of the Jenkins QA jobs setup the virtual environment for running
>> tests themselves. I believe these might actually be the cause of some of
>> the failures we saw initially with the commit - I'll review those, and
>> ensure they won't try to build the gssapi module from source on Windows.
>>
>> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:
>>
>>> FYI, I did a quick test (and browse of PyPI):
>>>
>>> - On Windows, it seems there is a binary wheel available:
>>>
>>> (gssapi) C:\Users\dpage>pip install gssapi
>>> Collecting gssapi
>>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>>      |████████████████████████████████| 670 kB 3.3 MB/s
>>> Collecting decorator
>>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>>> Installing collected packages: decorator, gssapi
>>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>>
>>> - On macOS, the wheel is built by pip, but it doesn't seem to have any
>>> additional binary dependencies.
>>>
>>> This should simplify things a lot - we just need to ensure the build
>>> scripts use the binary package on Windows, and install the build deps on
>>> the Linux/Docker environments (and update the package builds with the
>>> additional dependencies of course).
>>>
>>>
>>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:
>>>
>>>> Hi Khushboo,
>>>>
>>>> As you know, this has been rolled back as the buildfarm blew up. I
>>>> think there are a number of TODOs that need to be addressed, given that the
>>>> gssapi Python module is dependent on MIT Kerberos:
>>>>
>>>> In the patch:
>>>>
>>>> - Linux packages will need the additional dependencies to be declared
>>>> in the RPM/DEBs.
>>>> - The setup scripts for Linux will need to have the -dev packages added
>>>> as appropriate.
>>>> - The various READMEs that describe how to build packages will need to
>>>> be updated.
>>>> - The Dockerfile will need to be modified to add the required packages.
>>>> - The Windows build will need to be updated so the installer ships
>>>> additional required DLLs.
>>>> - Are there any additional macOS dependencies? If so, they need to be
>>>> handled.
>>>>
>>>> In the buildfarm:
>>>>
>>>> - All Linux build VMs need to be updated with the additional
>>>> dependencies.
>>>> - On Windows, we need to figure out how to build/ship KfW. It's a pain
>>>> to build, which we would typically do ourselves to ensure we're
>>>> consistently using the same buildchain. If we do build it ourselves:
>>>>   - Will the Python package find it during it's build?
>>>>   - We'll need to create a Jenkins job to perform the build.
>>>> - Is any work required on macOS, or does it ship with everything that's
>>>> needed? If not, we'll need to build it, and create the Jenkins job.
>>>>
>>>> One final thought: on Windows/macOS, can we force a binary installation
>>>> from PIP (pip install --only-binary=gssapi gssapi)? If so, will that
>>>> include the required libraries, as psycopg2-binary does?
>>>>
>>>>
>>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>>> [email protected]> wrote:
>>>>
>>>>> Thanks, patch applied.
>>>>>
>>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Please ignore my previous patch, attached the updated one.
>>>>>>
>>>>>> Thanks,
>>>>>> Khushboo
>>>>>>
>>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Please find the attached updated patch.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Khushboo
>>>>>>>
>>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi Khushboo
>>>>>>>>
>>>>>>>> Seems you have attached the wrong patch. Please send the updated
>>>>>>>> patch.
>>>>>>>>
>>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Khushboo
>>>>>>>>>
>>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>
>>>>>>>>>> I've just done the code review. Apart from below, the patch looks
>>>>>>>>>> good to me:
>>>>>>>>>>
>>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>>>> somewhere else and import them.
>>>>>>>>>>
>>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>>
>>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Done
>>>>>>>>>
>>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>>
>>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>>
>>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>>
>>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>  import config
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>>
>>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>>
>>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Removed, it was only for testing.
>>>>>>>>>
>>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>>
>>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>>
>>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>>
>>>>>>>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>>
>>>>>>>>>> +            #     continue
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>>
>>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>>
>>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Done.
>>>>>>>>>
>>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined
>>>>>>>>>> when creating a user.
>>>>>>>>>>
>>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Done.
>>>>>>>>>
>>>>>>>>>> 6) The below URLs belong to the authenticate module. Currently
>>>>>>>>>> they are in the browser module. I would also suggest rephrasing the URL
>>>>>>>>>> from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>>
>>>>>>>>> Done the rephrasing as well as moved to the authentication module.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> Also, even though the method GET works, we should use the POST
>>>>>>>>>> method for login and DELETE for logout.
>>>>>>>>>>
>>>>>>>>> Kerberos_login just redirects the page to the actual login, so no
>>>>>>>>> need for the POST method.
>>>>>>>>> I followed the same method for the Logout user we have used for
>>>>>>>>> the normal user.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>>
>>>>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>>
>>>>>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi Aditya
>>>>>>>>>>>
>>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>>
>>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>>
>>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>>> succeeds.
>>>>>>>>>>>>
>>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server +
>>>>>>>>>>>> Client is documented in a separate file and attached.
>>>>>>>>>>>>
>>>>>>>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>
>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> Thanks,
>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> *Thanks & Regards*
>>>>>>>> *Akshay Joshi*
>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>
>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>
>>>>>>>
>>>>>
>>>>> --
>>>>> *Thanks & Regards*
>>>>> *Akshay Joshi*
>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>
>>>>> *Mobile: +91 976-788-8246*
>>>>>
>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EDB: http://www.enterprisedb.com
>>>>
>>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EDB: http://www.enterprisedb.com
>>>
>>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EDB: http://www.enterprisedb.com
>>
>>

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 09:37  Khushboo Vashi <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Khushboo Vashi @ 2021-01-18 09:37 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

On Mon, Jan 18, 2021 at 2:45 PM Dave Page <[email protected]> wrote:

> Hi
>
> On Mon, Jan 18, 2021 at 7:30 AM Khushboo Vashi <
> [email protected]> wrote:
>
>> Hi,
>>
>> Please find the attached updated patch with the below changes:
>>
>> - Dependencies are added into Linux packages in the RPM/DEBs.
>> - Dev packages are added in the setup scripts for Linux.
>> - The required packages are added in the Dockerfile.
>> - Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
>> requirements.txt.
>>
>
> 1.6.9 is the last release that supports Python 3.4+. We should use that
> rather than older versions.
>
As per the https://pypi.org/project/gssapi/*1.6.9*/, it says Requires: Python
>=3.6.*


>
>
>> - krb5 libs are not bundled with the Desktop packages, so added the
>> gssapi dependency into the try/catch block.
>> - .dockerignore is introduced to ignore unwanted files/folders like
>> node_modules etc., which will make the docker build fast. (By Ashesh Vashi)
>>
>
> Aside from that one comment above, eyeball review of the build changes
> looks good.
>
>
>
>>
>> Thanks,
>> Khushboo
>>
>> On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:
>>
>>> And another thought...
>>>
>>> Some of the Jenkins QA jobs setup the virtual environment for running
>>> tests themselves. I believe these might actually be the cause of some of
>>> the failures we saw initially with the commit - I'll review those, and
>>> ensure they won't try to build the gssapi module from source on Windows.
>>>
>>> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:
>>>
>>>> FYI, I did a quick test (and browse of PyPI):
>>>>
>>>> - On Windows, it seems there is a binary wheel available:
>>>>
>>>> (gssapi) C:\Users\dpage>pip install gssapi
>>>> Collecting gssapi
>>>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>>>      |████████████████████████████████| 670 kB 3.3 MB/s
>>>> Collecting decorator
>>>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>>>> Installing collected packages: decorator, gssapi
>>>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>>>
>>>> - On macOS, the wheel is built by pip, but it doesn't seem to have any
>>>> additional binary dependencies.
>>>>
>>>> This should simplify things a lot - we just need to ensure the build
>>>> scripts use the binary package on Windows, and install the build deps on
>>>> the Linux/Docker environments (and update the package builds with the
>>>> additional dependencies of course).
>>>>
>>>>
>>>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:
>>>>
>>>>> Hi Khushboo,
>>>>>
>>>>> As you know, this has been rolled back as the buildfarm blew up. I
>>>>> think there are a number of TODOs that need to be addressed, given that the
>>>>> gssapi Python module is dependent on MIT Kerberos:
>>>>>
>>>>> In the patch:
>>>>>
>>>>> - Linux packages will need the additional dependencies to be declared
>>>>> in the RPM/DEBs.
>>>>> - The setup scripts for Linux will need to have the -dev packages
>>>>> added as appropriate.
>>>>> - The various READMEs that describe how to build packages will need to
>>>>> be updated.
>>>>> - The Dockerfile will need to be modified to add the required packages.
>>>>> - The Windows build will need to be updated so the installer ships
>>>>> additional required DLLs.
>>>>> - Are there any additional macOS dependencies? If so, they need to be
>>>>> handled.
>>>>>
>>>>> In the buildfarm:
>>>>>
>>>>> - All Linux build VMs need to be updated with the additional
>>>>> dependencies.
>>>>> - On Windows, we need to figure out how to build/ship KfW. It's a pain
>>>>> to build, which we would typically do ourselves to ensure we're
>>>>> consistently using the same buildchain. If we do build it ourselves:
>>>>>   - Will the Python package find it during it's build?
>>>>>   - We'll need to create a Jenkins job to perform the build.
>>>>> - Is any work required on macOS, or does it ship with everything
>>>>> that's needed? If not, we'll need to build it, and create the Jenkins job.
>>>>>
>>>>> One final thought: on Windows/macOS, can we force a binary
>>>>> installation from PIP (pip install --only-binary=gssapi gssapi)? If so,
>>>>> will that include the required libraries, as psycopg2-binary does?
>>>>>
>>>>>
>>>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Thanks, patch applied.
>>>>>>
>>>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Please ignore my previous patch, attached the updated one.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Khushboo
>>>>>>>
>>>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Please find the attached updated patch.
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Khushboo
>>>>>>>>
>>>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi Khushboo
>>>>>>>>>
>>>>>>>>> Seems you have attached the wrong patch. Please send the updated
>>>>>>>>> patch.
>>>>>>>>>
>>>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Khushboo
>>>>>>>>>>
>>>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>>
>>>>>>>>>>> I've just done the code review. Apart from below, the patch
>>>>>>>>>>> looks good to me:
>>>>>>>>>>>
>>>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>>>>> somewhere else and import them.
>>>>>>>>>>>
>>>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>>>
>>>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Done
>>>>>>>>>>
>>>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>>>
>>>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>>>
>>>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>>>
>>>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>  import config
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> +
>>>>>>>>>>>
>>>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>>>
>>>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>>>
>>>>>>>>>>> +
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Removed, it was only for testing.
>>>>>>>>>>
>>>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>>>
>>>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>>>
>>>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>>>
>>>>>>>>>>> +            #         current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>>>
>>>>>>>>>>> +            #     continue
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>>>
>>>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>>>
>>>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Done.
>>>>>>>>>>
>>>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined
>>>>>>>>>>> when creating a user.
>>>>>>>>>>>
>>>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Done.
>>>>>>>>>>
>>>>>>>>>>> 6) The below URLs belong to the authenticate module. Currently
>>>>>>>>>>> they are in the browser module. I would also suggest rephrasing the URL
>>>>>>>>>>> from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>>>
>>>>>>>>>> Done the rephrasing as well as moved to the authentication module.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>> Also, even though the method GET works, we should use the POST
>>>>>>>>>>> method for login and DELETE for logout.
>>>>>>>>>>>
>>>>>>>>>> Kerberos_login just redirects the page to the actual login, so no
>>>>>>>>>> need for the POST method.
>>>>>>>>>> I followed the same method for the Logout user we have used for
>>>>>>>>>> the normal user.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>>>
>>>>>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>>>
>>>>>>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi Aditya
>>>>>>>>>>>>
>>>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>>>
>>>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>>>> succeeds.
>>>>>>>>>>>>>
>>>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server +
>>>>>>>>>>>>> Client is documented in a separate file and attached.
>>>>>>>>>>>>>
>>>>>>>>>>>>> This patch also includes the small fix related to logging #5829
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>
>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> *Thanks & Regards*
>>>>>>>>> *Akshay Joshi*
>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>
>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>>> --
>>>>>> *Thanks & Regards*
>>>>>> *Akshay Joshi*
>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>
>>>>>> *Mobile: +91 976-788-8246*
>>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EDB: http://www.enterprisedb.com
>>>>>
>>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EDB: http://www.enterprisedb.com
>>>>
>>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EDB: http://www.enterprisedb.com
>>>
>>>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EDB: http://www.enterprisedb.com
>
>


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 09:55  Dave Page <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Dave Page @ 2021-01-18 09:55 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

On Mon, Jan 18, 2021 at 9:37 AM Khushboo Vashi <
[email protected]> wrote:

>
>
> On Mon, Jan 18, 2021 at 2:45 PM Dave Page <[email protected]> wrote:
>
>> Hi
>>
>> On Mon, Jan 18, 2021 at 7:30 AM Khushboo Vashi <
>> [email protected]> wrote:
>>
>>> Hi,
>>>
>>> Please find the attached updated patch with the below changes:
>>>
>>> - Dependencies are added into Linux packages in the RPM/DEBs.
>>> - Dev packages are added in the setup scripts for Linux.
>>> - The required packages are added in the Dockerfile.
>>> - Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
>>> requirements.txt.
>>>
>>
>> 1.6.9 is the last release that supports Python 3.4+. We should use that
>> rather than older versions.
>>
> As per the https://pypi.org/project/gssapi/*1.6.9*/, it says Requires: Python
> >=3.6.*
>

I think that's the metadata for the latest package version on the left. If
you read the main text, it says:
Requirements
Basic

   - A working implementation of GSSAPI (such as from MIT Kerberos) which
   includes header files
   - a C compiler (such as GCC)
   - either the enum34 Python package or Python 3.4+
   - the six and decorator python package


For 1.6.10, that changed to:
Requirements
Basic

   - A working implementation of GSSAPI (such as from MIT Kerberos) which
   supports delegation and includes header files
   - a C compiler (such as GCC)
   - Python 3.6+ (older releases support older versions, but are
   unsupported)
   - the decorator python package



>
>>
>>
>>> - krb5 libs are not bundled with the Desktop packages, so added the
>>> gssapi dependency into the try/catch block.
>>> - .dockerignore is introduced to ignore unwanted files/folders like
>>> node_modules etc., which will make the docker build fast. (By Ashesh Vashi)
>>>
>>
>> Aside from that one comment above, eyeball review of the build changes
>> looks good.
>>
>>
>>
>>>
>>> Thanks,
>>> Khushboo
>>>
>>> On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:
>>>
>>>> And another thought...
>>>>
>>>> Some of the Jenkins QA jobs setup the virtual environment for running
>>>> tests themselves. I believe these might actually be the cause of some of
>>>> the failures we saw initially with the commit - I'll review those, and
>>>> ensure they won't try to build the gssapi module from source on Windows.
>>>>
>>>> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:
>>>>
>>>>> FYI, I did a quick test (and browse of PyPI):
>>>>>
>>>>> - On Windows, it seems there is a binary wheel available:
>>>>>
>>>>> (gssapi) C:\Users\dpage>pip install gssapi
>>>>> Collecting gssapi
>>>>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>>>>      |████████████████████████████████| 670 kB 3.3 MB/s
>>>>> Collecting decorator
>>>>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>>>>> Installing collected packages: decorator, gssapi
>>>>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>>>>
>>>>> - On macOS, the wheel is built by pip, but it doesn't seem to have any
>>>>> additional binary dependencies.
>>>>>
>>>>> This should simplify things a lot - we just need to ensure the build
>>>>> scripts use the binary package on Windows, and install the build deps on
>>>>> the Linux/Docker environments (and update the package builds with the
>>>>> additional dependencies of course).
>>>>>
>>>>>
>>>>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:
>>>>>
>>>>>> Hi Khushboo,
>>>>>>
>>>>>> As you know, this has been rolled back as the buildfarm blew up. I
>>>>>> think there are a number of TODOs that need to be addressed, given that the
>>>>>> gssapi Python module is dependent on MIT Kerberos:
>>>>>>
>>>>>> In the patch:
>>>>>>
>>>>>> - Linux packages will need the additional dependencies to be declared
>>>>>> in the RPM/DEBs.
>>>>>> - The setup scripts for Linux will need to have the -dev packages
>>>>>> added as appropriate.
>>>>>> - The various READMEs that describe how to build packages will need
>>>>>> to be updated.
>>>>>> - The Dockerfile will need to be modified to add the required
>>>>>> packages.
>>>>>> - The Windows build will need to be updated so the installer ships
>>>>>> additional required DLLs.
>>>>>> - Are there any additional macOS dependencies? If so, they need to be
>>>>>> handled.
>>>>>>
>>>>>> In the buildfarm:
>>>>>>
>>>>>> - All Linux build VMs need to be updated with the additional
>>>>>> dependencies.
>>>>>> - On Windows, we need to figure out how to build/ship KfW. It's a
>>>>>> pain to build, which we would typically do ourselves to ensure we're
>>>>>> consistently using the same buildchain. If we do build it ourselves:
>>>>>>   - Will the Python package find it during it's build?
>>>>>>   - We'll need to create a Jenkins job to perform the build.
>>>>>> - Is any work required on macOS, or does it ship with everything
>>>>>> that's needed? If not, we'll need to build it, and create the Jenkins job.
>>>>>>
>>>>>> One final thought: on Windows/macOS, can we force a binary
>>>>>> installation from PIP (pip install --only-binary=gssapi gssapi)? If so,
>>>>>> will that include the required libraries, as psycopg2-binary does?
>>>>>>
>>>>>>
>>>>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Thanks, patch applied.
>>>>>>>
>>>>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> Please ignore my previous patch, attached the updated one.
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Khushboo
>>>>>>>>
>>>>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Khushboo
>>>>>>>>>
>>>>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi Khushboo
>>>>>>>>>>
>>>>>>>>>> Seems you have attached the wrong patch. Please send the updated
>>>>>>>>>> patch.
>>>>>>>>>>
>>>>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Khushboo
>>>>>>>>>>>
>>>>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>>>
>>>>>>>>>>>> I've just done the code review. Apart from below, the patch
>>>>>>>>>>>> looks good to me:
>>>>>>>>>>>>
>>>>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>>>>>> somewhere else and import them.
>>>>>>>>>>>>
>>>>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>>>>
>>>>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Done
>>>>>>>>>>>
>>>>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>>>>
>>>>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>>>>
>>>>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>>>>
>>>>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>  import config
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> +
>>>>>>>>>>>>
>>>>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>>>>
>>>>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>>>>
>>>>>>>>>>>> +
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Removed, it was only for testing.
>>>>>>>>>>>
>>>>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>>>>
>>>>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>>>>
>>>>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>>>>
>>>>>>>>>>>> +            #
>>>>>>>>>>>> current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>>>>
>>>>>>>>>>>> +            #     continue
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>>>>
>>>>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>>>>
>>>>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Done.
>>>>>>>>>>>
>>>>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined
>>>>>>>>>>>> when creating a user.
>>>>>>>>>>>>
>>>>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Done.
>>>>>>>>>>>
>>>>>>>>>>>> 6) The below URLs belong to the authenticate module. Currently
>>>>>>>>>>>> they are in the browser module. I would also suggest rephrasing the URL
>>>>>>>>>>>> from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>>>>
>>>>>>>>>>> Done the rephrasing as well as moved to the authentication
>>>>>>>>>>> module.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> Also, even though the method GET works, we should use the POST
>>>>>>>>>>>> method for login and DELETE for logout.
>>>>>>>>>>>>
>>>>>>>>>>> Kerberos_login just redirects the page to the actual login, so
>>>>>>>>>>> no need for the POST method.
>>>>>>>>>>> I followed the same method for the Logout user we have used for
>>>>>>>>>>> the normal user.
>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>>>>
>>>>>>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>>>>
>>>>>>>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi Aditya
>>>>>>>>>>>>>
>>>>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>>>>> succeeds.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server +
>>>>>>>>>>>>>> Client is documented in a separate file and attached.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> This patch also includes the small fix related to logging
>>>>>>>>>>>>>> #5829
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> --
>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>
>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>
>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>
>>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> *Thanks & Regards*
>>>>>>> *Akshay Joshi*
>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>
>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Dave Page
>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>> Twitter: @pgsnake
>>>>>>
>>>>>> EDB: http://www.enterprisedb.com
>>>>>>
>>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EDB: http://www.enterprisedb.com
>>>>>
>>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EDB: http://www.enterprisedb.com
>>>>
>>>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EDB: http://www.enterprisedb.com
>>
>>

-- 
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsnake

EDB: http://www.enterprisedb.com


^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 10:37  Khushboo Vashi <[email protected]>
  parent: Dave Page <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Khushboo Vashi @ 2021-01-18 10:37 UTC (permalink / raw)
  To: Dave Page <[email protected]>; +Cc: Akshay Joshi <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

On Mon, Jan 18, 2021 at 3:26 PM Dave Page <[email protected]> wrote:

>
>
> On Mon, Jan 18, 2021 at 9:37 AM Khushboo Vashi <
> [email protected]> wrote:
>
>>
>>
>> On Mon, Jan 18, 2021 at 2:45 PM Dave Page <[email protected]> wrote:
>>
>>> Hi
>>>
>>> On Mon, Jan 18, 2021 at 7:30 AM Khushboo Vashi <
>>> [email protected]> wrote:
>>>
>>>> Hi,
>>>>
>>>> Please find the attached updated patch with the below changes:
>>>>
>>>> - Dependencies are added into Linux packages in the RPM/DEBs.
>>>> - Dev packages are added in the setup scripts for Linux.
>>>> - The required packages are added in the Dockerfile.
>>>> - Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
>>>> requirements.txt.
>>>>
>>>
>>> 1.6.9 is the last release that supports Python 3.4+. We should use that
>>> rather than older versions.
>>>
>> As per the https://pypi.org/project/gssapi/*1.6.9*/, it says Requires: Python
>> >=3.6.*
>>
>
> I think that's the metadata for the latest package version on the left. If
> you read the main text, it says:
> Requirements
> Basic
>
>    - A working implementation of GSSAPI (such as from MIT Kerberos) which
>    includes header files
>    - a C compiler (such as GCC)
>    - either the enum34 Python package or Python 3.4+
>    - the six and decorator python package
>
>
> For 1.6.10, that changed to:
> Requirements
> Basic
>
>    - A working implementation of GSSAPI (such as from MIT Kerberos) which
>    supports delegation and includes header files
>    - a C compiler (such as GCC)
>    - Python 3.6+ (older releases support older versions, but are
>    unsupported)
>    - the decorator python package
>
>
> I got the error as below for all the versions till 1.6.2.

[image: Screen Shot 2021-01-18 at 3.27.59 PM.png]

So, as per our conversation on slack, we will go with 1.6.2.


>>
>>>
>>>
>>>> - krb5 libs are not bundled with the Desktop packages, so added the
>>>> gssapi dependency into the try/catch block.
>>>> - .dockerignore is introduced to ignore unwanted files/folders like
>>>> node_modules etc., which will make the docker build fast. (By Ashesh Vashi)
>>>>
>>>
>>> Aside from that one comment above, eyeball review of the build changes
>>> looks good.
>>>
>>>
>>>
>>>>
>>>> Thanks,
>>>> Khushboo
>>>>
>>>> On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:
>>>>
>>>>> And another thought...
>>>>>
>>>>> Some of the Jenkins QA jobs setup the virtual environment for running
>>>>> tests themselves. I believe these might actually be the cause of some of
>>>>> the failures we saw initially with the commit - I'll review those, and
>>>>> ensure they won't try to build the gssapi module from source on Windows.
>>>>>
>>>>> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:
>>>>>
>>>>>> FYI, I did a quick test (and browse of PyPI):
>>>>>>
>>>>>> - On Windows, it seems there is a binary wheel available:
>>>>>>
>>>>>> (gssapi) C:\Users\dpage>pip install gssapi
>>>>>> Collecting gssapi
>>>>>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>>>>>      |████████████████████████████████| 670 kB 3.3 MB/s
>>>>>> Collecting decorator
>>>>>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>>>>>> Installing collected packages: decorator, gssapi
>>>>>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>>>>>
>>>>>> - On macOS, the wheel is built by pip, but it doesn't seem to have
>>>>>> any additional binary dependencies.
>>>>>>
>>>>>> This should simplify things a lot - we just need to ensure the build
>>>>>> scripts use the binary package on Windows, and install the build deps on
>>>>>> the Linux/Docker environments (and update the package builds with the
>>>>>> additional dependencies of course).
>>>>>>
>>>>>>
>>>>>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:
>>>>>>
>>>>>>> Hi Khushboo,
>>>>>>>
>>>>>>> As you know, this has been rolled back as the buildfarm blew up. I
>>>>>>> think there are a number of TODOs that need to be addressed, given that the
>>>>>>> gssapi Python module is dependent on MIT Kerberos:
>>>>>>>
>>>>>>> In the patch:
>>>>>>>
>>>>>>> - Linux packages will need the additional dependencies to be
>>>>>>> declared in the RPM/DEBs.
>>>>>>> - The setup scripts for Linux will need to have the -dev packages
>>>>>>> added as appropriate.
>>>>>>> - The various READMEs that describe how to build packages will need
>>>>>>> to be updated.
>>>>>>> - The Dockerfile will need to be modified to add the required
>>>>>>> packages.
>>>>>>> - The Windows build will need to be updated so the installer ships
>>>>>>> additional required DLLs.
>>>>>>> - Are there any additional macOS dependencies? If so, they need to
>>>>>>> be handled.
>>>>>>>
>>>>>>> In the buildfarm:
>>>>>>>
>>>>>>> - All Linux build VMs need to be updated with the additional
>>>>>>> dependencies.
>>>>>>> - On Windows, we need to figure out how to build/ship KfW. It's a
>>>>>>> pain to build, which we would typically do ourselves to ensure we're
>>>>>>> consistently using the same buildchain. If we do build it ourselves:
>>>>>>>   - Will the Python package find it during it's build?
>>>>>>>   - We'll need to create a Jenkins job to perform the build.
>>>>>>> - Is any work required on macOS, or does it ship with everything
>>>>>>> that's needed? If not, we'll need to build it, and create the Jenkins job.
>>>>>>>
>>>>>>> One final thought: on Windows/macOS, can we force a binary
>>>>>>> installation from PIP (pip install --only-binary=gssapi gssapi)? If so,
>>>>>>> will that include the required libraries, as psycopg2-binary does?
>>>>>>>
>>>>>>>
>>>>>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>>>>>> [email protected]> wrote:
>>>>>>>
>>>>>>>> Thanks, patch applied.
>>>>>>>>
>>>>>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> Please ignore my previous patch, attached the updated one.
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Khushboo
>>>>>>>>>
>>>>>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Khushboo
>>>>>>>>>>
>>>>>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi Khushboo
>>>>>>>>>>>
>>>>>>>>>>> Seems you have attached the wrong patch. Please send the updated
>>>>>>>>>>> patch.
>>>>>>>>>>>
>>>>>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>
>>>>>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>>>>
>>>>>>>>>>>>> I've just done the code review. Apart from below, the patch
>>>>>>>>>>>>> looks good to me:
>>>>>>>>>>>>>
>>>>>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>>>>>>> somewhere else and import them.
>>>>>>>>>>>>>
>>>>>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>>>>>
>>>>>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Done
>>>>>>>>>>>>
>>>>>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>>>>>
>>>>>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>
>>>>>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>
>>>>>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>  import config
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> +
>>>>>>>>>>>>>
>>>>>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>>>>>
>>>>>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>>>>>
>>>>>>>>>>>>> +
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Removed, it was only for testing.
>>>>>>>>>>>>
>>>>>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>>>>>
>>>>>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>>>>>
>>>>>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>>>>>
>>>>>>>>>>>>> +            #
>>>>>>>>>>>>> current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>>>>>
>>>>>>>>>>>>> +            #     continue
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>>>>>
>>>>>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>>>>>
>>>>>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Done.
>>>>>>>>>>>>
>>>>>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined
>>>>>>>>>>>>> when creating a user.
>>>>>>>>>>>>>
>>>>>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Done.
>>>>>>>>>>>>
>>>>>>>>>>>>> 6) The below URLs belong to the authenticate module. Currently
>>>>>>>>>>>>> they are in the browser module. I would also suggest rephrasing the URL
>>>>>>>>>>>>> from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>>>>>
>>>>>>>>>>>> Done the rephrasing as well as moved to the authentication
>>>>>>>>>>>> module.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>> Also, even though the method GET works, we should use the POST
>>>>>>>>>>>>> method for login and DELETE for logout.
>>>>>>>>>>>>>
>>>>>>>>>>>> Kerberos_login just redirects the page to the actual login, so
>>>>>>>>>>>> no need for the POST method.
>>>>>>>>>>>> I followed the same method for the Logout user we have used for
>>>>>>>>>>>> the normal user.
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>>>>>
>>>>>>>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>>>>>
>>>>>>>>>>>>> +                 endpoint="kerberos_logout", methods=["GET"])
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi Aditya
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>>>>>> succeeds.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin Server +
>>>>>>>>>>>>>>> Client is documented in a separate file and attached.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> This patch also includes the small fix related to logging
>>>>>>>>>>>>>>> #5829
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> --
>>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> --
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>
>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> *Thanks & Regards*
>>>>>>>> *Akshay Joshi*
>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>
>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Dave Page
>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>> Twitter: @pgsnake
>>>>>>>
>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> --
>>>>>> Dave Page
>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>> Twitter: @pgsnake
>>>>>>
>>>>>> EDB: http://www.enterprisedb.com
>>>>>>
>>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EDB: http://www.enterprisedb.com
>>>>>
>>>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EDB: http://www.enterprisedb.com
>>>
>>>
>
> --
> Dave Page
> Blog: http://pgsnake.blogspot.com
> Twitter: @pgsnake
>
> EDB: http://www.enterprisedb.com
>
>


Attachments:

  [image/png] Screen Shot 2021-01-18 at 3.27.59 PM.png (75.4K, 3-Screen%20Shot%202021-01-18%20at%203.27.59%20PM.png)
  download | view image

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 11:10  Akshay Joshi <[email protected]>
  parent: Khushboo Vashi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Akshay Joshi @ 2021-01-18 11:10 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: Dave Page <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

Thanks, patch applied.

On Mon, Jan 18, 2021 at 4:07 PM Khushboo Vashi <
[email protected]> wrote:

>
>
> On Mon, Jan 18, 2021 at 3:26 PM Dave Page <[email protected]> wrote:
>
>>
>>
>> On Mon, Jan 18, 2021 at 9:37 AM Khushboo Vashi <
>> [email protected]> wrote:
>>
>>>
>>>
>>> On Mon, Jan 18, 2021 at 2:45 PM Dave Page <[email protected]> wrote:
>>>
>>>> Hi
>>>>
>>>> On Mon, Jan 18, 2021 at 7:30 AM Khushboo Vashi <
>>>> [email protected]> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> Please find the attached updated patch with the below changes:
>>>>>
>>>>> - Dependencies are added into Linux packages in the RPM/DEBs.
>>>>> - Dev packages are added in the setup scripts for Linux.
>>>>> - The required packages are added in the Dockerfile.
>>>>> - Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
>>>>> requirements.txt.
>>>>>
>>>>
>>>> 1.6.9 is the last release that supports Python 3.4+. We should use that
>>>> rather than older versions.
>>>>
>>> As per the https://pypi.org/project/gssapi/*1.6.9*/, it says Requires: Python
>>> >=3.6.*
>>>
>>
>> I think that's the metadata for the latest package version on the left.
>> If you read the main text, it says:
>> Requirements
>> Basic
>>
>>    - A working implementation of GSSAPI (such as from MIT Kerberos)
>>    which includes header files
>>    - a C compiler (such as GCC)
>>    - either the enum34 Python package or Python 3.4+
>>    - the six and decorator python package
>>
>>
>> For 1.6.10, that changed to:
>> Requirements
>> Basic
>>
>>    - A working implementation of GSSAPI (such as from MIT Kerberos)
>>    which supports delegation and includes header files
>>    - a C compiler (such as GCC)
>>    - Python 3.6+ (older releases support older versions, but are
>>    unsupported)
>>    - the decorator python package
>>
>>
>> I got the error as below for all the versions till 1.6.2.
>
> [image: Screen Shot 2021-01-18 at 3.27.59 PM.png]
>
> So, as per our conversation on slack, we will go with 1.6.2.
>
>
>>>
>>>>
>>>>
>>>>> - krb5 libs are not bundled with the Desktop packages, so added the
>>>>> gssapi dependency into the try/catch block.
>>>>> - .dockerignore is introduced to ignore unwanted files/folders like
>>>>> node_modules etc., which will make the docker build fast. (By Ashesh Vashi)
>>>>>
>>>>
>>>> Aside from that one comment above, eyeball review of the build changes
>>>> looks good.
>>>>
>>>>
>>>>
>>>>>
>>>>> Thanks,
>>>>> Khushboo
>>>>>
>>>>> On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:
>>>>>
>>>>>> And another thought...
>>>>>>
>>>>>> Some of the Jenkins QA jobs setup the virtual environment for running
>>>>>> tests themselves. I believe these might actually be the cause of some of
>>>>>> the failures we saw initially with the commit - I'll review those, and
>>>>>> ensure they won't try to build the gssapi module from source on Windows.
>>>>>>
>>>>>> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:
>>>>>>
>>>>>>> FYI, I did a quick test (and browse of PyPI):
>>>>>>>
>>>>>>> - On Windows, it seems there is a binary wheel available:
>>>>>>>
>>>>>>> (gssapi) C:\Users\dpage>pip install gssapi
>>>>>>> Collecting gssapi
>>>>>>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>>>>>>      |████████████████████████████████| 670 kB 3.3 MB/s
>>>>>>> Collecting decorator
>>>>>>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>>>>>>> Installing collected packages: decorator, gssapi
>>>>>>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>>>>>>
>>>>>>> - On macOS, the wheel is built by pip, but it doesn't seem to have
>>>>>>> any additional binary dependencies.
>>>>>>>
>>>>>>> This should simplify things a lot - we just need to ensure the build
>>>>>>> scripts use the binary package on Windows, and install the build deps on
>>>>>>> the Linux/Docker environments (and update the package builds with the
>>>>>>> additional dependencies of course).
>>>>>>>
>>>>>>>
>>>>>>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]> wrote:
>>>>>>>
>>>>>>>> Hi Khushboo,
>>>>>>>>
>>>>>>>> As you know, this has been rolled back as the buildfarm blew up. I
>>>>>>>> think there are a number of TODOs that need to be addressed, given that the
>>>>>>>> gssapi Python module is dependent on MIT Kerberos:
>>>>>>>>
>>>>>>>> In the patch:
>>>>>>>>
>>>>>>>> - Linux packages will need the additional dependencies to be
>>>>>>>> declared in the RPM/DEBs.
>>>>>>>> - The setup scripts for Linux will need to have the -dev packages
>>>>>>>> added as appropriate.
>>>>>>>> - The various READMEs that describe how to build packages will need
>>>>>>>> to be updated.
>>>>>>>> - The Dockerfile will need to be modified to add the required
>>>>>>>> packages.
>>>>>>>> - The Windows build will need to be updated so the installer ships
>>>>>>>> additional required DLLs.
>>>>>>>> - Are there any additional macOS dependencies? If so, they need to
>>>>>>>> be handled.
>>>>>>>>
>>>>>>>> In the buildfarm:
>>>>>>>>
>>>>>>>> - All Linux build VMs need to be updated with the additional
>>>>>>>> dependencies.
>>>>>>>> - On Windows, we need to figure out how to build/ship KfW. It's a
>>>>>>>> pain to build, which we would typically do ourselves to ensure we're
>>>>>>>> consistently using the same buildchain. If we do build it ourselves:
>>>>>>>>   - Will the Python package find it during it's build?
>>>>>>>>   - We'll need to create a Jenkins job to perform the build.
>>>>>>>> - Is any work required on macOS, or does it ship with everything
>>>>>>>> that's needed? If not, we'll need to build it, and create the Jenkins job.
>>>>>>>>
>>>>>>>> One final thought: on Windows/macOS, can we force a binary
>>>>>>>> installation from PIP (pip install --only-binary=gssapi gssapi)? If so,
>>>>>>>> will that include the required libraries, as psycopg2-binary does?
>>>>>>>>
>>>>>>>>
>>>>>>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>>>>>>> [email protected]> wrote:
>>>>>>>>
>>>>>>>>> Thanks, patch applied.
>>>>>>>>>
>>>>>>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Hi,
>>>>>>>>>>
>>>>>>>>>> Please ignore my previous patch, attached the updated one.
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Khushboo
>>>>>>>>>>
>>>>>>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Khushboo
>>>>>>>>>>>
>>>>>>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi Khushboo
>>>>>>>>>>>>
>>>>>>>>>>>> Seems you have attached the wrong patch. Please send the
>>>>>>>>>>>> updated patch.
>>>>>>>>>>>>
>>>>>>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> I've just done the code review. Apart from below, the patch
>>>>>>>>>>>>>> looks good to me:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>>>>>>>> somewhere else and import them.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Done
>>>>>>>>>>>>>
>>>>>>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>  import config
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Removed, it was only for testing.
>>>>>>>>>>>>>
>>>>>>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +            #
>>>>>>>>>>>>>> current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +            #     continue
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>>>>>>
>>>>>>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>
>>>>>>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had defined
>>>>>>>>>>>>>> when creating a user.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>
>>>>>>>>>>>>>> 6) The below URLs belong to the authenticate module.
>>>>>>>>>>>>>> Currently they are in the browser module. I would also suggest rephrasing
>>>>>>>>>>>>>> the URL from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>>>>>>
>>>>>>>>>>>>> Done the rephrasing as well as moved to the authentication
>>>>>>>>>>>>> module.
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Also, even though the method GET works, we should use the
>>>>>>>>>>>>>> POST method for login and DELETE for logout.
>>>>>>>>>>>>>>
>>>>>>>>>>>>> Kerberos_login just redirects the page to the actual login, so
>>>>>>>>>>>>> no need for the POST method.
>>>>>>>>>>>>> I followed the same method for the Logout user we have used
>>>>>>>>>>>>> for the normal user.
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +                 endpoint="kerberos_login", methods=["GET"])
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> +                 endpoint="kerberos_logout",
>>>>>>>>>>>>>> methods=["GET"])
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi Aditya
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>>>>>>> succeeds.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin
>>>>>>>>>>>>>>>> Server + Client is documented in a separate file and attached.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> This patch also includes the small fix related to logging
>>>>>>>>>>>>>>>> #5829
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> --
>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> --
>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>
>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> *Thanks & Regards*
>>>>>>>>> *Akshay Joshi*
>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>
>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> Dave Page
>>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>>> Twitter: @pgsnake
>>>>>>>>
>>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Dave Page
>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>> Twitter: @pgsnake
>>>>>>>
>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> --
>>>>>> Dave Page
>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>> Twitter: @pgsnake
>>>>>>
>>>>>> EDB: http://www.enterprisedb.com
>>>>>>
>>>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EDB: http://www.enterprisedb.com
>>>>
>>>>
>>
>> --
>> Dave Page
>> Blog: http://pgsnake.blogspot.com
>> Twitter: @pgsnake
>>
>> EDB: http://www.enterprisedb.com
>>
>>

-- 
*Thanks & Regards*
*Akshay Joshi*
*pgAdmin Hacker | Principal Software Architect*
*EDB Postgres <http://edbpostgres.com>*

*Mobile: +91 976-788-8246*


Attachments:

  [image/png] Screen Shot 2021-01-18 at 3.27.59 PM.png (75.4K, 3-Screen%20Shot%202021-01-18%20at%203.27.59%20PM.png)
  download | view image

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 12:34  Akshay Joshi <[email protected]>
  parent: Akshay Joshi <[email protected]>
  0 siblings, 1 reply; 32+ messages in thread

From: Akshay Joshi @ 2021-01-18 12:34 UTC (permalink / raw)
  To: Khushboo Vashi <[email protected]>; +Cc: Dave Page <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

Hi Khushboo

Jenkins build for OSX is failing with the below error can you please fix
and send the patch:

runTest (pgadmin.browser.tests.test_master_password.MasterPasswordTestCase)
TestCase for Create master password dialog ... 2021-01-18
12:07:32,542: ERROR	flask.app:	400 Bad Request: The CSRF tokens do not
match.
Traceback (most recent call last):
  File "/Users/jenkins/workspace/pgadmin4-macos-qa/venv/lib/python3.9/site-packages/flask_wtf/csrf.py",
line 256, in protect
    validate_csrf(self._get_csrf_token())
  File "/Users/jenkins/workspace/pgadmin4-macos-qa/venv/lib/python3.9/site-packages/flask_wtf/csrf.py",
line 106, in validate_csrf
    raise ValidationError('The CSRF tokens do not match.')
wtforms.validators.ValidationError: The CSRF tokens do not match.




On Mon, Jan 18, 2021 at 4:40 PM Akshay Joshi <[email protected]>
wrote:

> Thanks, patch applied.
>
> On Mon, Jan 18, 2021 at 4:07 PM Khushboo Vashi <
> [email protected]> wrote:
>
>>
>>
>> On Mon, Jan 18, 2021 at 3:26 PM Dave Page <[email protected]> wrote:
>>
>>>
>>>
>>> On Mon, Jan 18, 2021 at 9:37 AM Khushboo Vashi <
>>> [email protected]> wrote:
>>>
>>>>
>>>>
>>>> On Mon, Jan 18, 2021 at 2:45 PM Dave Page <[email protected]> wrote:
>>>>
>>>>> Hi
>>>>>
>>>>> On Mon, Jan 18, 2021 at 7:30 AM Khushboo Vashi <
>>>>> [email protected]> wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> Please find the attached updated patch with the below changes:
>>>>>>
>>>>>> - Dependencies are added into Linux packages in the RPM/DEBs.
>>>>>> - Dev packages are added in the setup scripts for Linux.
>>>>>> - The required packages are added in the Dockerfile.
>>>>>> - Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
>>>>>> requirements.txt.
>>>>>>
>>>>>
>>>>> 1.6.9 is the last release that supports Python 3.4+. We should use
>>>>> that rather than older versions.
>>>>>
>>>> As per the https://pypi.org/project/gssapi/*1.6.9*/, it says Requires: Python
>>>> >=3.6.*
>>>>
>>>
>>> I think that's the metadata for the latest package version on the left.
>>> If you read the main text, it says:
>>> Requirements
>>> Basic
>>>
>>>    - A working implementation of GSSAPI (such as from MIT Kerberos)
>>>    which includes header files
>>>    - a C compiler (such as GCC)
>>>    - either the enum34 Python package or Python 3.4+
>>>    - the six and decorator python package
>>>
>>>
>>> For 1.6.10, that changed to:
>>> Requirements
>>> Basic
>>>
>>>    - A working implementation of GSSAPI (such as from MIT Kerberos)
>>>    which supports delegation and includes header files
>>>    - a C compiler (such as GCC)
>>>    - Python 3.6+ (older releases support older versions, but are
>>>    unsupported)
>>>    - the decorator python package
>>>
>>>
>>> I got the error as below for all the versions till 1.6.2.
>>
>> [image: Screen Shot 2021-01-18 at 3.27.59 PM.png]
>>
>> So, as per our conversation on slack, we will go with 1.6.2.
>>
>>
>>>>
>>>>>
>>>>>
>>>>>> - krb5 libs are not bundled with the Desktop packages, so added the
>>>>>> gssapi dependency into the try/catch block.
>>>>>> - .dockerignore is introduced to ignore unwanted files/folders like
>>>>>> node_modules etc., which will make the docker build fast. (By Ashesh Vashi)
>>>>>>
>>>>>
>>>>> Aside from that one comment above, eyeball review of the build changes
>>>>> looks good.
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Khushboo
>>>>>>
>>>>>> On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:
>>>>>>
>>>>>>> And another thought...
>>>>>>>
>>>>>>> Some of the Jenkins QA jobs setup the virtual environment for
>>>>>>> running tests themselves. I believe these might actually be the cause of
>>>>>>> some of the failures we saw initially with the commit - I'll review those,
>>>>>>> and ensure they won't try to build the gssapi module from source on Windows.
>>>>>>>
>>>>>>> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]> wrote:
>>>>>>>
>>>>>>>> FYI, I did a quick test (and browse of PyPI):
>>>>>>>>
>>>>>>>> - On Windows, it seems there is a binary wheel available:
>>>>>>>>
>>>>>>>> (gssapi) C:\Users\dpage>pip install gssapi
>>>>>>>> Collecting gssapi
>>>>>>>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>>>>>>>      |████████████████████████████████| 670 kB 3.3 MB/s
>>>>>>>> Collecting decorator
>>>>>>>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>>>>>>>> Installing collected packages: decorator, gssapi
>>>>>>>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>>>>>>>
>>>>>>>> - On macOS, the wheel is built by pip, but it doesn't seem to have
>>>>>>>> any additional binary dependencies.
>>>>>>>>
>>>>>>>> This should simplify things a lot - we just need to ensure the
>>>>>>>> build scripts use the binary package on Windows, and install the build deps
>>>>>>>> on the Linux/Docker environments (and update the package builds with the
>>>>>>>> additional dependencies of course).
>>>>>>>>
>>>>>>>>
>>>>>>>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> Hi Khushboo,
>>>>>>>>>
>>>>>>>>> As you know, this has been rolled back as the buildfarm blew up. I
>>>>>>>>> think there are a number of TODOs that need to be addressed, given that the
>>>>>>>>> gssapi Python module is dependent on MIT Kerberos:
>>>>>>>>>
>>>>>>>>> In the patch:
>>>>>>>>>
>>>>>>>>> - Linux packages will need the additional dependencies to be
>>>>>>>>> declared in the RPM/DEBs.
>>>>>>>>> - The setup scripts for Linux will need to have the -dev packages
>>>>>>>>> added as appropriate.
>>>>>>>>> - The various READMEs that describe how to build packages will
>>>>>>>>> need to be updated.
>>>>>>>>> - The Dockerfile will need to be modified to add the required
>>>>>>>>> packages.
>>>>>>>>> - The Windows build will need to be updated so the installer ships
>>>>>>>>> additional required DLLs.
>>>>>>>>> - Are there any additional macOS dependencies? If so, they need to
>>>>>>>>> be handled.
>>>>>>>>>
>>>>>>>>> In the buildfarm:
>>>>>>>>>
>>>>>>>>> - All Linux build VMs need to be updated with the additional
>>>>>>>>> dependencies.
>>>>>>>>> - On Windows, we need to figure out how to build/ship KfW. It's a
>>>>>>>>> pain to build, which we would typically do ourselves to ensure we're
>>>>>>>>> consistently using the same buildchain. If we do build it ourselves:
>>>>>>>>>   - Will the Python package find it during it's build?
>>>>>>>>>   - We'll need to create a Jenkins job to perform the build.
>>>>>>>>> - Is any work required on macOS, or does it ship with everything
>>>>>>>>> that's needed? If not, we'll need to build it, and create the Jenkins job.
>>>>>>>>>
>>>>>>>>> One final thought: on Windows/macOS, can we force a binary
>>>>>>>>> installation from PIP (pip install --only-binary=gssapi gssapi)? If so,
>>>>>>>>> will that include the required libraries, as psycopg2-binary does?
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>>>>>>>> [email protected]> wrote:
>>>>>>>>>
>>>>>>>>>> Thanks, patch applied.
>>>>>>>>>>
>>>>>>>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Hi,
>>>>>>>>>>>
>>>>>>>>>>> Please ignore my previous patch, attached the updated one.
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Khushboo
>>>>>>>>>>>
>>>>>>>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>
>>>>>>>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi Khushboo
>>>>>>>>>>>>>
>>>>>>>>>>>>> Seems you have attached the wrong patch. Please send the
>>>>>>>>>>>>> updated patch.
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> I've just done the code review. Apart from below, the patch
>>>>>>>>>>>>>>> looks good to me:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of app
>>>>>>>>>>>>>>> object. They don't belong there. You can create the constants
>>>>>>>>>>>>>>> somewhere else and import them.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Done
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>  import config
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Removed, it was only for testing.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +            #
>>>>>>>>>>>>>>> current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +            #     continue
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had
>>>>>>>>>>>>>>> defined when creating a user.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> 6) The below URLs belong to the authenticate module.
>>>>>>>>>>>>>>> Currently they are in the browser module. I would also suggest rephrasing
>>>>>>>>>>>>>>> the URL from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Done the rephrasing as well as moved to the authentication
>>>>>>>>>>>>>> module.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Also, even though the method GET works, we should use the
>>>>>>>>>>>>>>> POST method for login and DELETE for logout.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Kerberos_login just redirects the page to the actual login,
>>>>>>>>>>>>>> so no need for the POST method.
>>>>>>>>>>>>>> I followed the same method for the Logout user we have used
>>>>>>>>>>>>>> for the normal user.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +                 endpoint="kerberos_login",
>>>>>>>>>>>>>>> methods=["GET"])
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> +                 endpoint="kerberos_logout",
>>>>>>>>>>>>>>> methods=["GET"])
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi Aditya
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>>>>>>>> succeeds.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin
>>>>>>>>>>>>>>>>> Server + Client is documented in a separate file and attached.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> This patch also includes the small fix related to logging
>>>>>>>>>>>>>>>>> #5829
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> --
>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>
>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>
>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Dave Page
>>>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>>>> Twitter: @pgsnake
>>>>>>>>>
>>>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> Dave Page
>>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>>> Twitter: @pgsnake
>>>>>>>>
>>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Dave Page
>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>> Twitter: @pgsnake
>>>>>>>
>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>
>>>>>>>
>>>>>
>>>>> --
>>>>> Dave Page
>>>>> Blog: http://pgsnake.blogspot.com
>>>>> Twitter: @pgsnake
>>>>>
>>>>> EDB: http://www.enterprisedb.com
>>>>>
>>>>>
>>>
>>> --
>>> Dave Page
>>> Blog: http://pgsnake.blogspot.com
>>> Twitter: @pgsnake
>>>
>>> EDB: http://www.enterprisedb.com
>>>
>>>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
> *pgAdmin Hacker | Principal Software Architect*
> *EDB Postgres <http://edbpostgres.com>*
>
> *Mobile: +91 976-788-8246*
>


-- 
*Thanks & Regards*
*Akshay Joshi*
*pgAdmin Hacker | Principal Software Architect*
*EDB Postgres <http://edbpostgres.com>*

*Mobile: +91 976-788-8246*


Attachments:

  [image/png] Screen Shot 2021-01-18 at 3.27.59 PM.png (75.4K, 3-Screen%20Shot%202021-01-18%20at%203.27.59%20PM.png)
  download | view image

^ permalink  raw  reply  [nested|flat] 32+ messages in thread

* Re: [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1
@ 2021-01-18 12:43  Khushboo Vashi <[email protected]>
  parent: Akshay Joshi <[email protected]>
  0 siblings, 0 replies; 32+ messages in thread

From: Khushboo Vashi @ 2021-01-18 12:43 UTC (permalink / raw)
  To: Akshay Joshi <[email protected]>; +Cc: Dave Page <[email protected]>; Aditya Toshniwal <[email protected]>; pgadmin-hackers

On Mon, Jan 18, 2021 at 6:05 PM Akshay Joshi <[email protected]>
wrote:

> Hi Khushboo
>
> Jenkins build for OSX is failing with the below error can you please fix
> and send the patch:
>
> runTest (pgadmin.browser.tests.test_master_password.MasterPasswordTestCase)
> TestCase for Create master password dialog ... 2021-01-18 12:07:32,542: ERROR	flask.app:	400 Bad Request: The CSRF tokens do not match.
> Traceback (most recent call last):
>   File "/Users/jenkins/workspace/pgadmin4-macos-qa/venv/lib/python3.9/site-packages/flask_wtf/csrf.py", line 256, in protect
>     validate_csrf(self._get_csrf_token())
>   File "/Users/jenkins/workspace/pgadmin4-macos-qa/venv/lib/python3.9/site-packages/flask_wtf/csrf.py", line 106, in validate_csrf
>     raise ValidationError('The CSRF tokens do not match.')
> wtforms.validators.ValidationError: The CSRF tokens do not match.
>
>
>
> I will check as in my local environment it is working fine.

>
> On Mon, Jan 18, 2021 at 4:40 PM Akshay Joshi <
> [email protected]> wrote:
>
>> Thanks, patch applied.
>>
>> On Mon, Jan 18, 2021 at 4:07 PM Khushboo Vashi <
>> [email protected]> wrote:
>>
>>>
>>>
>>> On Mon, Jan 18, 2021 at 3:26 PM Dave Page <[email protected]> wrote:
>>>
>>>>
>>>>
>>>> On Mon, Jan 18, 2021 at 9:37 AM Khushboo Vashi <
>>>> [email protected]> wrote:
>>>>
>>>>>
>>>>>
>>>>> On Mon, Jan 18, 2021 at 2:45 PM Dave Page <[email protected]> wrote:
>>>>>
>>>>>> Hi
>>>>>>
>>>>>> On Mon, Jan 18, 2021 at 7:30 AM Khushboo Vashi <
>>>>>> [email protected]> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> Please find the attached updated patch with the below changes:
>>>>>>>
>>>>>>> - Dependencies are added into Linux packages in the RPM/DEBs.
>>>>>>> - Dev packages are added in the setup scripts for Linux.
>>>>>>> - The required packages are added in the Dockerfile.
>>>>>>> - Conditional gssapi 1.6.2 dependency is added for Python 3.5 in
>>>>>>> requirements.txt.
>>>>>>>
>>>>>>
>>>>>> 1.6.9 is the last release that supports Python 3.4+. We should use
>>>>>> that rather than older versions.
>>>>>>
>>>>> As per the https://pypi.org/project/gssapi/*1.6.9*/, it says Requires:
>>>>>  Python >=3.6.*
>>>>>
>>>>
>>>> I think that's the metadata for the latest package version on the left.
>>>> If you read the main text, it says:
>>>> Requirements
>>>> Basic
>>>>
>>>>    - A working implementation of GSSAPI (such as from MIT Kerberos)
>>>>    which includes header files
>>>>    - a C compiler (such as GCC)
>>>>    - either the enum34 Python package or Python 3.4+
>>>>    - the six and decorator python package
>>>>
>>>>
>>>> For 1.6.10, that changed to:
>>>> Requirements
>>>> Basic
>>>>
>>>>    - A working implementation of GSSAPI (such as from MIT Kerberos)
>>>>    which supports delegation and includes header files
>>>>    - a C compiler (such as GCC)
>>>>    - Python 3.6+ (older releases support older versions, but are
>>>>    unsupported)
>>>>    - the decorator python package
>>>>
>>>>
>>>> I got the error as below for all the versions till 1.6.2.
>>>
>>> [image: Screen Shot 2021-01-18 at 3.27.59 PM.png]
>>>
>>> So, as per our conversation on slack, we will go with 1.6.2.
>>>
>>>
>>>>>
>>>>>>
>>>>>>
>>>>>>> - krb5 libs are not bundled with the Desktop packages, so added the
>>>>>>> gssapi dependency into the try/catch block.
>>>>>>> - .dockerignore is introduced to ignore unwanted files/folders like
>>>>>>> node_modules etc., which will make the docker build fast. (By Ashesh Vashi)
>>>>>>>
>>>>>>
>>>>>> Aside from that one comment above, eyeball review of the build
>>>>>> changes looks good.
>>>>>>
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Khushboo
>>>>>>>
>>>>>>> On Fri, Jan 15, 2021 at 3:48 PM Dave Page <[email protected]> wrote:
>>>>>>>
>>>>>>>> And another thought...
>>>>>>>>
>>>>>>>> Some of the Jenkins QA jobs setup the virtual environment for
>>>>>>>> running tests themselves. I believe these might actually be the cause of
>>>>>>>> some of the failures we saw initially with the commit - I'll review those,
>>>>>>>> and ensure they won't try to build the gssapi module from source on Windows.
>>>>>>>>
>>>>>>>> On Thu, Jan 14, 2021 at 4:34 PM Dave Page <[email protected]>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> FYI, I did a quick test (and browse of PyPI):
>>>>>>>>>
>>>>>>>>> - On Windows, it seems there is a binary wheel available:
>>>>>>>>>
>>>>>>>>> (gssapi) C:\Users\dpage>pip install gssapi
>>>>>>>>> Collecting gssapi
>>>>>>>>>   Downloading gssapi-1.6.12-cp39-cp39-win_amd64.whl (670 kB)
>>>>>>>>>      |████████████████████████████████| 670 kB 3.3 MB/s
>>>>>>>>> Collecting decorator
>>>>>>>>>   Downloading decorator-4.4.2-py2.py3-none-any.whl (9.2 kB)
>>>>>>>>> Installing collected packages: decorator, gssapi
>>>>>>>>> Successfully installed decorator-4.4.2 gssapi-1.6.12
>>>>>>>>>
>>>>>>>>> - On macOS, the wheel is built by pip, but it doesn't seem to have
>>>>>>>>> any additional binary dependencies.
>>>>>>>>>
>>>>>>>>> This should simplify things a lot - we just need to ensure the
>>>>>>>>> build scripts use the binary package on Windows, and install the build deps
>>>>>>>>> on the Linux/Docker environments (and update the package builds with the
>>>>>>>>> additional dependencies of course).
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Thu, Jan 14, 2021 at 4:04 PM Dave Page <[email protected]>
>>>>>>>>> wrote:
>>>>>>>>>
>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>
>>>>>>>>>> As you know, this has been rolled back as the buildfarm blew up.
>>>>>>>>>> I think there are a number of TODOs that need to be addressed, given that
>>>>>>>>>> the gssapi Python module is dependent on MIT Kerberos:
>>>>>>>>>>
>>>>>>>>>> In the patch:
>>>>>>>>>>
>>>>>>>>>> - Linux packages will need the additional dependencies to be
>>>>>>>>>> declared in the RPM/DEBs.
>>>>>>>>>> - The setup scripts for Linux will need to have the -dev packages
>>>>>>>>>> added as appropriate.
>>>>>>>>>> - The various READMEs that describe how to build packages will
>>>>>>>>>> need to be updated.
>>>>>>>>>> - The Dockerfile will need to be modified to add the required
>>>>>>>>>> packages.
>>>>>>>>>> - The Windows build will need to be updated so the installer
>>>>>>>>>> ships additional required DLLs.
>>>>>>>>>> - Are there any additional macOS dependencies? If so, they need
>>>>>>>>>> to be handled.
>>>>>>>>>>
>>>>>>>>>> In the buildfarm:
>>>>>>>>>>
>>>>>>>>>> - All Linux build VMs need to be updated with the additional
>>>>>>>>>> dependencies.
>>>>>>>>>> - On Windows, we need to figure out how to build/ship KfW. It's a
>>>>>>>>>> pain to build, which we would typically do ourselves to ensure we're
>>>>>>>>>> consistently using the same buildchain. If we do build it ourselves:
>>>>>>>>>>   - Will the Python package find it during it's build?
>>>>>>>>>>   - We'll need to create a Jenkins job to perform the build.
>>>>>>>>>> - Is any work required on macOS, or does it ship with everything
>>>>>>>>>> that's needed? If not, we'll need to build it, and create the Jenkins job.
>>>>>>>>>>
>>>>>>>>>> One final thought: on Windows/macOS, can we force a binary
>>>>>>>>>> installation from PIP (pip install --only-binary=gssapi gssapi)? If so,
>>>>>>>>>> will that include the required libraries, as psycopg2-binary does?
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Thu, Jan 14, 2021 at 8:18 AM Akshay Joshi <
>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>
>>>>>>>>>>> Thanks, patch applied.
>>>>>>>>>>>
>>>>>>>>>>> On Thu, Jan 14, 2021 at 1:42 PM Khushboo Vashi <
>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi,
>>>>>>>>>>>>
>>>>>>>>>>>> Please ignore my previous patch, attached the updated one.
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>
>>>>>>>>>>>> On Thu, Jan 14, 2021 at 12:17 PM Khushboo Vashi <
>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>
>>>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Thu, Jan 14, 2021 at 12:00 PM Akshay Joshi <
>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Hi Khushboo
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Seems you have attached the wrong patch. Please send the
>>>>>>>>>>>>>> updated patch.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Wed, Jan 13, 2021 at 2:35 PM Khushboo Vashi <
>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Please find the attached updated patch.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> On Fri, Jan 1, 2021 at 1:07 PM Aditya Toshniwal <
>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Hi Khushboo,
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> I've just done the code review. Apart from below, the patch
>>>>>>>>>>>>>>>> looks good to me:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 1) Move the auth source constants -ldap, kerberos out of
>>>>>>>>>>>>>>>> app object. They don't belong there. You can create the constants
>>>>>>>>>>>>>>>> somewhere else and import them.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +app.PGADMIN_LDAP_AUTH_SOURCE = 'ldap'
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +app.PGADMIN_KERBEROS_AUTH_SOURCE = 'kerberos'
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Done
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 2) Are we going to make kerberos default for wsgi ?
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> *--- a/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> *+++ b/web/pgAdmin4.wsgi*
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> @@ -24,6 +24,10 @@ builtins.SERVER_MODE = True
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>  import config
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +config.AUTHENTICATION_SOURCES = ['kerberos']
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +config.KERBEROS_AUTO_CREATE_USER = True
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Removed, it was only for testing.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 3) Remove the commented code.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +            # if self.form.data['email'] and
>>>>>>>>>>>>>>>> self.form.data['password'] and \
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +            #         source.get_source_name() ==\
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +            #
>>>>>>>>>>>>>>>> current_app.PGADMIN_KERBEROS_AUTH_SOURCE:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +            #     continue
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Removed the comment, it is actually the part of the code.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 4) KERBEROSAuthentication could be KerberosAuthentication
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> class KERBEROSAuthentication(BaseAuthentication):
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 5) You can use the constants (ldap, kerberos) you had
>>>>>>>>>>>>>>>> defined when creating a user.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +                    'auth_source': 'kerberos'
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Done.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> 6) The below URLs belong to the authenticate module.
>>>>>>>>>>>>>>>> Currently they are in the browser module. I would also suggest rephrasing
>>>>>>>>>>>>>>>> the URL from /kerberos_login to /login/kerberos. Same for logout.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Done the rephrasing as well as moved to the authentication
>>>>>>>>>>>>>>> module.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> Also, even though the method GET works, we should use the
>>>>>>>>>>>>>>>> POST method for login and DELETE for logout.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Kerberos_login just redirects the page to the actual login,
>>>>>>>>>>>>>>> so no need for the POST method.
>>>>>>>>>>>>>>> I followed the same method for the Logout user we have used
>>>>>>>>>>>>>>> for the normal user.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> [email protected]("/kerberos_login",
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +                 endpoint="kerberos_login",
>>>>>>>>>>>>>>>> methods=["GET"])
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> [email protected]("/kerberos_logout",
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> +                 endpoint="kerberos_logout",
>>>>>>>>>>>>>>>> methods=["GET"])
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 6:07 PM Akshay Joshi <
>>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Hi Aditya
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Can you please do the code review?
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> On Tue, Dec 22, 2020 at 3:44 PM Khushboo Vashi <
>>>>>>>>>>>>>>>>> [email protected]> wrote:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Please find the attached patch to support Kerberos
>>>>>>>>>>>>>>>>>> Authentication in pgAdmin RM 5457.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> The patch introduces a new pluggable option for Kerberos
>>>>>>>>>>>>>>>>>> authentication, using SPNEGO to forward kerberos tickets through a browser
>>>>>>>>>>>>>>>>>> which will bypass the login page entirely if the Kerberos Authentication
>>>>>>>>>>>>>>>>>> succeeds.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> The complete setup of the Kerberos Server + pgAdmin
>>>>>>>>>>>>>>>>>> Server + Client is documented in a separate file and attached.
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> This patch also includes the small fix related to logging
>>>>>>>>>>>>>>>>>> #5829
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>>>>> Khushboo
>>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> --
>>>>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>>>>> Aditya Toshniwal
>>>>>>>>>>>>>>>> pgAdmin hacker | Sr. Software Engineer | *edbpostgres.com*
>>>>>>>>>>>>>>>> <http://edbpostgres.com;
>>>>>>>>>>>>>>>> "Don't Complain about Heat, Plant a TREE"
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> --
>>>>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> --
>>>>>>>>>>> *Thanks & Regards*
>>>>>>>>>>> *Akshay Joshi*
>>>>>>>>>>> *pgAdmin Hacker | Principal Software Architect*
>>>>>>>>>>> *EDB Postgres <http://edbpostgres.com>*
>>>>>>>>>>>
>>>>>>>>>>> *Mobile: +91 976-788-8246*
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> Dave Page
>>>>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>>>>> Twitter: @pgsnake
>>>>>>>>>>
>>>>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> --
>>>>>>>>> Dave Page
>>>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>>>> Twitter: @pgsnake
>>>>>>>>>
>>>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>> --
>>>>>>>> Dave Page
>>>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>>>> Twitter: @pgsnake
>>>>>>>>
>>>>>>>> EDB: http://www.enterprisedb.com
>>>>>>>>
>>>>>>>>
>>>>>>
>>>>>> --
>>>>>> Dave Page
>>>>>> Blog: http://pgsnake.blogspot.com
>>>>>> Twitter: @pgsnake
>>>>>>
>>>>>> EDB: http://www.enterprisedb.com
>>>>>>
>>>>>>
>>>>
>>>> --
>>>> Dave Page
>>>> Blog: http://pgsnake.blogspot.com
>>>> Twitter: @pgsnake
>>>>
>>>> EDB: http://www.enterprisedb.com
>>>>
>>>>
>>
>> --
>> *Thanks & Regards*
>> *Akshay Joshi*
>> *pgAdmin Hacker | Principal Software Architect*
>> *EDB Postgres <http://edbpostgres.com>*
>>
>> *Mobile: +91 976-788-8246*
>>
>
>
> --
> *Thanks & Regards*
> *Akshay Joshi*
> *pgAdmin Hacker | Principal Software Architect*
> *EDB Postgres <http://edbpostgres.com>*
>
> *Mobile: +91 976-788-8246*
>


Attachments:

  [image/png] Screen Shot 2021-01-18 at 3.27.59 PM.png (75.4K, 3-Screen%20Shot%202021-01-18%20at%203.27.59%20PM.png)
  download | view image

^ permalink  raw  reply  [nested|flat] 32+ messages in thread


end of thread, other threads:[~2021-01-18 12:43 UTC | newest]

Thread overview: 32+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2020-12-22 10:14 [pgAdmin4][Patch] - RM 5457 - Kerberos Authentication - Phase 1 Khushboo Vashi <[email protected]>
2020-12-22 12:37 ` Akshay Joshi <[email protected]>
2021-01-01 07:37   ` Aditya Toshniwal <[email protected]>
2021-01-13 09:05     ` Khushboo Vashi <[email protected]>
2021-01-14 06:30       ` Akshay Joshi <[email protected]>
2021-01-14 06:47         ` Khushboo Vashi <[email protected]>
2021-01-14 08:12           ` Khushboo Vashi <[email protected]>
2021-01-14 08:18             ` Akshay Joshi <[email protected]>
2021-01-14 16:04               ` Dave Page <[email protected]>
2021-01-14 16:34                 ` Dave Page <[email protected]>
2021-01-15 10:18                   ` Dave Page <[email protected]>
2021-01-18 07:30                     ` Khushboo Vashi <[email protected]>
2021-01-18 09:15                       ` Dave Page <[email protected]>
2021-01-18 09:37                         ` Khushboo Vashi <[email protected]>
2021-01-18 09:55                           ` Dave Page <[email protected]>
2021-01-18 10:37                             ` Khushboo Vashi <[email protected]>
2021-01-18 11:10                               ` Akshay Joshi <[email protected]>
2021-01-18 12:34                                 ` Akshay Joshi <[email protected]>
2021-01-18 12:43                                   ` Khushboo Vashi <[email protected]>
2021-01-02 15:41 ` Stephen Frost <[email protected]>
2021-01-02 15:56   ` Dave Page <[email protected]>
2021-01-02 15:59     ` Stephen Frost <[email protected]>
2021-01-02 16:21       ` Dave Page <[email protected]>
2021-01-03 17:31         ` Stephen Frost <[email protected]>
2021-01-04 11:32           ` Dave Page <[email protected]>
2021-01-11 13:15           ` Magnus Hagander <[email protected]>
2021-01-11 13:21             ` Dave Page <[email protected]>
2021-01-11 16:50               ` Stephen Frost <[email protected]>
2021-01-11 16:59                 ` Dave Page <[email protected]>
2021-01-11 17:42                   ` Stephen Frost <[email protected]>
2021-01-12 09:08                     ` Dave Page <[email protected]>
2021-01-12 10:04                       ` Magnus Hagander <[email protected]>

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox