Weird-Sheep-Labs / django-azure-auth

A simple Django app for user authentication with Azure Active Directory/Entra ID.
MIT License
17 stars 10 forks source link

Retrieving extrafields #11

Closed marcotn closed 4 months ago

marcotn commented 1 year ago

Hi, do you think it would be possible to retrieve some extrafields from AzureAD during authentication, I am thinking about the EmployeeId .. do you have any suggestion about how to do it and in case I can make it would you be interested in a pull request ?

regoawt commented 1 year ago

Hi, I haven't confirmed this but I suspect you can add EmployeeID to the list of ID token claims in AzureAD, which you should then be able to access from the django session (ID token claims are stored on the session), for example in a view:

employee_id = request.session['id_token_claims'].get('EmployeeID')
marcotn commented 1 year ago

Hi I was a bit in a hurry and I managed to do it this way (I know it's ugly) but it works.

class SasaAuthHandler(AuthHandler): """ Class to interface with msal package and execute authentication process. """

def __init__(self, request=None):
    super().__init__()
    self._extra_fields = settings.AZURE_AUTH_EXTRA_FIELDS

def authenticate(self, token: dict) -> UserModel:
    """
    Helper method to authenticate the user. Gets the Azure user from the
    Microsoft Graph endpoint and gets/creates the associated Django user.

    :param token: MSAL auth token dictionary
    :return: Django user instance
    """

    _extra_returned = {}
    azure_user = self._get_azure_user(token["access_token"])
    if self._extra_fields:
        _extra_returned = self._get_azure_extra_fields(token["access_token"])

    # Allow for `outlook.com` users with email set on the
    # `userPrincipalName` attribute
    email = (
        azure_user["mail"]
        if azure_user.get("mail", None)
        else azure_user["userPrincipalName"]
    )

    # Using `UserModel._default_manager.get_by_natural_key` handles custom
    # user model and `USERNAME_FIELD` setting
    try:
        user = UserModel._default_manager.get_by_natural_key(email)
    except UserModel.DoesNotExist:
        user = UserModel._default_manager.create_user(username=email, email=email)
        user.first_name = attr if (attr := azure_user["givenName"]) else ""
        user.last_name = attr if (attr := azure_user["surname"]) else ""
        user.save()
    if user.username in settings.AZURE_AUTH_ADMINS:
        user.is_superuser = True
        user.is_staff = True
    if self._extra_fields:
        for _k, _v in self._extra_fields.items():
            _attr = getattr(user, _v)
            if _attr:
                setattr(user, _v, _extra_returned.get(_k))
                user.save()
    # TODO: Handle groups
    return user

def _get_azure_extra_fields(self, token):
    _extra_fields = ''
    for _extra_field in self._extra_fields:
        _extra_fields += f"{_extra_field},"
    _extra_fields = _extra_fields[:-1] #chop off the last ,
    url = f'https://graph.microsoft.com/v1.0//me?&$select={_extra_fields}'
    headers = {
        'Content-Type': 'application\json',
        'Authorization': f'Bearer {token}',
        'ConsistencyLevel': 'eventual'
    }
    result = {}
    r = requests.get(url, headers=headers)
    ret = r.json()
    for k,v in ret.items():
        if k in self._extra_fields:
            result[k] = v
    print(result)
    return result
regoawt commented 1 year ago

Hi, sorry for the delay. Thanks for the example - please feel free to submit a PR!

sebastian-muthwill commented 8 months ago

Hey @marcotn thanks for the suggestion. On thing that I just saw is, since you are not saving the user, this settings will not be saved if there are no _extre_fields.

if user.username in settings.AZURE_AUTH_ADMINS: user.is_superuser = True user.is_staff = True

Have you considered to submit a PR for this change? I would also be interested in saving additional attributes to the user model. If not I try to replicate it and create a PR for this.

marcotn commented 8 months ago

Hey @marcotn thanks for the suggestion. On thing that I just saw is, since you are not saving the user, this settings will not be saved if there are no _extre_fields.

if user.username in settings.AZURE_AUTH_ADMINS: user.is_superuser = True user.is_staff = True

Have you considered to submit a PR for this change? I would also be interested in saving additional attributes to the user model. If not I try to replicate it and create a PR for this.

Hi Sebastian, thanks for the suggestion, right now I have very little time so I cannot work seriously on a PR but if you need I can send you my code.

regoawt commented 5 months ago

This issue should be handled in the same fix as for #23 as per https://github.com/Weird-Sheep-Labs/django-azure-auth/issues/23#issuecomment-2112293823

regoawt commented 4 months ago

Please see https://github.com/Weird-Sheep-Labs/django-azure-auth/issues/23#issuecomment-2142771398 for an update.