Feide-innlogging

Beskrivelse

For å få Feide-innlogging brukes tjenesten Dataporten, som er en OAuth 2.0-provider som autentiserer brukeren via Feide.

Django er konfigurert til å autentisere via OAuth 2.0 ved hjelp av biblioteket django-allauth (se Django tilleggspakker), og trenger ikke noen spesiell kjennskap til Feide utover de tilpasningene som er beskrevet under.

Konfigurasjon av Feide-innlogging

For at Feide-innlogging skal fungere må det defineres en applikasjon i Dataporten. Dette gjøres via Dataporten Dashboard.

Se Registering and managing applications, spesielt Managing applications for framgangsmåte.

Når applikasjonen registreres trengs disse opplysningene:

Basic info

Grunnleggende innstillinger:

  • Navn: Passende beskrivelse, f.eks “Discourse SSO”.

  • Redirect URI: Vil typisk være http://localhost:8000/accounts/dataporten/login/callback/ for testinstallasjoner og https://discourse-sso.math.ntnu.no/accounts/dataporten/login/callback/ for produksjonsinstansen.

  • Require user interaction: Ja

  • Client type: Confidential

Auth providers

Innstillinger om hvilke brukere som skal kunne logge inn:

  • Accept all providers: Nei

  • Miscellaneous login providers: Ingen (evt. “Feide test users” ved behov)

  • Social network: Ingen

  • Åpne for alle i utdanningssektoren: Ja

Permissions

Hvilken informasjon vi ber om å få om brukeren fra Feide. Vi trenger:

  • E-post (email): Brukerens e-postadresse.

  • Bruker-ID (userid): Brukerens ID i dataporten.

  • Feide-navn (userid-feide): Brukerens identifikator i Feide. Tilsvarende eduPersonPrincipalName.

  • Navn (userinfo-name): Brukerens navn.

  • Gruppetilhørigheter for undervisning (groups-edu): Årstrinn (GREP), basisgrupper, undervisningsgrupper og andre grupper.

  • Organisasjonstilhørighet (groups-org): Informasjon om vertsorganisasjoner og organisasjonsenheter, og personens roller ved disse.

  • Andre gruppetilhørigheter (groups-other): Grupper.

  • Longterm (longterm): Langvarig tilgang. Tilgang inntil brukeren trekker rettighetene tilbake.

Skopet “Longterm” er tatt med for å kunne kvalitetssikre og debugge emneinformasjonen/gruppetilhørighetene, og gjør at vi kan slå opp brukerens gruppetilmedlemskaper via Feide Groups API ikke bare ved pålogging (og noen minutter etterpå), men også når det har gått noen timer siden vedkommende logget på.

OAuth details

Når applikasjonen er opprettet finner man applikasjonens OAuth credentials under menyvalget “OAuth details”:

  • Client ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

  • Client Secret: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Disse må legges inn i Django slik:

  • Gå til /admin/

  • Logg inn som brukeren du opprettet med ./manage.py createsuperuser

  • Opprett et nytt Social applications-objekt med følgende innstillinger:

    • Provider: Dataporten

    • Name: Dataporten

    • Client id: Client ID fra Dataporten

    • Secret key: Client Secret fra Dataporten

    • Sites: Dette nettstedet (typisk localhost eller discourse-sso.math.ntnu.no)

Nettstedet som brukes er nødt til å ha SITE_ID = 1 (med mindre dette blir overstyrt i src/discourse_sso/settings.py), så det er enklest å endre navn på default site example.com til ønsket navn, i stedet for å legge inn en ny site i Django admin.

Tilpasninger av django-allauth

Innstillinger

Django-allauth sender i utgangspunktet epost til nye brukerkontoer, slik at de kan verifisere/bekrefte epostadressen sin. Dette er disablet ved hjelp av innstillingene ACCOUNT_EMAIL_VERIFICATION = 'none' og SOCIALACCOUNT_EMAIL_VERIFICATION = 'none' i Django settings.

For at brukeren skal bli logget rett inn uten å måtte bekrefte at man ønsker å logge inn via en tredjepartstjeneste (Dataporten) er SOCIALACCOUNT_LOGIN_ON_GET = True satt.

Dataporten-biblioteket trenger tilgang til brukerens OAuth-token for å kunne hente gruppemedlemskap fra Feide, derfor er SOCIALACCOUNT_STORE_TOKENS = True satt.

Bruk fullstendig Feide-brukernavn

Når django-allauth oppretter lokal Django-brukerkonto blir brukernavnet i utgangspunktet satt til første komponent av Feide-brukernavnet (alt før @-tegnet). Vi ønsker at lokalt brukernavn skal være det fullstendige Feide-brukernavnet.

Dette er ikke konfigurerbart i django-allauth hvis man bruker den medfølgende dataporten-modulen, vi har derfor tilpasset denne.

Installasjon av django-allauth skjer normalt ved å legge til følgende i INSTALLED_APPS (se dokumentasjonen til django-allauth):

INSTALLED_APPS = (
    ...
    # The following apps are required:
    'django.contrib.auth',
    'django.contrib.messages',
    'django.contrib.sites',

    'allauth',
    'allauth.account',
    'allauth.socialaccount',
    # ... include the providers you want to enable:
    'allauth.socialaccount.providers.dataporten',
    ...
)

I stedet for å inkludere allauth.socialaccount.providers.dataporten inkluderer vi vår egen feide. Da brukes autentiseringsmodulen fra src/feide/provider.py og urlpatterns fra src/feide/urls.py.

feide.provider arver fra allauth.socialaccount.providers.dataporten og overstyrer kun brukernavnet:

import allauth.socialaccount.providers.dataporten.provider as dataporten
from sso.functions import extract_username

class FeideProvider(dataporten.DataportenProvider):
    """
    allauth.socialaccount.providers-klasse brukt i settings.INSTALLED_APPS.
    i stedet for allauth.socialaccount.providers.dataporten.
    """
    def extract_common_fields(self, data):
        """
        Overstyr data['username'] men bruk resten av verdiene as-is.
        """
        data = super().extract_common_fields(data)
        username = extract_username(data['userid_sec'])
        data['username'] = username
        return data

feide.urls henter nødvendige urlpatterns fra allauth.socialaccount.providers.dataporten.urls:

import allauth.socialaccount.providers.dataporten.urls

urlpatterns = allauth.socialaccount.providers.dataporten.urls.urlpatterns  # pylint: disable=invalid-name

Tilpassing av hvordan nye brukerkontoer opprettes

I utgangspunktet må en ny bruker logge inn én gang slik at brukerkontoen blir opprettet, før det er mulig å tildele andre rettigheter enn de som hentes automatisk fra FS.

Hvis vi oppretter en Django-brukerkonto med et gitt Feide-brukernavn på forhånd, vet ikke django-allauth (og kan ikke vite/anta) at dette er snakk om samme bruker, og django-allauth vil i utgangspunktet da opprette en annen Django-brukerkonto med annet/tilfeldig/udefinert brukernavn som er koblet til Feide-kontoen.

Vi har bedt django-allauth om å gjøre en slik antakelse - ved første gangs innlogging blir Feide-kontoen koblet mot eksisterende Django-konto hvis det finnes en Django-konto med samme brukernavn som Feide-kontoen.

Dette er gjort ved å bruke vår egen SocialAccountAdapter feide.adapter.SocialAccountAdapter. Denne arver fra allauth.socialaccount.adapter.DefaultSocialAccountAdapter men overstyrer logikken rundt oppretting av brukerkonto. Hvilken adapter som skal brukes styres av innstillingen SOCIALACCOUNT_ADAPTER i Django settings.