Page tree
Skip to end of metadata
Go to start of metadata

De verwachting is dat SURFsecureID vanaf 1 november 2019 OpenID Connect gaat ondersteunen. De dienst sluit dan aan op SURFconext met OpenID Connect en daar wordt dan SURFsecureID aangeroepen.

Introductie

SURFsecureID zelf ondersteunt op dit moment geen OpenID Connect koppeling. Een dienst die gebruik wil maken van SURFsecureID moet nu SAML2 gebruiken.

Echter, door het inzetten van een proxy tussen de dienst en SURFsecureID kan een dienst die OpenID Connect gebruikt wel aangesloten worden. Hieronder is dit schematisch weergegeven. De OpenID Connect Relying Party (OIDC RP) is de dienst die alleen OpenID Connect ondersteunt. De proxy vertaalt het OpenID Connect verzoek naar SAML, hiertoe doet de proxy zich voor als OpenID Provicer richting de dienst en als SAML Service Provider (SP) naar SURFsecureID.

Deze howto is geschreven voor een specifiek probleem van een instelling. Zij wilde AFAS gebruiken met SURFsecureID, maar AFAS ondersteunt dus alleen OpenID Connect als federatie protocol. De oplossing was om een SATOSA als proxy tussen AFAS en SURFsecureID te installeren.

Dit document beschrijft hoe SATOSA voor deze instelling geïnstalleerd en geconfigureerd is.

Voor je begint

Deze howto beschrijft beknopt de inrichting van een Ubuntu 16.04LTS server ten behoeve van een OIDC koppeling van AFAS online met SURFsecureID.

Het installeren van Ubuntu server 16.04LTS wordt buiten beschouwing gelaten.

In alle onderstaande commando's wordt uitgegaan van een actieve root shell. Let dus op wat je doet.


SATOSA installeren

Installeer python dependancies.

# apt install python3-setuptool python3-pip mongodb

Installeer SATOSA volgens de aanwijzingen op SATOSA manual installation.

Maak een SATOSA python virtual env.

# cd /opt
# virtuelenv --python=python3 satosa

Activeer de virtualenv.

# cd satosa
# . /bin/activate

Installeer SATOSA met pip

# pip install satosa

De paden in onderstaande handleiding gaan uit van /opt/satosa als working directory.

SATOSA configureren

Maak een file internal_attributes.yaml

attributes:
eppn:
openid: [sub, eppn]
saml: [eduPersonPrincipalName]
user_id_from_attrs: [eppn]
user_id_to_attr: eppn

Maak een file proxy_conf.yaml en vul correcte waarden in voor BASE (url),  STATE_ENCRYPTION_KEY en USER_ID_HASH_SALT

#--- SATOSA Config ---#
BASE: https://[base URL van de Proxy]
INTERNAL_ATTRIBUTES: "internal_attributes.yaml"
COOKIE_STATE_NAME: "SATOSA_STATE"
STATE_ENCRYPTION_KEY: "change this key"
CUSTOM_PLUGIN_MODULE_PATHS:
- "plugins/backends"
- "plugins/frontends"
BACKEND_MODULES:
- "plugins/backends/saml2_backend.yaml"
FRONTEND_MODULES:
- "plugins/frontends/oidc_frontend.yaml"
USER_ID_HASH_SALT: "change this salt"
LOGGING:
version: 1
formatters:
simple:
format: "[%(asctime)-19.19s] [%(levelname)-5.5s]: %(message)s"
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
info_file_handler:
class: logging.handlers.RotatingFileHandler
level: INFO
formatter: simple
filename: info.log
maxBytes: 10485760 # 10MB
backupCount: 20
encoding: utf8
loggers:
satosa:
level: DEBUG
handlers: [console]
propagate: yes
root:
level: INFO
handlers: [info_file_handler]

Maak een certificate directory:

# mkdir -p crt

Maak een 10 jaar geldig self-signed certificaat in deze directory

# cd crt
# openssl req -x509 -newkey rsa:4096 -keyout mijn_satosa.key -out mijn_satosa.crt -days 3650
# cd ..

Maak directories voor de backends configuraties:

# mkdir -p plugins/backends
# mkdir -p plugins/frontends

SATOSA SAML configuratie

Maak een SAML2 backend configuratie plugins/backends/saml2_backend.yaml en configureer de juiste waarden.

module: satosa.backends.saml2.SAMLBackend
name: Saml2
config:
sp_config:
key_file: crt/mijn_satosa.key
cert_file: crt/mijn_satosa.crt
organization: {display_name: Disply Name orginasatie, name: Naam organisatie, url: 'http://organisatie.nl/'}
contact_person:
- {contact_type: technical, email_address: ict@organisatie.nl, given_name: Technical}
- {contact_type: support, email_address: servicedesk@organisatie.nl, given_name: Support}
    metadata:
#local: [metadata/ssid-test.xml]
local: [metadata/ssid-prd.xml]
    entityid: <base_url>/<name>/ogt_proxy.xml
accepted_time_diff: 60
service:
sp:
ui_info:
display_name:
- lang: en
text: "Organisatie Proxy"
description:
- lang: en
text: "Organisatie Proxy"
information_url:
- lang: en
text: "http://organisatie.nl/"
privacy_statement_url:
- lang: en
text: "http://organisatie.nl/"
keywords:
- lang: en
text: ["Plaats", "AFAS", "Organisatie", "Afkorting"]
logo:
text: "http://sp.logo.url/"
width: "100"
height: "100"
authn_requests_signed: false
want_response_signed: false
allow_unsolicited: false
endpoints:
assertion_consumer_service:
- [<base_url>/<name>/acs/redirect, 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect']
- [<base_url>/<name>/acs/post, 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST']
name_id_format: 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'

SATOSA OIDC configuratie

Maak een OIDC frontend configuratie plugins/frontends/oidc_frontend.yaml:


module: satosa.frontends.openid_connect.OpenIDConnectFrontend
name: OIDC
config:
signing_key_path: crt/mijn_satosa.key
db_uri: mongodb://localhost # optional: only support MongoDB, will default to in-memory storage if not specified
provider:
client_registration_supported: No
response_types_supported: ["code", "id_token token"]
subject_types_supported: ["public"]
scopes_supported: ["openid", "email", "profile"]
claims_supported: ['sub', 'eppn']

Koppeling met SURFsecureID

Maak een metadata directory.

# mkdir metadata

Haal de SURFsecureID test en productie metadata op.

# curl https://sa-gw.test.surfconext.nl/authentication/metadata > metadata/ssid-test.xml
# curl https://sa-gw.surfconext.nl/authentication/metadata > metadata/ssid-prd.xml

Genereer SATOSA metadata.

# satosa-saml-metadata --dir metadata proxy_conf.yaml crt/cert.key crt/cert.crt

Wissel metadata/backend.xml met SURFconext uit en voer de nieuwe AFAS proxy op in het SURFConext SP Dashboard.

Koppeling met AFAS

We maken geen gebruik van de OIDC dynamic client registration. In plaats daarvan schrijven we de OIDC RP registratie zelf in de aanwezige Mongo database.

Maak een sync_clients script. Deze gebruiken we straks voor het inlezen van de OIDC RP configuratie.

#!/opt/satosa/bin/python
from pymongo import MongoClient
import json
import sys
import os
if len(sys.argv) < 2:
sys.exit("%s <clients.d>" % sys.argv[0])
client = MongoClient("mongodb://localhost:27017")
db = client['satosa']
mongo_coll = db['clients']
location = sys.argv[1]
file_coll = {}
for source in os.listdir(location):
with open("{}/{}".format(location,source)) as clients:
try:
file_coll.update(json.load(clients))
except:
sys.exit("Error loading {}".format(source))
# Debug collected clients
print("clients: {}".format(json.dumps(file_coll, indent=2)))
# Insert new clientID's (or update if different)
print("Inserting ID's")
for clientid, value in file_coll.items():
cursor = mongo_coll.find({"lookup_key": clientid})
if (cursor.count() == 0):
print(clientid)
doc = {
"lookup_key" : clientid,
"data" : value
}
mongo_coll.insert_one(doc)
elif (cursor.next()["data"] != value):
print("Update " + clientid)
mongo_coll.update_many({ "lookup_key": clientid }, { "$set": { "data": value } } )
# Cleanup removed ID's
print("Removing ID's")
cursor = mongo_coll.find({})
for doc in cursor:
clientid = doc["lookup_key"]
if clientid not in file_coll:
print(clientid)
mongo_coll.delete_many({'lookup_key': clientid})


Maak een clients directory

# mkdir clients

Maak een AFAS OIDC client in clients/clients.json en genereer een sterk client secret (zoals een sterk wachtwoord met minimaal 20 karakters).

{
"afasonline":
{
"application_type" : "web",
"client_name" : "AFAS Online",
"subject_type" : "public",
"client_secret" : "***",
"token_endpoint_auth_method": "client_secret_post",
"response_types" : [ "code" ],
"redirect_uris" : [ "https://sts.afasonline.com/signin-oidc" ],
"client_id" : "afasonline",
"client_secret_expires_at" : 0,
"client_id_issued_at" : 0
}
}

Voeg de client in de client database

# ./sync_clients clients



Voeg de OIDC proxy op als OpenID provider bij AFAS online:



SATOSA patch

Deze patch doet twee belangrijke zaken:

  • De manier van SAML koppelen met SURFsecureID gebruikt HTTP redirect en vereist een signed SAML AuthN request. Dit werd ten tijde van het schrijven van deze handleiding niet ondersteund.
  • Voorkomt dat de EPPN nogmaals door SATOSA gehashed wordt en in de sub van het ID Token zet

Patch SATOSA:

diff -Nur '--exclude=*.pyc' satosa-new/lib/python3.6/site-packages/satosa/backends/saml2.py satosa/lib/python3.6/site-packages/satosa/backends/saml2.py
--- satosa-new/lib/python3.6/site-packages/satosa/backends/saml2.py 2019-01-16 16:19:31.237803459 +0100
+++ satosa/lib/python3.6/site-packages/satosa/backends/saml2.py 2019-01-11 11:42:52.000000000 +0100
@@ -172,9 +172,9 @@
context.state)
acs_endp, response_binding = self.sp.config.getattr("endpoints", "sp")["assertion_consumer_service"][0]
req_id, req = self.sp.create_authn_request(
- destination, binding=response_binding, **kwargs)
+ destination, binding=binding, **kwargs)
relay_state = util.rndstr()
- ht_args = self.sp.apply_binding(binding, "%s" % req, destination, relay_state=relay_state)
+ ht_args = self.sp.apply_binding(binding, "%s" % req, destination, relay_state=relay_state, sigalg='http://www.w3.org/2001/04/xmldsig-more#rsa-sha256')
satosa_logging(logger, logging.DEBUG, "ht_args: %s" % ht_args, context.state)
except Exception as exc:
satosa_logging(logger, logging.DEBUG, "Failed to construct the AuthnRequest for state", context.state,
diff -Nur '--exclude=*.pyc' satosa-new/lib/python3.6/site-packages/satosa/internal_data.py satosa/lib/python3.6/site-packages/satosa/internal_data.py
--- satosa-new/lib/python3.6/site-packages/satosa/internal_data.py 2019-01-16 16:19:31.233803510 +0100
+++ satosa/lib/python3.6/site-packages/satosa/internal_data.py 2019-01-16 11:27:01.000000000 +0100
@@ -55,6 +55,7 @@
:param value: value to hash together with the salt
:return: hash value (SHA512)
"""
+ return value
return hashlib.sha512((value + salt).encode("utf-8")).hexdigest()

@staticmethod

SATOSA automatisch opstarten

Zorg dat de SATOSA start bij een server herstart met een systemd service file /etc/systemd/system/satosa.service

[Unit]
Description=SATOSA
After=syslog.target network.target
[Service]
Type=simple
User=satosa
WorkingDirectory=/opt/satosa
ExecStart=/opt/satosa/bin/python /opt/satosa/bin/gunicorn -blocalhost:8080 satosa.wsgi:app
Restart=on-abort
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=satosa
[Install]
WantedBy=multi-user.target

Enable SATOSA systemd unit

# systemctl daemon-reload
# systemctl enable satosa
# systemctl start satosa

Controleer start van SATOSA

# tail -f /var/log/syslog

Test!

  • No labels