Skip to content
Snippets Groups Projects
Commit 98c5798d authored by Andreas Klöckner's avatar Andreas Klöckner
Browse files

SAML2 bringup

parent 8c78514a
No related branches found
No related tags found
No related merge requests found
......@@ -550,13 +550,14 @@ class ExamFacilityMiddleware(object):
resolver_match = resolve(request.path)
from course.exam import check_in_for_exam, issue_exam_ticket
from course.auth import (user_profile, sign_in_by_email,
from course.auth import (user_profile, sign_in_choice, sign_in_by_email,
sign_in_stage2_with_token, sign_in_by_user_pw)
from course.flow import view_start_flow, view_flow_page
from django.contrib.auth.views import logout
ok = False
if resolver_match.func in [
sign_in_choice,
sign_in_by_email,
sign_in_stage2_with_token,
sign_in_by_user_pw,
......@@ -567,6 +568,9 @@ class ExamFacilityMiddleware(object):
logout]:
ok = True
elif path.startswith("/saml2"):
ok = True
elif (
(request.user.is_staff
or
......
......@@ -132,14 +132,14 @@ RELATE_MAINTENANCE_MODE = False
# May be set to a string to set a sitewide announcement visible on every page.
RELATE_SITE_ANNOUNCEMENT = None
# }}}
# Uncomment this to enable i18n, change 'en-us' to locale name your language.
# Make sure you have generated, translate and compile the message file of your
# language. If commented, RELATE will use default language 'en-us'.
#LANGUAGE_CODE='en-us'
# }}}
# {{{ exams and testing
RELATE_FACILITIES = {
......@@ -157,4 +157,118 @@ RELATE_TICKET_MINUTES_VALID_AFTER_USE = 12*60
# }}}
# {{{ saml2 (optional)
if RELATE_SIGN_IN_BY_SAML2_ENABLED:
from os import path
import saml2.saml
_BASEDIR = path.dirname(path.abspath(__file__))
_BASE_URL = 'https://relate.cs.illinois.edu'
SAML_CONFIG = {
# full path to the xmlsec1 binary programm
'xmlsec_binary': '/usr/bin/xmlsec1',
# your entity id, usually your subdomain plus the url to the metadata view
# (usually no need to change)
'entityid': _BASE_URL + '/saml2/metadata/',
# directory with attribute mapping
# (already populated with samples from djangosaml2, usually no need to
# change)
'attribute_map_dir': path.join(_BASEDIR, 'saml-config', 'attribute-maps'),
# this block states what services we provide
'service': {
'sp': {
'name': 'RELATE SAML2 SP',
'name_id_format': saml2.saml.NAMEID_FORMAT_PERSISTENT,
'endpoints': {
# url and binding to the assertion consumer service view
# do not change the binding or service name
'assertion_consumer_service': [
(_BASE_URL + '/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': [
(_BASE_URL + '/saml2/ls/',
saml2.BINDING_HTTP_REDIRECT),
(_BASE_URL + '/saml2/ls/post',
saml2.BINDING_HTTP_POST),
],
},
# attributes that this project needs to identify a user
'required_attributes': ['uid'],
# attributes that may be useful to have but not required
'optional_attributes': ['eduPersonAffiliation'],
# in this section the list of IdPs we talk to are defined
'idp': {
# Find the entity ID of your IdP and make this the key here:
'urn:mace:incommon:uiuc.edu': {
'single_sign_on_service': {
# Add the POST and REDIRECT bindings for the sign on service here:
saml2.BINDING_HTTP_POST:
'https://shibboleth.illinois.edu/idp/profile/SAML2/POST/SSO',
saml2.BINDING_HTTP_REDIRECT:
'https://shibboleth.illinois.edu/idp/profile/SAML2/Redirect/SSO',
},
'single_logout_service': {
# And the REDIRECT binding for the logout service here:
saml2.BINDING_HTTP_REDIRECT:
'https://shibboleth.illinois.edu/idp/logout.jsp', # noqa
},
},
},
},
},
# You will get this XML file from your institution. It has finite validity
# and will need to be re-downloaded periodically.
#
# "itrust" is an example name that's valid for the University of Illinois.
# This particular file is public and lives at
# https://discovery.itrust.illinois.edu/itrust-metadata/itrust-metadata.xml
'metadata': {
'local': [path.join(_BASEDIR, 'saml-config', 'itrust-metadata.xml')],
},
# set to 1 to output debugging information
'debug': 1,
# certificate
# see saml2-keygen.sh in this directory
'key_file': path.join(_BASEDIR, 'saml-config', 'sp-key.pem'), # private part
'cert_file': path.join(_BASEDIR, 'saml-config', 'sp-cert.pem'), # public part
# own metadata settings
'contact_person': [
{'given_name': 'Andreas',
'sur_name': 'Kloeckner',
'company': 'CS - University of Illinois',
'email_address': 'andreask@illinois.edu',
'contact_type': 'technical'},
{'given_name': 'Andreas',
'sur_name': 'Kloeckner',
'company': 'CS - University of Illinois',
'email_address': 'andreask@illinois.edu',
'contact_type': 'administrative'},
],
# you can set multilanguage information here
'organization': {
'name': [('RELATE', 'en')],
'display_name': [('RELATE', 'en')],
'url': [(_BASE_URL, 'en')],
},
'valid_for': 24, # how long is our metadata valid
}
# }}}
# vim: filetype=python:foldmethod=marker
......@@ -275,8 +275,6 @@ SAML_ATTRIBUTE_MAPPING = {
'sn': ('last_name', ),
}
SAML_CONFIG = join(BASE_DIR, "saml_config.py")
# }}}
# vim: foldmethod=marker
{% extends "base.html" %}
{% load i18n %}
{% block content %}
<h1>{% trans "Institutional Login (SAML2)" %}</h1>
<p>{% trans "Please select your Identity Provider from the following list:" %}</p>
<ul>
{% for url, name in available_idps %}
<li><a href="{% url 'djangosaml2.views.login' %}?idp={{ url }}{% if came_from %}&next={{ came_from }}{% endif %}">{{ name }}</a></li>
{% endfor %}
</ul>
{% endblock %}
......@@ -9,9 +9,10 @@
<li>
<a
class="btn btn-primary"
href="#"
href="{% url "djangosaml2.views.login" %}"
role="button"><i class="fa fa-institution"></i>
{% trans "Sign in using your institution's login" %} &raquo;</a>
(not yet working, but getting there)
</li>
{% endif %}
{% if relate_sign_in_by_email_enabled %}
......
......@@ -447,12 +447,12 @@ if settings.RELATE_MAINTENANCE_MODE:
if settings.RELATE_SIGN_IN_BY_SAML2_ENABLED:
urlpatterns.extend([
(r'^saml2/', include('djangosaml2.urls')),
url(r'^saml2/', include('djangosaml2.urls')),
])
if settings.DEBUG:
urlpatterns.extend([
# Keep commented unless debugging SAML2.
(r'^saml2-test/', 'djangosaml2.views.echo_attributes'),
url(r'^saml2-test/', 'djangosaml2.views.echo_attributes'),
])
# vim: fdm=marker
*.pem
*meta*.xml
This diff is collapsed.
EDUPERSON_OID = "urn:oid:1.3.6.1.4.1.5923.1.1.1."
X500ATTR = "urn:oid:2.5.4."
NOREDUPERSON_OID = "urn:oid:1.3.6.1.4.1.2428.90.1."
NETSCAPE_LDAP = "urn:oid:2.16.840.1.113730.3.1."
UCL_DIR_PILOT = "urn:oid:0.9.2342.19200300.100.1."
PKCS_9 = "urn:oid:1.2.840.113549.1.9."
UMICH = "urn:oid:1.3.6.1.4.1.250.1.57."
MAP = {
"identifier": "urn:mace:shibboleth:1.0:attributeNamespace:uri",
"fro": {
EDUPERSON_OID+'2': 'eduPersonNickname',
EDUPERSON_OID+'9': 'eduPersonScopedAffiliation',
EDUPERSON_OID+'11': 'eduPersonAssurance',
EDUPERSON_OID+'10': 'eduPersonTargetedID',
EDUPERSON_OID+'4': 'eduPersonOrgUnitDN',
NOREDUPERSON_OID+'6': 'norEduOrgAcronym',
NOREDUPERSON_OID+'7': 'norEduOrgUniqueIdentifier',
NOREDUPERSON_OID+'4': 'norEduPersonLIN',
EDUPERSON_OID+'1': 'eduPersonAffiliation',
NOREDUPERSON_OID+'2': 'norEduOrgUnitUniqueNumber',
NETSCAPE_LDAP+'40': 'userSMIMECertificate',
NOREDUPERSON_OID+'1': 'norEduOrgUniqueNumber',
NETSCAPE_LDAP+'241': 'displayName',
UCL_DIR_PILOT+'37': 'associatedDomain',
EDUPERSON_OID+'6': 'eduPersonPrincipalName',
NOREDUPERSON_OID+'8': 'norEduOrgUnitUniqueIdentifier',
NOREDUPERSON_OID+'9': 'federationFeideSchemaVersion',
X500ATTR+'53': 'deltaRevocationList',
X500ATTR+'52': 'supportedAlgorithms',
X500ATTR+'51': 'houseIdentifier',
X500ATTR+'50': 'uniqueMember',
X500ATTR+'19': 'physicalDeliveryOfficeName',
X500ATTR+'18': 'postOfficeBox',
X500ATTR+'17': 'postalCode',
X500ATTR+'16': 'postalAddress',
X500ATTR+'15': 'businessCategory',
X500ATTR+'14': 'searchGuide',
EDUPERSON_OID+'5': 'eduPersonPrimaryAffiliation',
X500ATTR+'12': 'title',
X500ATTR+'11': 'ou',
X500ATTR+'10': 'o',
X500ATTR+'37': 'cACertificate',
X500ATTR+'36': 'userCertificate',
X500ATTR+'31': 'member',
X500ATTR+'30': 'supportedApplicationContext',
X500ATTR+'33': 'roleOccupant',
X500ATTR+'32': 'owner',
NETSCAPE_LDAP+'1': 'carLicense',
PKCS_9+'1': 'email',
NETSCAPE_LDAP+'3': 'employeeNumber',
NETSCAPE_LDAP+'2': 'departmentNumber',
X500ATTR+'39': 'certificateRevocationList',
X500ATTR+'38': 'authorityRevocationList',
NETSCAPE_LDAP+'216': 'userPKCS12',
EDUPERSON_OID+'8': 'eduPersonPrimaryOrgUnitDN',
X500ATTR+'9': 'street',
X500ATTR+'8': 'st',
NETSCAPE_LDAP+'39': 'preferredLanguage',
EDUPERSON_OID+'7': 'eduPersonEntitlement',
X500ATTR+'2': 'knowledgeInformation',
X500ATTR+'7': 'l',
X500ATTR+'6': 'c',
X500ATTR+'5': 'serialNumber',
X500ATTR+'4': 'sn',
UCL_DIR_PILOT+'60': 'jpegPhoto',
X500ATTR+'65': 'pseudonym',
NOREDUPERSON_OID+'5': 'norEduPersonNIN',
UCL_DIR_PILOT+'3': 'mail',
UCL_DIR_PILOT+'25': 'dc',
X500ATTR+'40': 'crossCertificatePair',
X500ATTR+'42': 'givenName',
X500ATTR+'43': 'initials',
X500ATTR+'44': 'generationQualifier',
X500ATTR+'45': 'x500UniqueIdentifier',
X500ATTR+'46': 'dnQualifier',
X500ATTR+'47': 'enhancedSearchGuide',
X500ATTR+'48': 'protocolInformation',
X500ATTR+'54': 'dmdName',
NETSCAPE_LDAP+'4': 'employeeType',
X500ATTR+'22': 'teletexTerminalIdentifier',
X500ATTR+'23': 'facsimileTelephoneNumber',
X500ATTR+'20': 'telephoneNumber',
X500ATTR+'21': 'telexNumber',
X500ATTR+'26': 'registeredAddress',
X500ATTR+'27': 'destinationIndicator',
X500ATTR+'24': 'x121Address',
X500ATTR+'25': 'internationaliSDNNumber',
X500ATTR+'28': 'preferredDeliveryMethod',
X500ATTR+'29': 'presentationAddress',
EDUPERSON_OID+'3': 'eduPersonOrgDN',
NOREDUPERSON_OID+'3': 'norEduPersonBirthDate',
},
"to":{
'roleOccupant': X500ATTR+'33',
'gn': X500ATTR+'42',
'norEduPersonNIN': NOREDUPERSON_OID+'5',
'title': X500ATTR+'12',
'facsimileTelephoneNumber': X500ATTR+'23',
'mail': UCL_DIR_PILOT+'3',
'postOfficeBox': X500ATTR+'18',
'fax': X500ATTR+'23',
'telephoneNumber': X500ATTR+'20',
'norEduPersonBirthDate': NOREDUPERSON_OID+'3',
'rfc822Mailbox': UCL_DIR_PILOT+'3',
'dc': UCL_DIR_PILOT+'25',
'countryName': X500ATTR+'6',
'emailAddress': PKCS_9+'1',
'employeeNumber': NETSCAPE_LDAP+'3',
'organizationName': X500ATTR+'10',
'eduPersonAssurance': EDUPERSON_OID+'11',
'norEduOrgAcronym': NOREDUPERSON_OID+'6',
'registeredAddress': X500ATTR+'26',
'physicalDeliveryOfficeName': X500ATTR+'19',
'associatedDomain': UCL_DIR_PILOT+'37',
'l': X500ATTR+'7',
'stateOrProvinceName': X500ATTR+'8',
'federationFeideSchemaVersion': NOREDUPERSON_OID+'9',
'pkcs9email': PKCS_9+'1',
'givenName': X500ATTR+'42',
'x500UniqueIdentifier': X500ATTR+'45',
'eduPersonNickname': EDUPERSON_OID+'2',
'houseIdentifier': X500ATTR+'51',
'street': X500ATTR+'9',
'supportedAlgorithms': X500ATTR+'52',
'preferredLanguage': NETSCAPE_LDAP+'39',
'postalAddress': X500ATTR+'16',
'email': PKCS_9+'1',
'norEduOrgUnitUniqueIdentifier': NOREDUPERSON_OID+'8',
'eduPersonPrimaryOrgUnitDN': EDUPERSON_OID+'8',
'c': X500ATTR+'6',
'teletexTerminalIdentifier': X500ATTR+'22',
'o': X500ATTR+'10',
'cACertificate': X500ATTR+'37',
'telexNumber': X500ATTR+'21',
'ou': X500ATTR+'11',
'initials': X500ATTR+'43',
'eduPersonOrgUnitDN': EDUPERSON_OID+'4',
'deltaRevocationList': X500ATTR+'53',
'norEduPersonLIN': NOREDUPERSON_OID+'4',
'supportedApplicationContext': X500ATTR+'30',
'eduPersonEntitlement': EDUPERSON_OID+'7',
'generationQualifier': X500ATTR+'44',
'eduPersonAffiliation': EDUPERSON_OID+'1',
'eduPersonPrincipalName': EDUPERSON_OID+'6',
'localityName': X500ATTR+'7',
'owner': X500ATTR+'32',
'norEduOrgUnitUniqueNumber': NOREDUPERSON_OID+'2',
'searchGuide': X500ATTR+'14',
'certificateRevocationList': X500ATTR+'39',
'organizationalUnitName': X500ATTR+'11',
'userCertificate': X500ATTR+'36',
'preferredDeliveryMethod': X500ATTR+'28',
'internationaliSDNNumber': X500ATTR+'25',
'uniqueMember': X500ATTR+'50',
'departmentNumber': NETSCAPE_LDAP+'2',
'enhancedSearchGuide': X500ATTR+'47',
'userPKCS12': NETSCAPE_LDAP+'216',
'eduPersonTargetedID': EDUPERSON_OID+'10',
'norEduOrgUniqueNumber': NOREDUPERSON_OID+'1',
'x121Address': X500ATTR+'24',
'destinationIndicator': X500ATTR+'27',
'eduPersonPrimaryAffiliation': EDUPERSON_OID+'5',
'surname': X500ATTR+'4',
'jpegPhoto': UCL_DIR_PILOT+'60',
'eduPersonScopedAffiliation': EDUPERSON_OID+'9',
'protocolInformation': X500ATTR+'48',
'knowledgeInformation': X500ATTR+'2',
'employeeType': NETSCAPE_LDAP+'4',
'userSMIMECertificate': NETSCAPE_LDAP+'40',
'member': X500ATTR+'31',
'streetAddress': X500ATTR+'9',
'dmdName': X500ATTR+'54',
'postalCode': X500ATTR+'17',
'pseudonym': X500ATTR+'65',
'dnQualifier': X500ATTR+'46',
'crossCertificatePair': X500ATTR+'40',
'eduPersonOrgDN': EDUPERSON_OID+'3',
'authorityRevocationList': X500ATTR+'38',
'displayName': NETSCAPE_LDAP+'241',
'businessCategory': X500ATTR+'15',
'serialNumber': X500ATTR+'5',
'norEduOrgUniqueIdentifier': NOREDUPERSON_OID+'7',
'st': X500ATTR+'8',
'carLicense': NETSCAPE_LDAP+'1',
'presentationAddress': X500ATTR+'29',
'sn': X500ATTR+'4',
'domainComponent': UCL_DIR_PILOT+'25',
}
}
\ No newline at end of file
......@@ -2,7 +2,7 @@
# nicked and customized from Shibboleth
# Run as
# ./saml2-keygen.sh –h your.host.name –e https://your.host.name/saml2/metadata -y 10
# ./saml-keygen.sh –h your.host.name –e https://your.host.name/saml2/metadata/ -y 10
while getopts h:u:g:o:e:y:bf c
do
......
from os import path
import saml2
BASEDIR = path.dirname(path.abspath(__file__))
_BASE_URL = 'https://relate.cs.illinois.edu'
SAML_CONFIG = {
# full path to the xmlsec1 binary programm
'xmlsec_binary': '/usr/bin/xmlsec1',
# your entity id, usually your subdomain plus the url to the metadata view
'entityid': _BASE_URL + '/saml2/metadata/',
# directory with attribute mapping
'attribute_map_dir': path.join(BASEDIR, 'attribute-maps'),
# this block states what services we provide
'service': {
# we are just a lonely SP
'sp': {
'name': 'RELATE SAML2 SP',
'name_id_format': saml2.saml.NAMEID_FORMAT_PERSISTENT,
'endpoints': {
# url and binding to the assertion consumer service view
# do not change the binding or service name
'assertion_consumer_service': [
(_BASE_URL + '/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': [
(_BASE_URL + '/saml2/ls/',
saml2.BINDING_HTTP_REDIRECT),
(_BASE_URL + '/saml2/ls/post',
saml2.BINDING_HTTP_POST),
],
},
# attributes that this project needs to identify a user
'required_attributes': ['uid'],
# attributes that may be useful to have but not required
'optional_attributes': ['eduPersonAffiliation'],
# in this section the list of IdPs we talk to are defined
'idp': {
# we do not need a WAYF service since there is
# only an IdP defined here. This IdP should be
# present in our metadata
# the keys of this dictionary are entity ids
'https://localhost/simplesaml/saml2/idp/metadata.php': {
'single_sign_on_service': {
saml2.BINDING_HTTP_REDIRECT:
'https://localhost/simplesaml/saml2/idp/SSOService.php',
},
'single_logout_service': {
saml2.BINDING_HTTP_REDIRECT:
'https://localhost/simplesaml/saml2/idp/SingleLogoutService.php', # noqa
},
},
},
},
},
# where the remote metadata is stored
'metadata': {
'local': [path.join(BASEDIR, 'saml-config', 'remote_metadata.xml')],
},
# set to 1 to output debugging information
'debug': 1,
# certificate
# see saml2-keygen.sh in this directory
'key_file': path.join(BASEDIR, 'saml-config', 'sp-key.pem'), # private part
'cert_file': path.join(BASEDIR, 'saml-config', 'sp-cert.pem'), # public part
# own metadata settings
'contact_person': [
{'given_name': 'Andreas',
'sur_name': 'Kloeckner',
'company': 'CS - University of Illinois',
'email_address': 'andreask@illinois.edu',
'contact_type': 'technical'},
{'given_name': 'Andreas',
'sur_name': 'Kloeckner',
'company': 'CS - University of Illinois',
'email_address': 'andreask@illinois.edu',
'contact_type': 'administrative'},
],
# you can set multilanguage information here
'organization': {
'name': [('RELATE', 'en')],
'display_name': [('RELATE', 'en')],
'url': [(_BASE_URL, 'en')],
},
'valid_for': 24, # how long is our metadata valid
}
# vim: filetype=python
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment