AzureAdOAuthenticator returning given name instead of username

After successful login using Azure AD Oauthenticator we are getting the full given name instead of the unique username so the local process spawner is failing to spawn with errors. How do we make the username as firstname.lastname so that the OS username will match for getpwnam() .:

[E 2022-11-23 05:04:19.937 JupyterHub user:832] Unhandled error starting xxxxxxx, xxxxxxx (xxxx)'s server: “getpwnam(): name not found: ‘xxxxxx, xxxxxx (xxxxx)’”
Traceback (most recent call last):
File “/data/opt/anaconda3/lib/python3.9/site-packages/jupyterhub/user.py”, line 747, in spawn
url = await gen.with_timeout(timedelta(seconds=spawner.start_timeout), f)
File “/data/opt/anaconda3/lib/python3.9/site-packages/jupyterhub/spawner.py”, line 1664, in start
env = self.get_env()
File “/data/opt/anaconda3/lib/python3.9/site-packages/jupyterhub/spawner.py”, line 1611, in get_env
env = self.user_env(env)
File “/data/opt/anaconda3/lib/python3.9/site-packages/jupyterhub/spawner.py”, line 1598, in user_env
home = pwd.getpwnam(self.user.name).pw_dir
KeyError: “getpwnam(): name not found: ‘xxxxx, xxxxxx (xxxxxx)’”

These are the parms we set in /etc/jupyterhub/jupyterhub_config.py

import os
from oauthenticator.azuread import AzureAdOAuthenticator

c.JupyterHub.authenticator_class = AzureAdOAuthenticator
c.Application.log_level = ‘DEBUG’
c.AzureAdOAuthenticator.tenant_id = os.environ.get(‘AAD_TENANT_ID’)
c.AzureAdOAuthenticator.client_id = ‘redacted’
c.AzureAdOAuthenticator.client_secret = ‘redacted’
c.AzureAdOAuthenticator.oauth_callback_url = ‘https://redacted:8000/hub/oauth_callback
c.AzureAdOAuthenticator.scope = [‘openid’, ‘profile’, ‘email’]
c.AzureAdOAuthenticator.username_claim = unique_name

Is the required username already available in your response? If so you change the field used as the username.

If not you can write a custom function to generate your username base on the userinfo response:

Thanks for the reply! How would you figure out the fields in the Azure AD response within the ssl payload. And how do you change the field used as the username.

“Is the required username already available in your response? If so you change the field used as the username.”

You can set c.GenericOAuthenticator.username_claim to the name of the field you want to use.

A bit of Googling brought up Microsoft identity platform UserInfo endpoint - Microsoft Entra | Microsoft Learn but I don’t know whether that applies to all AureAD servers, so you may have to add some debug logs or talk to your AzureAD administrator to work out what’s in the response.

As given in example oauthenticator/sample_jupyter_config.py at 0a2f0d8c0a99469570b7c1168cec6dfcaf45ec5f · jupyterhub/oauthenticator · GitHub after changing in the config to:
c.AzureAdOAuthenticator.username_claim = ‘unique_name’

Now I get the email address returned so getting closer. Just need to figure out how to get the upn firstname.lastname or may need to change config to ignore the @xyz.com suffix in the email address. Which parameter in the config can be used to remove the @xyz.com suffix using some regular expression or other means?

username_claim can be a callable, which means it can be a function that manipulates the response. Something like this may work:

def get_username_from_userinfo(userinfo):
    return userinfo["email"].split("@")[0]

c.AzureAdOAuthenticator.username_claim = get_username_from_userinfo

Hello @manics I tried above code but jupyterhub wont start and gave error below. Another other ideas?

  File "/data1r10/opt/anaconda3/lib/python3.9/site-packages/traitlets/traitlets.py", line 2190, in validate
    self.error(obj, value)
  File "/data1r10/opt/anaconda3/lib/python3.9/site-packages/traitlets/traitlets.py", line 692, in error
    raise TraitError(e)
traitlets.traitlets.TraitError: The 'username_claim' trait of an AzureAdOAuthenticator instance expected a unicode string, not the function 'get_username_from_userinfo'.

Apologies, that was only recently added to AzureAdOAuthenticator as part of a large refactoring so it’s not released yet:

Previously only some authenticators supported a callable username_claim, but hopefully it won’t be too long until it’s released.

ok no problem, will try to see if can include the logic manually or wait until official release. I haven’t looked at the code much so if you can point me to the function to add some code for the simplest way to modify the email to remove the @xyz.com suffix that will be a great help.

1 Like