.. _feide: 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 :ref:`djangotilleggspakker`), og trenger ikke noen spesiell kjennskap til Feide utover de tilpasningene som er beskrevet under. Funksjonaliteten er avhengig av innstillingen :envvar:`USE_FEIDE_AUTH`. .. _feide_konfigurasjon: 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 "Wagtail utviklingsmiljø" for testinstallasjoner. * **Redirect URI:** Vil typisk være ``http://localhost:8000/accounts/dataporten/login/callback/`` for testinstallasjoner og ``https://wagtail.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 * **Social network:** Ingen * **Åpne for alle i utdanningssektoren:** Ja Permissions ~~~~~~~~~~~ Hvilken informasjon vi ber om å få om brukeren fra Feide. Vi trenger kun: * **E-post (email):** Brukerens e-postadresse. * **Bruker-ID (userid):** Brukerens ID i dataporten. * **Feide-navn (userid-feide):** Brukerens identifikator i Feide. Tilsvarende ``eduPersonPrincipalName``. 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 /django-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 ``wagtail.math.ntnu.no``) Nettstedet som brukes er nødt til å ha ``SITE_ID = 1`` (dette er hardkodet i ``src/website/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. .. _feide_lokale_tilpasninger: 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. 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: :: 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) for userid in data.get('userid_sec'): usertype, username = userid.split(':') if usertype == 'feide': data['username'] = username break return data ``feide.urls`` arver fra ``allauth.socialaccount.providers.dataporten.urls`` og installerer de nødvendige urlpatterns hvis :envvar:`USE_FEIDE_AUTH` er påskrudd: :: from django.conf import settings import allauth.socialaccount.providers.dataporten.urls if settings.USE_FEIDE_AUTH: urlpatterns = allauth.socialaccount.providers.dataporten.urls.urlpatterns # pylint: disable=invalid-name else: urlpatterns = [] 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 redigeringsrettigheter. Vi ønsker å kunne opprette brukerkontoer med riktige rettigheter på forhånd, slik at alt er klart til bruk første gang vedkommende logger inn i Wagtail. 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. Uønsket funksjonalitet i django-allauth ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django-allauth har ekstra funksjonalitet som vi ikke ønsker å bruke: * signup: Det er mulig å opprette lokal brukerkonto direkte, uten å gå via Feide-innlogging. * passordendring: En bruker kan sette lokalt passord på den lokale django-brukerkontoen sin, og dermed klare å logge inn selv om Feide-brukerkontoen blir stengt. Vi ønsker ikke slike bakveier inn i systemet, og har disablet disse funksjonene. Django-allauth har ingen mekanisme for å disable disse (dokumentasjonen nevner ingen ting om denne problemstillingen), så vi har brukt en workaround som kan komme til å slutte å fungere i nyere versjoner av django-allauth. I stedet for å la vår ``src/website/urls.py`` inkludere hele ``allauth.urls``, inkluderer vi kun de entrypointene som har med dataporten å gjøre. Dette gjøres via vår egen modul ``feide.urls``. En annen mulig løsning kunne vært å inkludere hele ``allauth.urls`` for så å overstyre/maskere de entrypointene vi ikke ønsker skal bli brukt. Denne måten er også sårbar for eventuelle endringer i nye versjoner av django-allauth (som tilføyer nye eller bytter navn på de endepunktene vi har overstyrt. Det er derfor lagt til automatiserte tester i ``src/feide/tests.py`` som sjekker at alt fremdeles er OK etter eventuelle oppgraderinger av django-allauth: Testene sjekker at de endepunktene og viewene vi har overstyrt faktisk er de som brukes, og at det ikke har dukket opp nye endepunkter under ``/accounts`` som ikke er maskert (bortsett fra ``/accounts/dataporten``). Se ``src/feide/tests.py``. Inn- og utlogging ~~~~~~~~~~~~~~~~~ Utlogging fra Dataporten er ikke implementert i django-allauth. Vi har derfor implementert noen egne views i ``feide``-modulen: * ``feide.views.logout``: Logger ut brukeren på riktig måte. Se https://docs.feide.no/developer_oauth/technical_details/oauth_authentication.html#logout * ``feide.views.login``: Redirigerer brukeren til riktig innloggings-URL avhengig av om Feide-innlogging er påskrudd eller ikke. Dette viewet brukes for tiden ikke av noen templates. Logging av inn/utlogginger og feilede innloggingsforsøk gjøres via signalhåndterere/callbacks i ``feide.signals``. Disse installeres via AppConfig-klassen i ``feide.apps``, se ``src/feide/__init__.py``.