Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: OIDC plugin not working with CILogon #630

Open
epkknd opened this issue Oct 30, 2024 · 1 comment
Open

Bug: OIDC plugin not working with CILogon #630

epkknd opened this issue Oct 30, 2024 · 1 comment
Labels
bug Something isn't working

Comments

@epkknd
Copy link

epkknd commented Oct 30, 2024

What happened?

I have installed coldfront and configured it to use cilogon for OIDC authentication. I am able to login using OIDC, but the username doesn't get pulled in properly (it uses a random string of characters as the username, instead of what is actually in the uid claim), and the first/last name fields are left blank. I have configured the OIDC client with attribute mapping, which is a feature in cilogon that allows us to change the name of claims. I used this to match the claims on our OIDC client to the claims that the oidc plugin is looking for in coldfront/plugins/mokey_oidc/auth.py. I used curl to check the claims from the same OIDC client, and it shows all the claim names are matching up to what auth.py is looking for. Even after doing this, it made no difference. I also tried deleting my user and logging in again to make sure it was actually creating a new user each time instead of using saved information. I also had one of my coworkers try logging in and he had the same result.

P.S. I'm running version 1.1.6 but that isn't an option in this form

Version

1.1.5

Component

Users

What browsers are you seeing the problem on?

Other

Relevant log output

(0.002) INSERT INTO `auth_user` (`password`, `last_login`, `is_superuser`, `username`, `first_name`, `last_name`, `email`, `is_staff`, `is_active`, `date_joined`) VALUES ('<REDACTED_PASSWORD>', NULL, 0, 'rQ-MVn0W-gU2YM5SHCkeB0mIJ1I', '', '', '<REDACTED_EMAIL', 0, 1, '2024-10-30 15:43:10.528617') RETURNING `auth_user`.`id`; args=('<REDACTED_PASSWORD>'', None, False, 'rQ-MVn0W-gU2YM5SHCkeB0mIJ1I', '', '', '<REDACTED_EMAIL>', False, True, '2024-10-30 15:43:10.528617'); alias=default

Tasks/ user tests when bug is fixed

  • [ ]
@epkknd epkknd added the bug Something isn't working label Oct 30, 2024
@chrisdaaz
Copy link

chrisdaaz commented Dec 9, 2024

This sounds like default behavior of the mozilla-django-oidc app. If the email doesn't exist in ColdFront, a new user is created with a hash of the email address as the username. I had to write a custom override to properly create new users (using a function that querie's our LDAP_:

# In a custom app we created for Northwestern-specific overrides
# In: coldfront/northwestern/auth.py
from mozilla_django_oidc.auth import OIDCAuthenticationBackend
from django.contrib.auth.models import User, Group
from coldfront.northwestern.utils import get_ldap_info

class NorthwesternOIDCAB(OIDCAuthenticationBackend):
    '''Override Default mozilla_django_odic methods'''    
    def create_user(self, claims):
        '''Create user from claims and LDAP data'''
        netid = claims.get('sub')
        if not netid:
            raise ValueError("NetID is required to create a user")

        # Retrieve user information from LDAP
        first_name = get_ldap_info(netid, 'givenName')
        last_name = get_ldap_info(netid, 'sn')
        email = get_ldap_info(netid, 'mail')

        # Create a new user instance
        user = User(
            username=netid,
            first_name=first_name,
            last_name=last_name,
            email=email
        )
        user.save()
        
        # Add user to a group based on their affiliation
        self.add_user_to_group_based_on_affiliation(user)
        
        return [user]

    def filter_users_by_claims(self, claims):
        '''Override the method to filter users by netid'''
        netid = claims.get('sub')
        if not netid:
            return self.UserModel.objects.none()
        
        try:
            # check if user exists
            user = User.objects.get(username=netid)
            return [user]
        except User.DoesNotExist:
            # create user if they do not exist
            return self.create_user(claims)

    def add_user_to_group_based_on_affiliation(self, user):
        '''Add user to a group based on their affiliation'''
        netid = user.username # Get the netid from the user
        
        # Retrieve affiliation from LDAP
        affiliation = get_ldap_info(netid, 'eduPersonPrimaryAffiliation')
        
        # Add user to a group based on their affiliation
        if affiliation == 'staff':
            group = Group.objects.get(name='Staff')
            group.user_set.add(user)
        elif affiliation == 'student':
            group = Group.objects.get(name='Student')
            group.user_set.add(user)
        elif affiliation == 'faculty':
            group = Group.objects.get(name='Faculty')
            group.user_set.add(user)
        elif affiliation == 'affiliate':
            group = Group.objects.get(name='Affiliate')
            group.user_set.add(user)
        else:
            group = Group.objects.get(name='Other')
            group.user_set.add(user)

To get this to work, I had to update: coldfront/config/auth.py

AUTHENTICATION_BACKENDS += [
    #'mozilla_django_oidc.auth.OIDCAuthenticationBackend',
    'coldfront.northwestern.auth.NorthwesternOIDCAB',
    'django.contrib.auth.backends.ModelBackend',
]

The claims I got from our OIDC provider were sub (username) and email, so I had to query LDAP to get first and last names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants