I805

From k-space wiki
Jump to: navigation, search

I805 Authentication & Authorization

The goal of this course is to give an insight into various technologies used for authentication and authorization, mostly focusing on web technologies. Student who has passed the course should be able to introduce variety of authentication and authorization schemes into their applications.

Course is held at the hackerspace on Mondays and Fridays. To pass the course have 5 of 7 labs presented and 70% exam questions answered correctly.

In this course you're given a Ubuntu 16.04 container with public IP address. Use PHP 7.0 running under Apache2 to implement the labs.

Alternative submissions with nginx, Python, Flask etc are also accepted given that the used module does not significantly reduce the complexity of the submission.

Link to slides: X.509, Kerberos/LDAP, U2F

Assignments submissions accepted up to 1. nov 18:00, after that in December (have a lot of other stuff to do)

Exam attempts: 1. nov 16:00 at k-space.ee


37. week: HTTPS and X.509 certificates

Lecture about X.509 certificates and hardening TLS settings.

Lab prerequisites: public IP address, SSH access to the server, DNS record pointing to the IP address:

http://andris-web.k-space.ee/

http://chris-web.k-space.ee/

http://frank-web.k-space.ee/

http://indrek-web.k-space.ee/

http://karl-web.k-space.ee/

http://martin-web.k-space.ee/

http://peep-web.k-space.ee/

For the lab configure your webserver (nginx, Apache etc) to use Let's Encrypt certificates and use https://www.ssllabs.com/ssltest/ to verify the settings. Use Flask, PHP or your favourite tools as backend.

For lab submission send nicely formatted e-mail to lauri.vosandi@gmail.com stating the course code I805 in the e-mail title:

  • Open Wireshark, start packet capture, perform HTTPS request to your webserver, and stop the packet capture
  • Inspect the captured traffic and investigate which bits are visible in the handshake? Which ciphers are selected? Is the hostname visible in the handshake? Is the certificate (chain) visible?
  • Tweak the web server settings according to https://cipherli.st/
  • Elaborate what changes are observed compared to the vanilla web server configuration

38. week: HTTPS Client Certificates

For prototyping acquire your certificate:

pkcs15-tool -r 1 > auth.pem

Code snippets to test out in Python:

from asn1crypto import pem, x509
fh = open("cert.pem", "rb") # Open for reading as binary file
buf = fh.read()
header, _, der_bytes = pem.unarmor(buf) # This shall perform header checks and base64 decoding
cert = x509.Certificate.load(der_bytes) # This shall parse the ASN.1 representation of the certificate
cert.native # Serialize into native Python objects (dict, list, string, int, float, etc)
cert["tbs_certificate"]["subject"].native

Code snippet to perform (not cryptographically correct!) OCSP check:

 from asn1crypto import ocsp, pem, x509
 import requests
 certificate_buf = b"""
 -----BEGIN CERTIFICATE-----
 MIIF3DCCA8SgAwIBAgIPFVYSG+QtowBF9Ooqd9TiMA0GCSqGSIb3DQEBCwUAMIGo
 MRUwEwYKCZImiZPyLGQBGRYFcm9ja3MxGTAXBgoJkiaJk/IsZAEZFgljZXJ0aWR1
 ZGUxEzARBgoJkiaJk/IsZAEZFgNjYTUxFDASBgNVBAoMC0stU1BBQ0UgTkdPMR4w
 HAYDVQQLDBVDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMMIENlcnRpZHVk
 ZSBhdCBjYTUuY2VydGlkdWRlLnJvY2tzMB4XDTE4MDkyMDA5MzIxM1oXDTE5MDUx
 ODA5MzcxM1owgZQxFTATBgoJkiaJk/IsZAEZFgVyb2NrczEZMBcGCgmSJomT8ixk
 ARkWCWNlcnRpZHVkZTETMBEGCgmSJomT8ixkARkWA2NhNTEUMBIGA1UECgwLSy1T
 UEFDRSBOR08xFDASBgNVBAsMC1JvYWR3YXJyaW9yMR8wHQYDVQQDDBZhcmF1c2No
 ZWNrZXJAbWFjLTc4YTQ3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
 l6XMXtn2fDMLPlfUF+ZYjaIwu6hQFNV9X2Mna4kJkGtg3XLpCNz2BMVIaGq4moVU
 m6+LAmjWSz3B3Ww0ykNBIkRKac0dhbinB2C4TVmtmwBqiOGb3wsShFJefDGB5JsC
 22XzmS1Vv4ADakd9W7NIvqLA96wPuI9SJUBc4Og+PsG1MrBwvArw/36WyQw7oRWK
 NxnEoLjrQBP1iNUrk7UG/SVjyE459KgWVwTgKqUsoWbU+/fixWm3f60JONykKnVc
 HCGRlvdnX8GpCmKEhuU8jGdfsQipdSSwZ6ZWgldC91Uf/uaVl7lg2KFmaRNOdHrD
 6Upq8ZG5QmrVvUNu9HLD+wIDAQABo4IBEzCCAQ8wQAYIKwYBBQUHAQEENDAyMDAG
 CCsGAQUFBzABhiRodHRwOi8vY2E1LmNlcnRpZHVkZS5yb2Nrcy9hcGkvb2NzcC8w
 HwYDVR0jBBgwFoAUcn3wnrlvd+WqeQ5Ehm8XtUlbsuEwCQYDVR0TBAIwADA4BgNV
 HR8EMTAvMC2gK6AphidodHRwOi8vY2E1LmNlcnRpZHVkZS5yb2Nrcy9hcGkvcmV2
 b2tlZC8wEwYDVR0lBAwwCgYIKwYBBQUHAwIwHQYDVR0OBBYEFLnZ6MOX8kUmVLtC
 aJl2QoxQD9q1MA4GA1UdDwEB/wQEAwIFoDAhBgNVHREEGjAYghZhcmF1c2NoZWNr
 ZXJAbWFjLTc4YTQ3MA0GCSqGSIb3DQEBCwUAA4ICAQA5bwJdb/4pEMkcdhvxjqlo
 msvPPAkqfZfEIftaULuk24yNWvEGr1VpbpdGTwu2AdOiqmBGOZV01t/Tm26cVSzG
 tNuXbeyD6wMqId/1O3lLQr0z2/Zo3O7L05jz5u+2ek5PSF7MzeB5DTzsIzbSvQCA
 8spq0Z0J1pCXS4K2CGDZy1DPpKILI5jOGpIELwPFgwBzlT20ufVuQrQt7lvnUGwC
 RFWb3EKpHQE2gdWF6F2oiShkZJ2Kqsy4+dGFiimdM81vVmUGvCS8If0FHAyWo117
 xH41eWI2nVrEbUBBAP522dipFeWnHpc42XcbDmVOMKeBFnM+vt3VydSl30djEHOX
 UlOuRZ5rpnCejHWGoRxoPTX+ljNoyYwkcs/wLG4MX/qcV7CdfU1ESLoqUpBvdP7w
 2UQf+sybYsEmmB00y3MsvmJmaNZkeb6cySuN85kcZQ59WwWz5yR/GR76QZm6rioB
 eumxfemVgXYYXWL4RRyVyOqQPf7+bjp044pc++AW8tVcajhvy1me4T/5MMqmsQCi
 TLGcw4Fa4xrdwRE5sth41ZmugfmBTsggiwwm7Sy1XzwXO9stehGqTSr+S4zvJqGj
 GxInNnyJCnjc/+6HHSfaYnCVMzhkd/iUEnoiU1aETjTRropy3/6O79M4zrBTVc3V
 6BQc/tEpLI3oBosHzdnsZw==
 -----END CERTIFICATE-----
 """
 url = "http://ca5.certidude.rocks/api/ocsp/"
 header, _, certificate_der_bytes = pem.unarmor(certificate_buf)
 certificate = x509.Certificate.load(certificate_der_bytes)
 print("Certificate subject:", certificate.subject.native)
 buf = ocsp.OCSPRequest({
     "tbs_request": {
         "request_list": [{
             "req_cert": {
                 "serial_number":  certificate.serial_number,
                 'hash_algorithm': {
                     'algorithm': "sha1"
                 },
                 'issuer_name_hash': certificate.subject.sha1,
                 'issuer_key_hash': certificate.public_key.sha1,
             },
         }],
     }
 }).dump()
 r = requests.post(url, data=buf, headers={"Content-Type":"application/ocsp-request"})
 response = ocsp.OCSPResponse.load(r.content)
 for r in response["response_bytes"]["response"].native["tbs_response_data"]["responses"]:
     if r["cert_status"]:
         print("Certificate revoked:", r["cert_status"])
     else:
         print("Certificate valid/unknown")

Tasks:

  • Reconfigure your webserver to accept Estonian ID card, Digi-ID, TRP or E-resident authentication
  • In your application parse the certificate information, for Python use https://github.com/wbond/asn1crypto
  • Use the information as basis for creating user account in your system

Relevant questions:

  • Which user account fields can be provisioned from the information supplied by the certificate?
  • Does the certificate provide any authorization information?
  • What error is displayed to the end user if server fails to update client certificate revocation list (CRL)?
  • Is it possible to configure OCSP for client certificates in the web server configuration? Why?
  • How would one implement status checking in the web application backend?

Submission:

  • Send your website page which requires TLS client authentication
  • Make sure the application already populates an SQL database users table with relevant user information from certificate (birthdate, e-mail, first name, last name)
  • Answer to the questions above

39. week: Password storage

Add correctly implemented password storage for your web application.

Submission and related questions:

  • Implement password reset and session tracking functionality in your program
  • Allow logins with password if password has been set
  • Why storing passwords in database in plain-text is not acceptable?
  • Is simply using MD5 hashing algorithm on the password enough?
  • What are the lifetime and scope options of a cookie?
  • Why aren't one-time login links used in mainstream web?

40. week: Mobile-ID and Smart-ID

Code snippet to perform Mobile-ID authentication, see more information about demo accounts here:

 # pip3 install suds-jurko
 from suds.client import Client
 from time import sleep
 client = Client("https://tsp.demo.sk.ee/dds.wsdl")
 mid = client.service.MobileAuthenticate(, 'EE', "+37200000766", 'EST', \
     'Testimine', 'lauri-web.k-space.ee login', '12345678901234567890', \
     'asynchClientServer', 0, True, False)
 if mid.Status != 'OK':
     raise Exception("Failed to talk to SK server: %s" % mid.Status)
 print("Challenge: " + mid.ChallengeID)
 status = 'OUTSTANDING_TRANSACTION'
 while status == 'OUTSTANDING_TRANSACTION':
     sleep(2)
     status = client.service.GetMobileAuthenticateStatus(mid.Sesscode, False).Status
 if status != 'USER_AUTHENTICATED':
     raise Exception("Authentication failed: %s" % status)
 print('Hi ' + mid.UserGivenname + ' ' + mid.UserSurname + ', ' + mid.UserIDCode)
 print(mid.CertificateData)

Code snippet to perform Smart-ID authentication, see more information about demo accounts here:

 import requests
 import hashlib
 import struct
 import os
 from time import sleep
 from base64 import b64encode
 idcode = "10101010005"
 sid_url = "https://sid.demo.sk.ee/smart-id-rp/v1/"
 url = "%sauthentication/pno/EE/%s" % (sid_url, idcode)
 blob = os.urandom(64)
 i, = struct.unpack(">H", hashlib.sha256(blob).digest()[-2:])
 challenge = "%d" % (i % 10000)
 data={
     "relyingPartyUUID": "00000000-0000-0000-0000-000000000000",
     "relyingPartyName": "DEMO",
     "hash": b64encode(blob).decode("ascii"),
     "hashType": "SHA512",
     "displayText": "Ahoy there"
 }
 r = requests.post(url, json=data)
 sesscode = r.json().get("sessionID")
 state = "RUNNING"
 while state == "RUNNING":
     sleep(2)
     url = "%ssession/%s" % (sid_url, sesscode)
     print("Fetching: %s" % url)
     r = requests.get(url)
     state = r.json().get("state")
 if state == "COMPLETE":
     result = r.json().get("result").get("endResult")
     if result == "OK":
         print('Authenticated successfully')
         print(r.json().get("cert").get("value"))
     else:
         print("Authentication request failed: %s" % result)

Submission and related questions:

  • Implement Mobile-ID or Smart-ID support for your web application
  • Where is the private key stored in case of Mobile-ID? What about Smart-ID?
  • Is certificate validation also part of Mobile-ID/Smart-ID authetnication process or your application needs to perform it separately?
  • Which intermediate CA is used to sign Mobile-ID certificates? Smart-ID certificates?

41. week: Using LDAP as authentication backend

Change your password via remote desktop, your first name is the username and password is S4l4k4l4!!

 rdesktop 193.40.101.118 -g 90% -d office.lan


On your web server box install some packages:

 apt install ldap-utils libldap2-dev libsasl2-dev
 pip3 install pyldap

Obtain CA certificate used by LDAPS connections, save it to /etca/ldap/domain.pem

 -----BEGIN CERTIFICATE-----
 MIIFozCCA4ugAwIBAgIE+w6/WzANBgkqhkiG9w0BAQUFADBxMR0wGwYDVQQKExRT
 YW1iYSBBZG1pbmlzdHJhdGlvbjE3MDUGA1UECxMuU2FtYmEgLSB0ZW1wb3Jhcnkg
 YXV0b2dlbmVyYXRlZCBDQSBjZXJ0aWZpY2F0ZTEXMBUGA1UEAxMOREMxLm9mZmlj
 ZS5sYW4wHhcNMTgxMDExMDg1MTA3WhcNMjAwOTEwMDg1MTA3WjBxMR0wGwYDVQQK
 ExRTYW1iYSBBZG1pbmlzdHJhdGlvbjE3MDUGA1UECxMuU2FtYmEgLSB0ZW1wb3Jh
 cnkgYXV0b2dlbmVyYXRlZCBDQSBjZXJ0aWZpY2F0ZTEXMBUGA1UEAxMOREMxLm9m
 ZmljZS5sYW4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDUAzQF+Ygo
 J71iqneeI/Alqu3MMFePEtSp7hZSXtUL3+DkmU03T9WarMq0cQLaEDhcVoR7azzD
 f5bm4OCz0BMRyDD3Y1BYawcRHhE4vRLjNg1/XxQF3iTM7h9WgEx+CBEglmJK0JWP
 5HG4ukzjW0Xc6q5zI4Z1ypusxsqDpvDRA8HpTDXObCUK6UkT3cjcvumuH9XdjZf5
 nhDsU2dAdU3k7tUh3ViGAaWKHnXsQP/SYVdwbzz8Ry5m1FUhtsvNts+n55idFEUw
 Yn6GbnIaNB239pvUrY4zQ3l0PTvRcfm4Sssn++iocj/farx3ciYMe4G61BqAAQNF
 6/xyju4bDN83bGjaW3GUdB0wsronbg3RLxdV0FPTCmhyuKyPVxhldccViMsGfk7d
 O9e/Vxff3uRxuAXUf/LP0ntW1f5pDGP8nlnJIi8itHonlV5yzfvvO2WEIOw7fJn6
 NkUiOHupAeeu+8OiKHrZcgGMiBaxqo9exJy1FpM7yrBYKOYHBH4y5DFRK+wtxMid
 FK0UQGAddRMnc3iIxK7paiXn388Wp1JZehjtMw1kRXUE1aMeb0d4BX4krVHKyI4X
 eMrJeUf0q8qDJpy+NNPtXvXBUq+NI63c9R5GosC7YWBDpL+6FXCT7OiQiOOKgQfa
 DaKA9F5ZJpxUMJvdJtJTxQL6Dv1FFkDD5wIDAQABo0MwQTAPBgNVHRMBAf8EBTAD
 AQH/MA8GA1UdDwEB/wQFAwMHBgAwHQYDVR0OBBYEFE1Wi6XWVhojSlfMCzW9pm1Q
 PzQpMA0GCSqGSIb3DQEBBQUAA4ICAQBYRlPCFDaieaDGZKZg9OvkOCJrOjKLhG48
 guvDdxsqZLMEZC31xp0lw+x7aDRUNG9sKY1RGCtePqwyrzBgkeQwX+yIPyRPMLPX
 w54xYKSEcwERLkOmp03geTUvj8MdOkwBVVqiK0TXu7JpLrQf+w9XwItocZlJuAUG
 H0iQhHrRalleX7svly0gx9NtAUb/mz97vBomnkOhBpGlqoCihTI5m/sNgd1oB7ZN
 mGeyTZyvfCNOStd8IiFQHe4LngobTnYtvOvyrRl2xP9Zx3R+Jdfz8gEAIcPT7+Jx
 7j/lnGbPdepIRfTTMaf5hxgY42AXPMPxk3m8yA98h9hk5QQ7abMEGKe9jCUq8cPP
 pJBiBr9xbgSPq2ZTwH7LKHgYPhzxP07BZ8C3m3TmTW9mWkibfkbqmpje7/vrIaf1
 rnY4mNsXZQ0H5mMFLteOXHfjbehp2vvR7HNOz1A+QegOVo52/9Lh38epFB0CRRQw
 lyKcMISZKg5Rfd3XfNM+wnnKaetas2FF8B4PexY5JOS2OfSgOlqqYytheuVP1WnB
 1b2/lubylqW4kBg+xI7+YN5jPen7K59F/79Fc8S+CUwGykYJzaE+rqafcpvB7AcL
 hjoCSh7npPzfIG8HHYl3Fp0Rjdc4/L7pSOmXfojE4tm0zdZOk5ckvZ59twBes7pr
 kZ0YufmmLw==
 -----END CERTIFICATE-----

Configure LDAP client to use the certificates in /etc/ldap/ldap.conf

 BASE dc=office,dc=lan
 URI ldaps://dc1.office.lan
 TLS_CACERT /etc/ldap/domain.pem

Configure your web application to perform LDAP simple bind during authenitcation step, a'la:

 import ldap, ldap.sasl
 from getpass import getpass
 username = input("Enter username: ")
 password = getpass("Enter password: ")
 if "@" not in username:
     username = username + "@office.lan"
 try:
     conn = ldap.initialize('ldaps://dc1.office.lan')
     conn.set_option(ldap.OPT_REFERRALS, 0)
     conn.simple_bind_s(username, password)
 except ldap.SERVER_DOWN:
     print("Server down, possibly TLS certificate verification misconfigured!")
 except ldap.INVALID_CREDENTIALS:
     print("Authentication failed!")
     raise
 else:
     attribs = 'givenName', 'sn'
     search_filter = '(&(objectClass=user)(objectCategory=person)(userPrincipalName=%s))' % username
     r = conn.search_s('dc=office,dc=lan', ldap.SCOPE_SUBTREE, search_filter, attribs)
     for dn,entry in r:
         if not dn: continue
         given_name, = entry.get("givenName")
         surname, = entry.get("sn")
         print("Hello, ", given_name.decode("utf-8"), surname.decode("utf-8"))


This should be roughly equivalent with following, x stands for simple bind and W stands for interactive password prompt:

 ldapsearch -H ldaps://dc1.office.lan -x -W \
   -D lauri@office.lan \
   -b dc=office,dc=lan \
   '(&(objectClass=user)(objectCategory=person)(userPrincipalName=lauri@office.lan))' \
   givenName sn

First use ldapsearch to explore what kind of information is stored at the domain controller.

Quiz questions:

  • What needs to be done before LDAPS can be used to contact the LDAP server?

42. week: Using Kerberos for single sign-on

In Windows environments single sign-on heavily depends on the Kerberos protocol, see here for more about Kerberos. Configure you web application to use Kerberos authentication. Lectures here

Install some packages:

 apt install samba krb5-user libsasl2-modules-gssapi-heimdal

Adjust /etc/hosts so following command outputs fully qualified name of the machine (blah.office.lan):

 hostname -f

On your container make sure you can do Kerberos authenticated LDAP requests:

 kinit username@OFFICE.LAN
 ldapsearch -Y GSSAPI -H ldap://dc1.office.lan

Reset Kerberos client at /etc/krb5.conf:

 [libdefaults]
 default_realm = OFFICE.LAN
 dns_lookup_realm = true
 dns_lookup_kdc = true

Reset Samba client config at /etc/samba/smb.conf:

 [global]
 security = ads
 workgroup = OFFICE
 realm = OFFICE.LAN
 kerberos method = system keytab
 interfaces = eth1
 bind interfaces only = yes

Join domain, this shall create computer user object at domain controller and export it's keytab to /etc/krb5.keytab:

 kinit username@OFFICE.LAN
 net ads join -k

At this point it would be a good idea to observe what is stored in /etc/krb5.keytab:

 klist -Kkte

Now proceed to obtain keytab for the web server and adjust permissions accordingly:

 KRB5_KTNAME=FILE:/etc/apache2/server.keytab net ads keytab add HTTP -k
 chown root:www-data /etc/apache2/server.keytab
 chmod 640 /etc/apache2/server.keytab

From here on continue configuring your server to demand Kerberos authentication using that keytab


For the adventurous ones you can attempt to implement Kerberos authentication in your application, see example here: https://github.com/laurivosandi/certidude/blob/master/certidude/api/utils/firewall.py#L111



Questions:

  • What needs to be done before Kerberos can be used?
  • What kind of protection mechanisms does SPNEGO provide?
  • Does Kerberos provide any information regarding authorization?
  • What are the correct filesystem permissions for the Kerberos keytab?

Lab prerequisites: Usable domain controller, domain joined Windows desktop/server for testing the web application

43. week: Multifactor authentication with U2F

As an additional protection mechanism add U2F support for your web application

Lab preqrequisites: U2F dongle

44. week: Identity provider via OAuth2

Implement Google or any other third party login for your web application. See more documentation here and here