Skip to content

Instantly share code, notes, and snippets.

@darbula
Last active March 7, 2021 19:37
Show Gist options
  • Save darbula/5003f1d2e1528b089b30 to your computer and use it in GitHub Desktop.
Save darbula/5003f1d2e1528b089b30 to your computer and use it in GitHub Desktop.
Instructions on how to implement Single Sign-On authentication using AAI@EduHr in Django. In Croatian language.

AAI@EduHr: Django SSO

  1. Osnovni preduvjet za korištenje Single Sign-On (SSO) autentikacije u Django projektu je instalacija i konfiguracija paketa djangosaml2 koja se može obaviti prateći detaljne upute na stranici https://bitbucket.org/lgs/djangosaml2

    Referentne, testirane te u ovim uputama preporučene verzije potrebnih paketa su:

    • xmlsec1 1.2.18 (openssl)
    • pysaml2==0.4.3
    • djangosaml2==0.10.0

    U paketu pysaml2 0.4.3 potrebno je obaviti sljedeću promjenu u datoteci binding.py:

    # komentirati sljedeći redak
    # login_url = "?".join([location, urllib.urlencode(args)])
    # i umjesto njega dodati sljedeća dva retka
    join_symbol = "&" if "?" in location else "?"
    login_url = join_symbol.join([location, urllib.urlencode(args)])

    U nastavku su navedene modifikacije koraka navedenih uputama u točki 1. te dodatni koraci koje je potrebno obaviti kako bi autentikacija bila uspješna.

  2. Postojeći autentikacijski sustav preporučeno je u potpunosti zamijeniti sa SSO autentikacijom, pa 'djangosaml2.backends.Saml2Backend' treba biti jedini autentikacijski backend definiran u settings.py:

    AUTHENTICATION_BACKENDS = (
        'djangosaml2.backends.Saml2Backend',
    )
  3. Postaviti URL-ove na koji će se usmjeriti korisnika nakon uspješne prijave odnosno odjave. Postavka LOGIN_REDIRECT_URL se koristi samo ukoliko korisnik nije došao do formulara za prijavu pokušajem pristupa adresi u zaštićenom dijelu stranica, u tom slučaju se nakon uspješne prijave korisnik proslijeđuje na željenu adresu:

    LOGIN_REDIRECT_URL = '/'
    LOGOUT_REDIRECT_URL = '/'
  4. Ostaviti preddefiniranu vrijednost za postavku koji definira polje u modelu User nad kojim će se nakon uspješne autentikacije od strane AAI@EduHr sustava obaviti upit kako bi se pronašao odgovarajući Django korisnik:

    SAML_DJANGO_USER_MAIN_ATTRIBUTE = 'username'
  5. Ukoliko je korisnik uspješno autenticiran od strane AAI@EduHr sustava, a upitom u model User u polje definirano postavkom SAML_DJANGO_USER_MAIN_ATTRIBUTE nije pronađen odgovarajući korisnik tada će se kreirati novi Django korisnik i to u ovisnosti o slijedećoj postavci:

    SAML_CREATE_UNKNOWN_USER = True

    Ukoliko želite veću kontrolu prilikom odluke o stvaranju novih Django korisnika pogledajte nekoliko opcija u odjeljku Kreiranje Django korisnika.

  6. Nakon autentikacije Django korisnika Saml2Backend može unijeti odnosno osvježiti podatke o korisniku iz podataka iz imenika odnosno atributa koji su isporučeni od strane AAI@EduHr sustava prilikom same autentikacije.

    Kako bi definirali koji će atributi biti isporučeni pogledajte odjeljak u ovim uputama u kojem se opisuje postupak registracije aplikacije u sustav AAI@EduHr.

    Nadalje, potrebno je definirati u koja će polja modela User isporučeni atributi biti upisivani. Slijedeće vrijednosti možete koristiti kao početne:

    SAML_ATTRIBUTE_MAPPING = {
        'hrEduPersonUniqueID': ('username', ),
        'mail': ('email', ),
        'givenName': ('first_name', ),
        'sn': ('last_name', ),
    }

    Prema djangosaml2 uputama isporučeni atributi se mogu automatski upisivati i u polja modela u kojem je definiran profil korisnika, međutim takav način osvježavanja profila bi trebalo izbjegavati s obzirom da koristi funkcionalnosti koje nisu podržane u novim verzijama Djanga kao što to opisuje ovaj issue.

    Osvježavanje drugih modela korištenjem isporučenih atributa kao i selektivno osvježavanje modela User može se ostvariti definiranjem handler-a za pre_user_save signal kako je opisano u uputama za djangosaml2. Ukoliko radite update modela koji nije User potrebno je pozvati i save metodu.

  7. Ako koristite Django verziju 1.5 ili višu tada je potrebno kopirati sve template-e iz djangosaml2 aplikacije koji koriste url template tag i modificirati ih na način da imaju navodnike oko prvog parametra.

    Kako je navedeno i u službenoj dokumentaciji, Django od verzije 1.5 ne podržava implicitno pretvaranje prvog argumenta url template tag-a u string. Isto je napomenuto i u zasada nerješenoj razvojnoj stavci djangosaml2 paketa.

Konfiguracija paketa pysaml2

Paket djangosaml2 u pozadini koristi paket pysaml koji obavlja većinu posla vezanog uz kreiranje saml paketa i komunikacije.

Primjer konfiguracije tog paketa prilagođen sustavu AAI@EduHr koji se definira u datoteci settings.py dan je u nastavku:

from os import path
import saml2
BASEDIR = path.dirname(path.abspath(__file__))
SAML_CONFIG = {
    'xmlsec_binary': '/usr/bin/xmlsec1',
    'entityid': 'http://localhost:8000/saml2/metadata/',
    'service': {
      'sp': {
            'name': 'Django sample SP',
            'endpoints': {
                # url and binding to the assetion consumer service view
                # do not change the binding or service name
                'assertion_consumer_service': [
                  ('http://localhost:8000/saml2/acs/',
                   saml2.BINDING_HTTP_POST),
                ],
                # url and binding to the single logout service view
                # do not change the binding or service name
                'single_logout_service': [
                    ('http://localhost:8000/saml2/ls/',
                    saml2.BINDING_HTTP_REDIRECT),
                ],
            },
        },
    },
    # where the remote metadata is stored
    'metadata': {
        'remote': [
            {
                "url": "https://login.aaiedu.hr/sso/module.php/aggregator/?id=aaieduhr_fedlab&mimetype=application"  # lab
                #"url": "https://login.aaiedu.hr/sso/idp_riteh.xml",  # production
                "cert": "idp.crt"
            }
        ],
        #'local': [path.join('path', 'to', 'remote_metadata.xml')],  # local xml alternative
    },

    # set to 1 to output debugging information
    #'debug': 1,

    # certificate
    'key_file': path.join(BASEDIR, 'key.pem'),    # private part
    'cert_file': path.join(BASEDIR, 'cert.pem'),  # public part

    # own metadata settings used by make_metadata.py
    'contact_person': [
        {
        'given_name': 'Name',
        'sur_name': 'Surname',
        'company': 'Company',
        'email_address': 'mail@example.com',
        'contact_type': 'technical',
        },
        {
        'given_name': 'Name',
        'sur_name': 'Surname',
        'company': 'Company',
        'email_address': 'mail@example.com',
        'contact_type': 'administrative',
        },
    ],
    # you can set multilanguage information here
    'organization': {
        'name': [('Company', 'en'), ],
        'display_name': [('CO', 'en'), ],
        'url': [('http://www.example.com', 'en'), ],
    },
}

Službena dokumentacija svih parametara može se naći na ovoj stranici.

Ono što slijedi su potrebne modifikacije te standardne konfiguracije:

  • Provjerite ako je put do datoteke xmlsec1 ispravno upisan u parametar'xmlsec_binary'. Put možete naći naredbom which xmlsec1.

  • Vrijednosti parametara entityid, assertion_consumer_service i single_logout_service potrebno je unijeti na način da se "localhost:8000" zamijeni s nazivom i portom poslužitelja na kojem se aplikacija nalazi.

  • Sadržaj datoteke remote_metadata.xml dohvaća se s adrese https://login.aaiedu.hr/sso/idp_riteh.xml za produkciju odnosno https://login.aaiedu.hr/sso/module.php/aggregator/?id=aaieduhr_fedlab&mimetype=application za lab. Certifikat idp.crt u kojem je javni ključ kojim verificiramo datoteku je potrebno dohvatiti s adrese https://login.aaiedu.hr/sso/module.php/saml/idp/certs.php/idp.crt. Dodatno je potrebno osigurati prisutnost TERENA SSL CA certifikata u datoteci /path/to/lib/python2.7/site-packages/httplib2/cacerts.txt. Lanac certifikata može se dobiti naredbom openssl s_client -showcerts -connect login.aaiedu.hr:443 </dev/null, iz kojeg je potrebno kopirati samo TERENA SSL CA certifikat.

    • Ukoliko verifikacija datoteke ne funkcionira moguće zaobići udaljeni dohvat i datoteku dohvaćati koristeći cron npr. 0 7 * * * wget --ca-directory=/path/to/lib/python2.7/site-packages/httplib2 -O ~/path/to/remote_metadata.xml https://login.aaiedu.hr/sso/saml2/idp/metadata.php te referencirati se na nju u postavkama koristeći:

      'metadata': {
          'local': [path.join('path', 'to', 'remote_metadata.xml')],
      },
  • Što se tiče parametara

    'key_file': path.join(BASEDIR, 'key.pem'),  # private part
    'cert_file': path.join(BASEDIR, 'cert.pem'),  # public part

    Sustav AAI@EduHr za sada još uvijek ne provjerava certifikat vaše aplikacije pa možete kreirati bilo kakav self signed certifikat i unijeti ga kao parametar.

    Primjer kreiranja self signed certifikata:

    openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 365000 -nodes

Opcionalna dodatna podešavanja

  • Za potrebe razvoja lokalno odnosno na Django razvojnom poslužitelju te za potrebe testiranja može se koristiti mockdjangosaml2 paket. Upute za instalaciju i konfiguriranje nalaze se na stranicama repozitorija.

  • Postaviti https.

    Tijekom prijave se u nekim browserima (Firefox) javlja slijedeća poruka.

    Although this page is encrypted, the information you have entered is to be sent over an unencrypted connection and could easily be read by a third party. Are you sure you want to continue sending this information?

    Iako sigurnost nije dovedena u pitanje poruka ne izgleda lijepo. Mogući razlog je taj što AssertionConsumerServiceURL http://localhost:8000/saml2/acs/ ne koristi https protokol? TODO: provjeriti

Kreiranje Django korisnika

Ukoliko želite kontrolu prilikom odluke o stvaranju novih Django korisnika, odnosno ne želite za svakog korisnika koji je uspješno autenticiran preko sustava AAI@EduHr automatski stvoriti novog Django korisnika tada postoji nekoliko opcija od kojih izdvajamo:

  1. U projektu se definira novi backend kao podrazred Saml2Backend-a te u njemu definirati metodu is_authorized koja treba vratiti True ili False u ovisnosti o atributima korisnika. Primjer u kojem se pristup omogućava samo djelatnicima Tehničkog fakulteta u Rijeci, odnosno samo za njih se, ukoliko je potrebno, stvaraju novi Django korisnici:

    from djangosaml2.backends import Saml2Backend
    
    class CustomSaml2Backend(Saml2Backend):
        def is_authorized(self, attributes, attribute_mapping):
            if attributes.get('hrEduPersonHomeOrg', [''])[0]=='riteh.hr' and \
                attributes.get('hrEduPersonPrimaryAffiliation', [''])[0]=='djelatnik':
                return True
            return False

    U ovom slučaju postavka SAML_CREATE_UNKNOWN_USER ostaje definirana kao True. Takodjer, ne zaboravite u postavci AUTHENTICATION_BACKENDS zamijeniti postojeći backend s novim.

  2. Postavite vrijednost postavke SAML_CREATE_UNKNOWN_USER na ˙False˙. U tom slučaju potrebno je za korisnike za koje se želi omogućiti pristup prethodno kreirati odgovarajuće Django korisnike nekom drugom metodom npr. kroz admin sučelje. Ti korisnici moraju imati korisničko ime koje odgovara 'hrEduPersonUniqueID'u LDAP bazi.

Obavezni koraci koji nisu vezani uz Django

Osim prethodno navedenoga, trebat ćete i registrirati Vašu aplikaciju u sustavu AAI@EduHr te zatražiti kreiranje testnog elektroničkog identiteta.

Registracija aplikacije

Registracija aplikacije obavlja se putem Registra resursa koji se nalazi na adresi http://www.aaiedu.hr/aairr/

Nakon što se prijavite u Registar, kliknite na ikonicu "Resursi koji koriste SAML protokol" i zatim u prozoru koji će vam se otvoriti kliknite na gumb "Zatraži registraciju novog resursa".

Prilikom popunjavanja zahtjeva:

U izborniku Vrsta resursa trebate odabrati: test.

U polju SAML metapodaci trebate upisati slijedeće vrijednosti:

  • Jedinstveni identifikator resursa: treba odgovarati onome što ste u datoteci settings.py unijeli kao vrijednost parametra 'entityid'.

  • AssertionConsumerService URL: treba odgovarati onome što ste u datoteci settings.py unijeli kao vrijednost parametra 'assertion_consumer_service'.

  • SingleLogoutService URL: treba odgovarati onome što ste u datoteci settings.py unijeli kao vrijednost parametra 'single_logout_service'.

  • Redirect Sign: false

  • Shema po kojoj se mapiraju atributi: niti jedna

  • Verzija SAML protokola koju servis koristi: 2.0

U polju "Označite atribute koje sustav AAI@EduHr treba isporučivati resursu" trebate odabrati isključivo minimalni set atributa koji je potreban za normalno funkcioniranje vaše aplikacije.

Popis svih atributa koje sustav AAI@EduHr može isporučiti vašoj aplikaciji naveden je na web stranici http://schema.aaiedu.hr/shema/

Ostatak forme popunite prema vlastitom nahođenju.

Testni elektronički identitet

I na kraju, obzirom da se u ovoj fazi radi o testnoj aplikaciji, morat ćete zatražiti i kreiranje testnog elektroničkog identiteta putem web sučelja na adresi https://fed-lab.aaiedu.hr/zahtjev.php?show=zahtjev_identitet

@zmajstor
Copy link

@darbula, hvala ti, vrlo korisno, ako netko želi koristit AAI@EduHr Single Sign-On u Ruby on Rails aplikaciji, ovo može pomoći: https://gist.github.com/zmajstor/9c00c8a76faa73e6cf96

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment