Intternal server error 500 with KDCAutheticator

Hi,

I have a z2jh with authenticator_class = KDCAutheticator but with our small fix in autheticate function.

The authetication works but the annoying thing is that no user can authenticate on the first try (the page will show Internal Server Error 500) but when you reload the page or just authenticate again, everything is fine.

I have logs from the hub pod which clearly show, that even when I specified KDCAutheticator as default auth, the LocalAutheticator still wants to create system users. I do not want LocalAuthenticator to create these users but setting c.LocalAuthenticator.create_system_users = False didn’t help at all.

Logs:
the authenticate function works as expected, it extracts username and handles over.

[I 2021-03-16 12:02:45.610 JupyterHub kdcauthenticator:145] kerberos.authGSSServerInit
16/03/2021 13:02:45 
[I 2021-03-16 12:02:45.610 JupyterHub kdcauthenticator:153] kerberos.checkPassword
16/03/2021 13:02:47 
[I 2021-03-16 12:02:47.709 JupyterHub kdcauthenticator:159] Extracted User = username
16/03/2021 13:02:47 
[D 2021-03-16 12:02:47.724 JupyterHub reflector:275] events watcher timeout
16/03/2021 13:02:47 
[D 2021-03-16 12:02:47.724 JupyterHub reflector:206] Connecting events watcher
16/03/2021 13:02:47 
[E 2021-03-16 12:02:47.829 JupyterHub web:1789] Uncaught exception POST /hub/login?next=%2Fhub%2F (192.168.2.221)

However at this point, code falls back to some check whether user exists.

[E 2021-03-16 12:02:47.829 JupyterHub web:1789] Uncaught exception POST /hub/login?next=%2Fhub%2F (192.168.2.221)
16/03/2021 13:02:47     HTTPServerRequest(protocol='https', host='hub.cerit-sc.cz', method='POST', uri='/hub/login?next=%2Fhub%2F', version='HTTP/1.1', remote_ip='192.168.2.221')
16/03/2021 13:02:47     Traceback (most recent call last):
16/03/2021 13:02:47       File "/usr/local/lib/python3.8/dist-packages/tornado/web.py", line 1704, in _execute
16/03/2021 13:02:47         result = await result
16/03/2021 13:02:47       File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/login.py", line 144, in post
16/03/2021 13:02:47         user = await self.login_user(data)
16/03/2021 13:02:47       File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 753, in login_user
16/03/2021 13:02:47         user = await self.auth_to_user(authenticated)
16/03/2021 13:02:47       File "/usr/local/lib/python3.8/dist-packages/jupyterhub/handlers/base.py", line 732, in auth_to_user
16/03/2021 13:02:47         await maybe_future(self.authenticator.add_user(user))
16/03/2021 13:02:47       File "/usr/local/lib/python3.8/dist-packages/jupyterhub/auth.py", line 838, in add_user
16/03/2021 13:02:47         raise KeyError(
16/03/2021 13:02:47     KeyError: 'User username does not exist on the system. Set LocalAuthenticator.create_system_users=True to automatically create system users from jupyterhub users.'

I went through code and thought that if new user is detected, username is added to sqlite db and then looked up if it already exists. I don’t need system user, it is suffiecient that the user autheticated in kerberos realm.

Is there any way how to solve this? I can’t find any way on how I could use this add function instead of this one. They both do exist but I don’t know how they are chosen

Login function wants to add_user when it doesn’t exist

    async def login_user(self, data=None):
        """Login a user"""
        auth_timer = self.statsd.timer('login.authenticate').start()
        authenticated = await self.authenticate(data)
        auth_timer.stop(send=False)

        if authenticated:
            user = await self.auth_to_user(authenticated)
            self.set_login_cookie(user)
            ...

Authenticated variable contains username from kerberos authenticate function which is fine. Then auth_to_user function resolves and this piece of code inside it

        if user is None:
            user = self.find_user(username)
            new_user = user is None
            if new_user:
                user = self.user_from_username(username)
                await maybe_future(self.authenticator.add_user(user))

decides that user should be added (user is None by default, set to something only when : user(User, optional): the User object to refresh, if refreshing
).

Should I override the add_user function in KDCAuthenticator? How can I turn this off?

Relevant part of Z2JH config:

 config:                                                                       
    JupyterHub:                                                                 
      authenticator_class: "kdcauthenticator.kdcauthenticator.KDCAuthenticator"
    krb-extra: |                                                                
           
      c.KDCAuthenticator.service_name = "http@name.cz"        

Thanks for any comments!

Your KDCAuthenticator class inherits from LocalAuthenticator:

Which is why it requires a matching local user.

Compare this with for example the DummyAuthenticator:

which inherits from Authenticator, and doesn’t require a local user.

You could either make this change in KDCAuthenticator- it might just work, or you might need to implement some other functions that it requires. Alternatively you could do as you suggested and override some of the functions in LocalAuthenticator, you’ll have to figure out whether you can just override one or if you need to override several by reading through the code.

1 Like

Hi,
yes, we have thought of changing the LocalAuthenticator to just Authenticator. When change happened, whole authetication starts to work.

1 Like