From 5a8a8f595e6f54f783e279324efe452f9b1e12ec Mon Sep 17 00:00:00 2001 From: Mathieu Hinderyckx Date: Wed, 15 Mar 2017 00:01:09 +0100 Subject: [PATCH] Some cleanup and added comments. Improve docs. --- README.rst | 52 +-- djangosaml2idp/__init__.py | 2 +- djangosaml2idp/identity.py | 6 + .../templates/djangosaml2idp/login.html | 2 - djangosaml2idp/views.py | 42 ++- docs/example_setup/README.rst | 36 ++ docs/index.rst | 112 +----- docs/installation.rst | 101 ++++++ example_setup/README.rst | 36 ++ example_setup/docker-compose.yml | 4 +- example_setup/idp/Dockerfile | 12 +- .../idp/idp/saml2_config/sp_metadata.xml | 87 +++-- example_setup/idp/idp/settings.py | 54 +-- .../idp/idp/templates/idp/login.html | 10 +- example_setup/sp/Dockerfile | 10 +- .../saml2_config/attribute-maps/__init__.py | 0 .../sp/saml2_config/attribute-maps/basic.py | 325 ++++++++++++++++++ .../saml2_config/attribute-maps/saml_uri.py | 205 +++++++++++ .../saml2_config/attribute-maps/shibboleth.py | 190 ++++++++++ .../sp/sp/saml2_config/idp_metadata.xml | 89 +++-- example_setup/sp/sp/settings.py | 62 ++-- example_setup/sp/sp/views.py | 3 +- tests/settings.py | 52 --- 23 files changed, 1116 insertions(+), 376 deletions(-) create mode 100644 djangosaml2idp/identity.py create mode 100644 docs/example_setup/README.rst create mode 100644 docs/installation.rst create mode 100644 example_setup/README.rst create mode 100644 example_setup/sp/sp/saml2_config/attribute-maps/__init__.py create mode 100644 example_setup/sp/sp/saml2_config/attribute-maps/basic.py create mode 100644 example_setup/sp/sp/saml2_config/attribute-maps/saml_uri.py create mode 100644 example_setup/sp/sp/saml2_config/attribute-maps/shibboleth.py diff --git a/README.rst b/README.rst index bc341a7..5a1c98a 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,11 @@ djangosaml2idp :target: https://pypi.python.org/pypi/djangosaml2idp :alt: PyPi +.. image:: https://readthedocs.org/projects/djangosaml2idp/badge/?version=latest + :alt: Documentation Status + :scale: 100% + :target: https://djangosaml2idp.readthedocs.io/en/latest/?badge=latest + .. image:: https://travis-ci.org/mhindery/djangosaml2idp.svg?branch=master :target: https://travis-ci.org/mhindery/djangosaml2idp :alt: Travis CI @@ -34,7 +39,7 @@ PySAML2 uses xmlsec1_ binary to sign SAML assertions so you need to install it either through your operating system package or by compiling the source code. It doesn't matter where the final executable is installed because you will need to set the full path to it in the configuration stage. -``xmlsec`` is available (at least) for Debian, OSX and Alpine Linux. +xmlsec is available (at least) for Debian, OSX and Alpine Linux. .. _xmlsec1: http://www.aleksey.com/xmlsec/ @@ -72,46 +77,49 @@ In your Django settings, configure your IdP. Configuration follows the pysaml2_c from saml2.saml import NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED from saml2.sigver import get_xmlsec_binary - BASE_URL = "http://localhost:9000/idp" + LOGIN_URL = '/login/' + BASE_URL = 'http://localhost:9000/idp' SAML_IDP_CONFIG = { - "entityid": "%s/metadata" % BASE_URL, - "description": "Example IdP setup", - "valid_for": 168, - "service": { - "idp": { - "name": "Django localhost IdP", - "endpoints": { - "single_sign_on_service": [ - ("%s/sso/post" % BASE_URL, saml2.BINDING_HTTP_POST), - ("%s/sso/redirect" % BASE_URL, saml2.BINDING_HTTP_REDIRECT), + 'debug' : DEBUG, + 'xmlsec_binary': get_xmlsec_binary(['/opt/local/bin', '/usr/bin/xmlsec1']), + 'entityid': '%s/metadata' % BASE_URL, + 'description': 'Example IdP setup', + + 'service': { + 'idp': { + 'name': 'Django localhost IdP', + 'endpoints': { + 'single_sign_on_service': [ + ('%s/sso/post' % BASE_URL, saml2.BINDING_HTTP_POST), + ('%s/sso/redirect' % BASE_URL, saml2.BINDING_HTTP_REDIRECT), ], }, - "name_id_format": [NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED], + 'name_id_format': [NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED], 'sign_response': True, 'sign_assertion': True, }, }, + 'metadata': { 'local': [os.path.join(os.path.join(os.path.join(BASE_DIR, 'idp'), 'saml2_config'), 'sp_metadata.xml')], }, # Signing - 'key_file': BASE_DIR + '/certificates/private_key.pem', # private part - 'cert_file': BASE_DIR + '/certificates/public_key.pem', # public part + 'key_file': BASE_DIR + '/certificates/private_key.pem', + 'cert_file': BASE_DIR + '/certificates/public_key.pem', # Encryption 'encryption_keypairs': [{ - 'key_file': BASE_DIR + '/certificates/private_key.pem', # private part - 'cert_file': BASE_DIR + '/certificates/public_key.pem', # public part + 'key_file': BASE_DIR + '/certificates/private_key.pem', + 'cert_file': BASE_DIR + '/certificates/public_key.pem', }], - "xmlsec_binary": get_xmlsec_binary(["/opt/local/bin", "/usr/bin/xmlsec1"]), - 'debug' : DEBUG, + 'valid_for': 365, } You also have to define a mapping for each SP you talk to:: - SAML_IDP_ACS_ATTRIBUTE_MAPPING = { - "http://localhost:8000/saml2/metadata/": { - # Map Django user attributes to output SAML attributes + SAML_IDP_ATTRIBUTE_MAPPING = { + 'http://localhost:8000/saml2/metadata/': { + # DJANGO: SAML 'email': 'email', 'first_name': 'first_name', 'last_name': 'last_name', diff --git a/djangosaml2idp/__init__.py b/djangosaml2idp/__init__.py index 39fea26..737d2bc 100644 --- a/djangosaml2idp/__init__.py +++ b/djangosaml2idp/__init__.py @@ -1,4 +1,4 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals -__version__ = '0.2.0' \ No newline at end of file +__version__ = '0.2.1' \ No newline at end of file diff --git a/djangosaml2idp/identity.py b/djangosaml2idp/identity.py new file mode 100644 index 0000000..bd1aed2 --- /dev/null +++ b/djangosaml2idp/identity.py @@ -0,0 +1,6 @@ +def create_identity(user, sp_mapping): + identity = {} + for user_attr, out_attr in sp_mapping.items(): + if hasattr(user, user_attr): + identity[out_attr] = getattr(user, user_attr) + return identity diff --git a/djangosaml2idp/templates/djangosaml2idp/login.html b/djangosaml2idp/templates/djangosaml2idp/login.html index 98c6d36..64bcd79 100644 --- a/djangosaml2idp/templates/djangosaml2idp/login.html +++ b/djangosaml2idp/templates/djangosaml2idp/login.html @@ -7,7 +7,5 @@ - {% if autosubmit %} - {% endif %} diff --git a/djangosaml2idp/views.py b/djangosaml2idp/views.py index 9d5e91e..2e40612 100644 --- a/djangosaml2idp/views.py +++ b/djangosaml2idp/views.py @@ -21,38 +21,35 @@ from saml2.server import Server from six import text_type +from .identity import create_identity + logger = logging.getLogger(__name__) + @csrf_exempt def sso_entry(request): + """ Entrypoint view for SSO. Gathers the parameters from the HTTP request, stores them in the session + and redirects the requester to the login_process view. + """ passed_data = request.POST if request.method == 'POST' else request.GET try: request.session['SAMLRequest'] = passed_data['SAMLRequest'] except (KeyError, MultiValueDictKeyError) as e: return HttpResponseBadRequest(e) request.session['RelayState'] = passed_data.get('RelayState', '') - # For HTTP-REDIRECT endpoint + # TODO check how the redirect saml way works. Taken from example idp in pysaml2. if "SigAlg" in passed_data and "Signature" in passed_data: request.session['SigAlg'] = passed_data['SigAlg'] request.session['Signature'] = passed_data['Signature'] return HttpResponseRedirect(reverse('saml_login_process')) -def create_identity(user, sp_mapping): - identity = {} - for user_attr, out_attr in sp_mapping.items(): - if hasattr(user, user_attr): - identity[out_attr] = getattr(user, user_attr) - return identity - - # TODO Add http redirect logic based on https://github.com/rohe/pysaml2/blob/master/example/idp2_repoze/idp.py#L327 @login_required def login_process(request): - """ - Processor-based login continuation. - Presents a SAML 2.0 Assertion for POSTing back to the Service Provider. + """ View which processes the actual SAML request and returns a self-submitting form with the SAML response. + The login_required decorator ensures the user authenticates first on the IdP using 'normal' ways. """ # Construct server with config from settings dict conf = IdPConfig() @@ -61,13 +58,12 @@ def login_process(request): # Parse incoming request try: req_info = IDP.parse_authn_request(request.session['SAMLRequest'], BINDING_HTTP_POST) - _authn_req = req_info.message except Exception as excp: return HttpResponseBadRequest(excp) - + # TODO this is taken from example, but no idea how this works or whats it does. Check SAML2 specification? # Signed request for HTTP-REDIRECT if "SigAlg" in request.session and "Signature" in request.session: - _certs = IDP.metadata.certs(_authn_req.issuer.text, "any", "signing") + _certs = IDP.metadata.certs(req_info.message.issuer.text, "any", "signing") verified_ok = False for cert in _certs: # TODO implement @@ -80,23 +76,24 @@ def login_process(request): binding_out, destination = IDP.pick_binding( service="assertion_consumer_service", - entity_id=_authn_req.issuer.text) + entity_id=req_info.message.issuer.text) # Gather response arguments try: - resp_args = IDP.response_args(_authn_req) + resp_args = IDP.response_args(req_info.message) except (UnknownPrincipal, UnsupportedBinding) as excp: return HttpResponseServerError(excp) # Create Identity dict (SP-specific) + # TODO abstract somewhat, make pluggable/configurable try: - sp_mapping = settings.SAML_IDP_ACS_ATTRIBUTE_MAPPING.get(resp_args['sp_entity_id'], {'username': 'username'}) + sp_mapping = settings.SAML_IDP_ATTRIBUTE_MAPPING.get(resp_args['sp_entity_id'], {'username': 'username'}) except AttributeError: - identity = {'username': 'username'} + sp_mapping = {'username': 'username'} identity = create_identity(request.user, sp_mapping) - # TODO investigate how this works, because I don't get it - req_authn_context = _authn_req.requested_authn_context or PASSWORD + # TODO investigate how this works, because I don't get it. Specification? + req_authn_context = req_info.message.requested_authn_context or PASSWORD AUTHN_BROKER = AuthnBroker() AUTHN_BROKER.add(authn_context_class_ref(req_authn_context), "") @@ -123,7 +120,8 @@ def login_process(request): def metadata(request): - """Returns an XML with the SAML 2.0 metadata for this Idp as configured in the settings.py file. + """ Returns an XML with the SAML 2.0 metadata for this Idp. + The metadata is constructed on-the-fly based on the config dict in the django settings. """ conf = IdPConfig() conf.load(copy.deepcopy(settings.SAML_IDP_CONFIG)) diff --git a/docs/example_setup/README.rst b/docs/example_setup/README.rst new file mode 100644 index 0000000..173e74e --- /dev/null +++ b/docs/example_setup/README.rst @@ -0,0 +1,36 @@ +Example SP/IdP implementation +============================= + +This is a barebone example implementation of a setup with a Service Provider and Identity Provider. +The SP is implemented using djangosaml2, the IdP using djangosaml2idp. +Both are default django projects with only the bare minimum of added code for a functional demo or start. +This to keep it clear and obvious how to implement the SP/IdP functionality without other clutter serving as distraction. + +A docker-compose_ file is included, providing a minimum-entry-barrier setup to get up and running, without complicated & error-prone setup requirements. +The example will run equally on Mac/Windows/Linux using docker. + +.. _docker-compose: https://docs.docker.com/compose/ + +How to run +---------- + +Go to this folder in a terminal and start the containers:: + + docker-compose up -d + +Give it a minute the first time to download and build the required images. They'll be cached for the successive runs. +You now have a SP running at http://localhost:8000/ and a IdP at http://localhost:9000/ (you can check with :code:`docker-compose ps`), configured to talk with each other. +In order to do some login, you will need to create a user account on the IdP:: + + docker exec -it djangosaml2idp_idp python manage.py createsuperuser + +Now go to the SP in your browser. The page shows you're not logged in; click on the link to login. You'll get redirected to the IdP which +shows a basic login form. Enter the credentials from the user you just created. You will then get redirected back to the SP, showing you are logged in with the user information. +And that is essentially what SAML2 does :) + +Cleanup +------- + +To stop the containers:: + + docker-compose stop \ No newline at end of file diff --git a/docs/index.rst b/docs/index.rst index 6e41a7c..0ca8911 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -11,6 +11,11 @@ djangosaml2idp :target: https://travis-ci.org/mhindery/djangosaml2idp :alt: Travis CI +.. image:: https://readthedocs.org/projects/djangosaml2idp/badge/?version=latest + :alt: Documentation Status + :scale: 100% + :target: https://djangosaml2idp.readthedocs.io/en/latest/?badge=latest + .. image:: https://landscape.io/github/mhindery/djangosaml2idp/master/landscape.svg?style=flat :target: https://landscape.io/github/mhindery/djangosaml2idp/master :alt: Code Health @@ -29,114 +34,15 @@ It builds on top of PySAML2_, is compatible with Python 2/3 and all current supp .. _PySAML2: https://github.com/rohe/pysaml2/ -Installation ------------- - -PySAML2 uses xmlsec1_ binary to sign SAML assertions so you need to install -it either through your operating system package or by compiling the source -code. It doesn't matter where the final executable is installed because -you will need to set the full path to it in the configuration stage. -``xmlsec`` is available (at least) for Debian, OSX and Alpine Linux. - -.. _xmlsec1: http://www.aleksey.com/xmlsec/ - -Now you can install the djangosaml2idp package using pip. This -will also install PySAML2 and its dependencies automatically:: - - pip install djangosaml2idp - - -Configuration & Usage ---------------------- -The first thing you need to do is add ``djangosaml2idp`` to the list of installed apps:: - - INSTALLED_APPS = ( - 'django.contrib.admin', - 'djangosaml2idp', - ... - ) - -Now include ``djangosaml2idp`` in your project by adding it in the url config:: - - from django.conf.urls import url, include - from django.contrib import admin - - urlpatterns = [ - url(r'^idp/', include('djangosaml2idp.urls')), - url(r'^admin/', admin.site.urls), - ... - ] - -In your Django settings, configure your IdP. Configuration follows the pysaml2_configuration_. The IdP from the example project looks like this:: - - ... - import saml2 - from saml2.saml import NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED - from saml2.sigver import get_xmlsec_binary - - BASE_URL = "http://localhost:9000/idp" - - SAML_IDP_CONFIG = { - "entityid": "%s/metadata" % BASE_URL, - "description": "Example IdP setup", - "valid_for": 168, - "service": { - "idp": { - "name": "Django localhost IdP", - "endpoints": { - "single_sign_on_service": [ - ("%s/sso/post" % BASE_URL, saml2.BINDING_HTTP_POST), - ("%s/sso/redirect" % BASE_URL, saml2.BINDING_HTTP_REDIRECT), - ], - }, - "name_id_format": [NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED], - 'sign_response': True, - 'sign_assertion': True, - }, - }, - 'metadata': { - 'local': [os.path.join(os.path.join(os.path.join(BASE_DIR, 'idp'), 'saml2_config'), 'sp_metadata.xml')], - }, - # Signing - 'key_file': BASE_DIR + '/certificates/private_key.pem', # private part - 'cert_file': BASE_DIR + '/certificates/public_key.pem', # public part - # Encryption - 'encryption_keypairs': [{ - 'key_file': BASE_DIR + '/certificates/private_key.pem', # private part - 'cert_file': BASE_DIR + '/certificates/public_key.pem', # public part - }], - "xmlsec_binary": get_xmlsec_binary(["/opt/local/bin", "/usr/bin/xmlsec1"]), - 'debug' : DEBUG, - } - -You also have to define a mapping for each SP you talk to:: - - SAML_IDP_ACS_ATTRIBUTE_MAPPING = { - "http://localhost:8000/saml2/metadata/": { - # Map Django user attributes to output SAML attributes - 'email': 'email', - 'first_name': 'first_name', - 'last_name': 'last_name', - 'is_staff': 'is_staff', - 'is_superuser': 'is_superuser', - } - } - -That's all for the IdP configuration. Assuming you run the Django development server on localhost:8000, you can get its metadata by visiting http://localhost:8000/idp/metadata/. -Use this metadata xml to configure your SP. Place the metadata xml from that SP in the location specified in the config dict (sp_metadata.xml in the example above). - -.. _pysaml2_configuration: https://github.com/rohe/pysaml2/blob/master/doc/howto/config.rst - -Example project ---------------- -``example_project`` contains a barebone demo setup. -It consists of a Service Provider implemented with ``djangosaml2`` and an Identity Provider using ``djangosaml2idp``. - +Table of contents +================== .. toctree:: :maxdepth: 2 :caption: Contents: + installation + example_setup/README Indices and tables diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..14a76e1 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,101 @@ +Installation +============ + +PySAML2 uses xmlsec1_ binary to sign SAML assertions so you need to install +it either through your operating system package or by compiling the source +code. It doesn't matter where the final executable is installed because +you will need to set the full path to it in the configuration stage. +xmlsec is available (at least) for Debian, OSX and Alpine Linux. + +.. _xmlsec1: http://www.aleksey.com/xmlsec/ + +Now you can install the djangosaml2idp package using pip. This +will also install PySAML2 and its dependencies automatically:: + + pip install djangosaml2idp + + +Configuration & Usage +--------------------- +The first thing you need to do is add ``djangosaml2idp`` to the list of installed apps:: + + INSTALLED_APPS = ( + 'django.contrib.admin', + 'djangosaml2idp', + ... + ) + +Now include ``djangosaml2idp`` in your project by adding it in the url config:: + + from django.conf.urls import url, include + from django.contrib import admin + + urlpatterns = [ + url(r'^idp/', include('djangosaml2idp.urls')), + url(r'^admin/', admin.site.urls), + ... + ] + +In your Django settings, configure your IdP. Configuration follows the pysaml2_configuration_. The IdP from the example project looks like this:: + + ... + import saml2 + from saml2.saml import NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED + from saml2.sigver import get_xmlsec_binary + + LOGIN_URL = '/login/' + BASE_URL = 'http://localhost:9000/idp' + + SAML_IDP_CONFIG = { + 'debug' : DEBUG, + 'xmlsec_binary': get_xmlsec_binary(['/opt/local/bin', '/usr/bin/xmlsec1']), + 'entityid': '%s/metadata' % BASE_URL, + 'description': 'Example IdP setup', + + 'service': { + 'idp': { + 'name': 'Django localhost IdP', + 'endpoints': { + 'single_sign_on_service': [ + ('%s/sso/post' % BASE_URL, saml2.BINDING_HTTP_POST), + ('%s/sso/redirect' % BASE_URL, saml2.BINDING_HTTP_REDIRECT), + ], + }, + 'name_id_format': [NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED], + 'sign_response': True, + 'sign_assertion': True, + }, + }, + + 'metadata': { + 'local': [os.path.join(os.path.join(os.path.join(BASE_DIR, 'idp'), 'saml2_config'), 'sp_metadata.xml')], + }, + # Signing + 'key_file': BASE_DIR + '/certificates/private_key.pem', + 'cert_file': BASE_DIR + '/certificates/public_key.pem', + # Encryption + 'encryption_keypairs': [{ + 'key_file': BASE_DIR + '/certificates/private_key.pem', + 'cert_file': BASE_DIR + '/certificates/public_key.pem', + }], + 'valid_for': 365, + } + +You also have to define a mapping for each SP you talk to:: + + SAML_IDP_ATTRIBUTE_MAPPING = { + 'http://localhost:8000/saml2/metadata/': { + # DJANGO: SAML + 'email': 'email', + 'first_name': 'first_name', + 'last_name': 'last_name', + 'is_staff': 'is_staff', + 'is_superuser': 'is_superuser', + } + } + +That's all for the IdP configuration. Assuming you run the Django development server on localhost:8000, you can get its metadata by visiting http://localhost:8000/idp/metadata/. +Use this metadata xml to configure your SP. Place the metadata xml from that SP in the location specified in the config dict (sp_metadata.xml in the example above). + +.. _pysaml2_configuration: https://github.com/rohe/pysaml2/blob/master/doc/howto/config.rst + diff --git a/example_setup/README.rst b/example_setup/README.rst new file mode 100644 index 0000000..173e74e --- /dev/null +++ b/example_setup/README.rst @@ -0,0 +1,36 @@ +Example SP/IdP implementation +============================= + +This is a barebone example implementation of a setup with a Service Provider and Identity Provider. +The SP is implemented using djangosaml2, the IdP using djangosaml2idp. +Both are default django projects with only the bare minimum of added code for a functional demo or start. +This to keep it clear and obvious how to implement the SP/IdP functionality without other clutter serving as distraction. + +A docker-compose_ file is included, providing a minimum-entry-barrier setup to get up and running, without complicated & error-prone setup requirements. +The example will run equally on Mac/Windows/Linux using docker. + +.. _docker-compose: https://docs.docker.com/compose/ + +How to run +---------- + +Go to this folder in a terminal and start the containers:: + + docker-compose up -d + +Give it a minute the first time to download and build the required images. They'll be cached for the successive runs. +You now have a SP running at http://localhost:8000/ and a IdP at http://localhost:9000/ (you can check with :code:`docker-compose ps`), configured to talk with each other. +In order to do some login, you will need to create a user account on the IdP:: + + docker exec -it djangosaml2idp_idp python manage.py createsuperuser + +Now go to the SP in your browser. The page shows you're not logged in; click on the link to login. You'll get redirected to the IdP which +shows a basic login form. Enter the credentials from the user you just created. You will then get redirected back to the SP, showing you are logged in with the user information. +And that is essentially what SAML2 does :) + +Cleanup +------- + +To stop the containers:: + + docker-compose stop \ No newline at end of file diff --git a/example_setup/docker-compose.yml b/example_setup/docker-compose.yml index 307c07e..31cc098 100644 --- a/example_setup/docker-compose.yml +++ b/example_setup/docker-compose.yml @@ -3,7 +3,7 @@ version: '2' services: sp: restart: always - container_name: saml_sp + container_name: djangosaml2idp_sp build: sp stdin_open: true tty: true @@ -15,7 +15,7 @@ services: idp: restart: always - container_name: saml_idp + container_name: djangosaml2idp_idp build: idp stdin_open: true tty: true diff --git a/example_setup/idp/Dockerfile b/example_setup/idp/Dockerfile index 29ac90d..253ca16 100644 --- a/example_setup/idp/Dockerfile +++ b/example_setup/idp/Dockerfile @@ -1,19 +1,13 @@ FROM alpine:latest RUN apk add --update \ - python \ - python-dev \ - py-pip \ - build-base \ - openssl openssl-dev \ - git \ - libffi libffi-dev libxml2 libxml2-dev libxslt-dev libxslt \ - swig \ + python python-dev py-pip \ + build-base libffi-dev openssl-dev \ xmlsec \ && rm -rf /var/cache/apk/* ADD requirements.txt /tmp RUN pip install -r /tmp/requirements.txt -EXPOSE 8000 +EXPOSE 9000 CMD python manage.py migrate && python manage.py runserver 0.0.0.0:9000 \ No newline at end of file diff --git a/example_setup/idp/idp/saml2_config/sp_metadata.xml b/example_setup/idp/idp/saml2_config/sp_metadata.xml index db31b8a..e100174 100644 --- a/example_setup/idp/idp/saml2_config/sp_metadata.xml +++ b/example_setup/idp/idp/saml2_config/sp_metadata.xml @@ -1,46 +1,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - -MIIDCTCCAfGgAwIBAgIJAOEE5ViDK6CjMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV BAMMEHNwLmxvY2FsaG9zdC5jb20wHhcNMTcwMzExMTk0OTU2WhcNMTcwNDEwMTk0 OTU2WjAbMRkwFwYDVQQDDBBzcC5sb2NhbGhvc3QuY29tMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAvXUBWGKYoV6MR+RNqMuUBKLt/EsyYWAMckBH0dUK 5iqL4dTyYrLXUEkD3u44AldNL+8olnZCZIkkoPUiC2LwOqwdkFc5UQY2+NmBIC+g FMWkC8quTnw4elTUQmZlNv/dmOprU+Dze/yVLTh2EwW34JsxdtJNQNwEpb3SqErA DN5ExXw9ZgB3Yx225N9iMLBTn1EiyEeiJKYKbM96aiQyxAmVLYF/88c3n5Oatx/7 MDk4Fu2hKA2hZ8ZpwYGImAPZuVQx71yc3V2NzQWNkZvqa2RZXdEKk+HlAxg1/9SP wYvqlEz7LrYv8mAbF177JE5Sd0ImrtTqoj0TzyG8sULwVQIDAQABo1AwTjAdBgNV HQ4EFgQU9e+s8CKad94rVZZojYE5NpJqHzswHwYDVR0jBBgwFoAU9e+s8CKad94r VZZojYE5NpJqHzswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZrA9 sGQhbBAraMkGxQ2CqtK84ft+XV6KwQpLkdIT8xNutnTaD6i4CR+mfmMyQavnoW1U zUygG3MyRLlFKjulhj/jXjihynht9vjmT1lse7byMSnp2KZMkLNf5LWkI+5sJoSs Ob787SyQI6M4JOYaN3EnizIn5GDz7pV7W5OxPpsRF6YqeWNr6thOFfYpbwreBlKg mUefAh/+mH89ZcSqGDkNazMD6QJJDOaxzJsr6njXTSrz2oRKQkGxgCVjx4zQIM8F ZYmN4j5W2qNoZQpstUVN5GIcM8IUz4trcSadq8OlxNpvna4mXcQfWYO3118PQOG+ bqzBEzkSE5eW8+vRkQ== - - - - - - - - -MIIDCTCCAfGgAwIBAgIJAOEE5ViDK6CjMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV BAMMEHNwLmxvY2FsaG9zdC5jb20wHhcNMTcwMzExMTk0OTU2WhcNMTcwNDEwMTk0 OTU2WjAbMRkwFwYDVQQDDBBzcC5sb2NhbGhvc3QuY29tMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAvXUBWGKYoV6MR+RNqMuUBKLt/EsyYWAMckBH0dUK 5iqL4dTyYrLXUEkD3u44AldNL+8olnZCZIkkoPUiC2LwOqwdkFc5UQY2+NmBIC+g FMWkC8quTnw4elTUQmZlNv/dmOprU+Dze/yVLTh2EwW34JsxdtJNQNwEpb3SqErA DN5ExXw9ZgB3Yx225N9iMLBTn1EiyEeiJKYKbM96aiQyxAmVLYF/88c3n5Oatx/7 MDk4Fu2hKA2hZ8ZpwYGImAPZuVQx71yc3V2NzQWNkZvqa2RZXdEKk+HlAxg1/9SP wYvqlEz7LrYv8mAbF177JE5Sd0ImrtTqoj0TzyG8sULwVQIDAQABo1AwTjAdBgNV HQ4EFgQU9e+s8CKad94rVZZojYE5NpJqHzswHwYDVR0jBBgwFoAU9e+s8CKad94r VZZojYE5NpJqHzswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZrA9 sGQhbBAraMkGxQ2CqtK84ft+XV6KwQpLkdIT8xNutnTaD6i4CR+mfmMyQavnoW1U zUygG3MyRLlFKjulhj/jXjihynht9vjmT1lse7byMSnp2KZMkLNf5LWkI+5sJoSs Ob787SyQI6M4JOYaN3EnizIn5GDz7pV7W5OxPpsRF6YqeWNr6thOFfYpbwreBlKg mUefAh/+mH89ZcSqGDkNazMD6QJJDOaxzJsr6njXTSrz2oRKQkGxgCVjx4zQIM8F ZYmN4j5W2qNoZQpstUVN5GIcM8IUz4trcSadq8OlxNpvna4mXcQfWYO3118PQOG+ bqzBEzkSE5eW8+vRkQ== - - - - - - - -urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress - - - + + + + + + + + + + + + + + + + + + + + + + + + MIIDCTCCAfGgAwIBAgIJAOEE5ViDK6CjMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV BAMMEHNwLmxvY2FsaG9zdC5jb20wHhcNMTcwMzExMTk0OTU2WhcNMTcwNDEwMTk0 OTU2WjAbMRkwFwYDVQQDDBBzcC5sb2NhbGhvc3QuY29tMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAvXUBWGKYoV6MR+RNqMuUBKLt/EsyYWAMckBH0dUK 5iqL4dTyYrLXUEkD3u44AldNL+8olnZCZIkkoPUiC2LwOqwdkFc5UQY2+NmBIC+g FMWkC8quTnw4elTUQmZlNv/dmOprU+Dze/yVLTh2EwW34JsxdtJNQNwEpb3SqErA DN5ExXw9ZgB3Yx225N9iMLBTn1EiyEeiJKYKbM96aiQyxAmVLYF/88c3n5Oatx/7 MDk4Fu2hKA2hZ8ZpwYGImAPZuVQx71yc3V2NzQWNkZvqa2RZXdEKk+HlAxg1/9SP wYvqlEz7LrYv8mAbF177JE5Sd0ImrtTqoj0TzyG8sULwVQIDAQABo1AwTjAdBgNV HQ4EFgQU9e+s8CKad94rVZZojYE5NpJqHzswHwYDVR0jBBgwFoAU9e+s8CKad94r VZZojYE5NpJqHzswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZrA9 sGQhbBAraMkGxQ2CqtK84ft+XV6KwQpLkdIT8xNutnTaD6i4CR+mfmMyQavnoW1U zUygG3MyRLlFKjulhj/jXjihynht9vjmT1lse7byMSnp2KZMkLNf5LWkI+5sJoSs Ob787SyQI6M4JOYaN3EnizIn5GDz7pV7W5OxPpsRF6YqeWNr6thOFfYpbwreBlKg mUefAh/+mH89ZcSqGDkNazMD6QJJDOaxzJsr6njXTSrz2oRKQkGxgCVjx4zQIM8F ZYmN4j5W2qNoZQpstUVN5GIcM8IUz4trcSadq8OlxNpvna4mXcQfWYO3118PQOG+ bqzBEzkSE5eW8+vRkQ== + + + + + + + MIIDCTCCAfGgAwIBAgIJAOEE5ViDK6CjMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV BAMMEHNwLmxvY2FsaG9zdC5jb20wHhcNMTcwMzExMTk0OTU2WhcNMTcwNDEwMTk0 OTU2WjAbMRkwFwYDVQQDDBBzcC5sb2NhbGhvc3QuY29tMIIBIjANBgkqhkiG9w0B AQEFAAOCAQ8AMIIBCgKCAQEAvXUBWGKYoV6MR+RNqMuUBKLt/EsyYWAMckBH0dUK 5iqL4dTyYrLXUEkD3u44AldNL+8olnZCZIkkoPUiC2LwOqwdkFc5UQY2+NmBIC+g FMWkC8quTnw4elTUQmZlNv/dmOprU+Dze/yVLTh2EwW34JsxdtJNQNwEpb3SqErA DN5ExXw9ZgB3Yx225N9iMLBTn1EiyEeiJKYKbM96aiQyxAmVLYF/88c3n5Oatx/7 MDk4Fu2hKA2hZ8ZpwYGImAPZuVQx71yc3V2NzQWNkZvqa2RZXdEKk+HlAxg1/9SP wYvqlEz7LrYv8mAbF177JE5Sd0ImrtTqoj0TzyG8sULwVQIDAQABo1AwTjAdBgNV HQ4EFgQU9e+s8CKad94rVZZojYE5NpJqHzswHwYDVR0jBBgwFoAU9e+s8CKad94r VZZojYE5NpJqHzswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAZrA9 sGQhbBAraMkGxQ2CqtK84ft+XV6KwQpLkdIT8xNutnTaD6i4CR+mfmMyQavnoW1U zUygG3MyRLlFKjulhj/jXjihynht9vjmT1lse7byMSnp2KZMkLNf5LWkI+5sJoSs Ob787SyQI6M4JOYaN3EnizIn5GDz7pV7W5OxPpsRF6YqeWNr6thOFfYpbwreBlKg mUefAh/+mH89ZcSqGDkNazMD6QJJDOaxzJsr6njXTSrz2oRKQkGxgCVjx4zQIM8F ZYmN4j5W2qNoZQpstUVN5GIcM8IUz4trcSadq8OlxNpvna4mXcQfWYO3118PQOG+ bqzBEzkSE5eW8+vRkQ== + + + + + + urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress + + \ No newline at end of file diff --git a/example_setup/idp/idp/settings.py b/example_setup/idp/idp/settings.py index ca01065..5a92725 100644 --- a/example_setup/idp/idp/settings.py +++ b/example_setup/idp/idp/settings.py @@ -1,4 +1,4 @@ -""" +''' Django settings for idp project. Generated by 'django-admin startproject' using Django 1.10.6. @@ -8,7 +8,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.10/ref/settings/ -""" +''' import os @@ -121,52 +121,54 @@ STATIC_URL = '/static/' -### Added settings -LOGIN_URL = '/login/' +### Everything above are default settings made by django-admin startproject +### The following is added for djangosaml2idp IdP configuration. import saml2 from saml2.saml import NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED from saml2.sigver import get_xmlsec_binary -BASE_URL = "http://localhost:9000/idp" +LOGIN_URL = '/login/' +BASE_URL = 'http://localhost:9000/idp' SAML_IDP_CONFIG = { - "entityid": "%s/metadata" % BASE_URL, - "description": "Example IdP setup", - "valid_for": 168, - "service": { - "idp": { - "name": "Django localhost IdP", - "endpoints": { - "single_sign_on_service": [ - ("%s/sso/post" % BASE_URL, saml2.BINDING_HTTP_POST), - ("%s/sso/redirect" % BASE_URL, saml2.BINDING_HTTP_REDIRECT), + 'debug' : DEBUG, + 'xmlsec_binary': get_xmlsec_binary(['/opt/local/bin', '/usr/bin/xmlsec1']), + 'entityid': '%s/metadata' % BASE_URL, + 'description': 'Example IdP setup', + + 'service': { + 'idp': { + 'name': 'Django localhost IdP', + 'endpoints': { + 'single_sign_on_service': [ + ('%s/sso/post' % BASE_URL, saml2.BINDING_HTTP_POST), + ('%s/sso/redirect' % BASE_URL, saml2.BINDING_HTTP_REDIRECT), ], }, - "name_id_format": [NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED], + 'name_id_format': [NAMEID_FORMAT_EMAILADDRESS, NAMEID_FORMAT_UNSPECIFIED], 'sign_response': True, 'sign_assertion': True, }, }, + 'metadata': { 'local': [os.path.join(os.path.join(os.path.join(BASE_DIR, 'idp'), 'saml2_config'), 'sp_metadata.xml')], }, # Signing - 'key_file': BASE_DIR + '/certificates/private_key.pem', # private part - 'cert_file': BASE_DIR + '/certificates/public_key.pem', # public part + 'key_file': BASE_DIR + '/certificates/private_key.pem', + 'cert_file': BASE_DIR + '/certificates/public_key.pem', # Encryption 'encryption_keypairs': [{ - 'key_file': BASE_DIR + '/certificates/private_key.pem', # private part - 'cert_file': BASE_DIR + '/certificates/public_key.pem', # public part + 'key_file': BASE_DIR + '/certificates/private_key.pem', + 'cert_file': BASE_DIR + '/certificates/public_key.pem', }], - "xmlsec_binary": get_xmlsec_binary(["/opt/local/bin", "/usr/bin/xmlsec1"]), - 'debug' : DEBUG, + 'valid_for': 365, } - -SAML_IDP_ACS_ATTRIBUTE_MAPPING = { - "http://localhost:8000/saml2/metadata/": { - # Map Django user attributes to output SAML attributes +SAML_IDP_ATTRIBUTE_MAPPING = { + 'http://localhost:8000/saml2/metadata/': { + # DJANGO: SAML 'email': 'email', 'first_name': 'first_name', 'last_name': 'last_name', diff --git a/example_setup/idp/idp/templates/idp/login.html b/example_setup/idp/idp/templates/idp/login.html index 6174797..daa4ef2 100644 --- a/example_setup/idp/idp/templates/idp/login.html +++ b/example_setup/idp/idp/templates/idp/login.html @@ -1,8 +1,6 @@
-{% csrf_token %} - -{{ form }} -
- - + {% csrf_token %} + {{ form.as_table }} + +
\ No newline at end of file diff --git a/example_setup/sp/Dockerfile b/example_setup/sp/Dockerfile index c47bce7..b143fd9 100644 --- a/example_setup/sp/Dockerfile +++ b/example_setup/sp/Dockerfile @@ -1,14 +1,8 @@ FROM alpine:latest RUN apk add --update \ - python \ - python-dev \ - py-pip \ - build-base \ - openssl openssl-dev \ - git \ - libffi libffi-dev libxml2 libxml2-dev libxslt-dev libxslt \ - swig \ + python python-dev py-pip \ + build-base libffi-dev openssl-dev \ xmlsec \ && rm -rf /var/cache/apk/* diff --git a/example_setup/sp/sp/saml2_config/attribute-maps/__init__.py b/example_setup/sp/sp/saml2_config/attribute-maps/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/example_setup/sp/sp/saml2_config/attribute-maps/basic.py b/example_setup/sp/sp/saml2_config/attribute-maps/basic.py new file mode 100644 index 0000000..5060140 --- /dev/null +++ b/example_setup/sp/sp/saml2_config/attribute-maps/basic.py @@ -0,0 +1,325 @@ +MAP = { + "identifier": "urn:oasis:names:tc:SAML:2.0:attrname-format:basic", + "fro": { + 'urn:mace:dir:attribute-def:aRecord': 'aRecord', + 'urn:mace:dir:attribute-def:aliasedEntryName': 'aliasedEntryName', + 'urn:mace:dir:attribute-def:aliasedObjectName': 'aliasedObjectName', + 'urn:mace:dir:attribute-def:associatedDomain': 'associatedDomain', + 'urn:mace:dir:attribute-def:associatedName': 'associatedName', + 'urn:mace:dir:attribute-def:audio': 'audio', + 'urn:mace:dir:attribute-def:authorityRevocationList': 'authorityRevocationList', + 'urn:mace:dir:attribute-def:buildingName': 'buildingName', + 'urn:mace:dir:attribute-def:businessCategory': 'businessCategory', + 'urn:mace:dir:attribute-def:c': 'c', + 'urn:mace:dir:attribute-def:cACertificate': 'cACertificate', + 'urn:mace:dir:attribute-def:cNAMERecord': 'cNAMERecord', + 'urn:mace:dir:attribute-def:carLicense': 'carLicense', + 'urn:mace:dir:attribute-def:certificateRevocationList': 'certificateRevocationList', + 'urn:mace:dir:attribute-def:cn': 'cn', + 'urn:mace:dir:attribute-def:co': 'co', + 'urn:mace:dir:attribute-def:commonName': 'commonName', + 'urn:mace:dir:attribute-def:countryName': 'countryName', + 'urn:mace:dir:attribute-def:crossCertificatePair': 'crossCertificatePair', + 'urn:mace:dir:attribute-def:dITRedirect': 'dITRedirect', + 'urn:mace:dir:attribute-def:dSAQuality': 'dSAQuality', + 'urn:mace:dir:attribute-def:dc': 'dc', + 'urn:mace:dir:attribute-def:deltaRevocationList': 'deltaRevocationList', + 'urn:mace:dir:attribute-def:departmentNumber': 'departmentNumber', + 'urn:mace:dir:attribute-def:description': 'description', + 'urn:mace:dir:attribute-def:destinationIndicator': 'destinationIndicator', + 'urn:mace:dir:attribute-def:displayName': 'displayName', + 'urn:mace:dir:attribute-def:distinguishedName': 'distinguishedName', + 'urn:mace:dir:attribute-def:dmdName': 'dmdName', + 'urn:mace:dir:attribute-def:dnQualifier': 'dnQualifier', + 'urn:mace:dir:attribute-def:documentAuthor': 'documentAuthor', + 'urn:mace:dir:attribute-def:documentIdentifier': 'documentIdentifier', + 'urn:mace:dir:attribute-def:documentLocation': 'documentLocation', + 'urn:mace:dir:attribute-def:documentPublisher': 'documentPublisher', + 'urn:mace:dir:attribute-def:documentTitle': 'documentTitle', + 'urn:mace:dir:attribute-def:documentVersion': 'documentVersion', + 'urn:mace:dir:attribute-def:domainComponent': 'domainComponent', + 'urn:mace:dir:attribute-def:drink': 'drink', + 'urn:mace:dir:attribute-def:eduOrgHomePageURI': 'eduOrgHomePageURI', + 'urn:mace:dir:attribute-def:eduOrgIdentityAuthNPolicyURI': 'eduOrgIdentityAuthNPolicyURI', + 'urn:mace:dir:attribute-def:eduOrgLegalName': 'eduOrgLegalName', + 'urn:mace:dir:attribute-def:eduOrgSuperiorURI': 'eduOrgSuperiorURI', + 'urn:mace:dir:attribute-def:eduOrgWhitePagesURI': 'eduOrgWhitePagesURI', + 'urn:mace:dir:attribute-def:eduPersonAffiliation': 'eduPersonAffiliation', + 'urn:mace:dir:attribute-def:eduPersonEntitlement': 'eduPersonEntitlement', + 'urn:mace:dir:attribute-def:eduPersonNickname': 'eduPersonNickname', + 'urn:mace:dir:attribute-def:eduPersonOrgDN': 'eduPersonOrgDN', + 'urn:mace:dir:attribute-def:eduPersonOrgUnitDN': 'eduPersonOrgUnitDN', + 'urn:mace:dir:attribute-def:eduPersonPrimaryAffiliation': 'eduPersonPrimaryAffiliation', + 'urn:mace:dir:attribute-def:eduPersonPrimaryOrgUnitDN': 'eduPersonPrimaryOrgUnitDN', + 'urn:mace:dir:attribute-def:eduPersonPrincipalName': 'eduPersonPrincipalName', + 'urn:mace:dir:attribute-def:eduPersonScopedAffiliation': 'eduPersonScopedAffiliation', + 'urn:mace:dir:attribute-def:eduPersonTargetedID': 'eduPersonTargetedID', + 'urn:mace:dir:attribute-def:email': 'email', + 'urn:mace:dir:attribute-def:emailAddress': 'emailAddress', + 'urn:mace:dir:attribute-def:employeeNumber': 'employeeNumber', + 'urn:mace:dir:attribute-def:employeeType': 'employeeType', + 'urn:mace:dir:attribute-def:enhancedSearchGuide': 'enhancedSearchGuide', + 'urn:mace:dir:attribute-def:facsimileTelephoneNumber': 'facsimileTelephoneNumber', + 'urn:mace:dir:attribute-def:favouriteDrink': 'favouriteDrink', + 'urn:mace:dir:attribute-def:fax': 'fax', + 'urn:mace:dir:attribute-def:federationFeideSchemaVersion': 'federationFeideSchemaVersion', + 'urn:mace:dir:attribute-def:friendlyCountryName': 'friendlyCountryName', + 'urn:mace:dir:attribute-def:generationQualifier': 'generationQualifier', + 'urn:mace:dir:attribute-def:givenName': 'givenName', + 'urn:mace:dir:attribute-def:gn': 'gn', + 'urn:mace:dir:attribute-def:homePhone': 'homePhone', + 'urn:mace:dir:attribute-def:homePostalAddress': 'homePostalAddress', + 'urn:mace:dir:attribute-def:homeTelephoneNumber': 'homeTelephoneNumber', + 'urn:mace:dir:attribute-def:host': 'host', + 'urn:mace:dir:attribute-def:houseIdentifier': 'houseIdentifier', + 'urn:mace:dir:attribute-def:info': 'info', + 'urn:mace:dir:attribute-def:initials': 'initials', + 'urn:mace:dir:attribute-def:internationaliSDNNumber': 'internationaliSDNNumber', + 'urn:mace:dir:attribute-def:janetMailbox': 'janetMailbox', + 'urn:mace:dir:attribute-def:jpegPhoto': 'jpegPhoto', + 'urn:mace:dir:attribute-def:knowledgeInformation': 'knowledgeInformation', + 'urn:mace:dir:attribute-def:l': 'l', + 'urn:mace:dir:attribute-def:labeledURI': 'labeledURI', + 'urn:mace:dir:attribute-def:localityName': 'localityName', + 'urn:mace:dir:attribute-def:mDRecord': 'mDRecord', + 'urn:mace:dir:attribute-def:mXRecord': 'mXRecord', + 'urn:mace:dir:attribute-def:mail': 'mail', + 'urn:mace:dir:attribute-def:mailPreferenceOption': 'mailPreferenceOption', + 'urn:mace:dir:attribute-def:manager': 'manager', + 'urn:mace:dir:attribute-def:member': 'member', + 'urn:mace:dir:attribute-def:mobile': 'mobile', + 'urn:mace:dir:attribute-def:mobileTelephoneNumber': 'mobileTelephoneNumber', + 'urn:mace:dir:attribute-def:nSRecord': 'nSRecord', + 'urn:mace:dir:attribute-def:name': 'name', + 'urn:mace:dir:attribute-def:norEduOrgAcronym': 'norEduOrgAcronym', + 'urn:mace:dir:attribute-def:norEduOrgNIN': 'norEduOrgNIN', + 'urn:mace:dir:attribute-def:norEduOrgSchemaVersion': 'norEduOrgSchemaVersion', + 'urn:mace:dir:attribute-def:norEduOrgUniqueIdentifier': 'norEduOrgUniqueIdentifier', + 'urn:mace:dir:attribute-def:norEduOrgUniqueNumber': 'norEduOrgUniqueNumber', + 'urn:mace:dir:attribute-def:norEduOrgUnitUniqueIdentifier': 'norEduOrgUnitUniqueIdentifier', + 'urn:mace:dir:attribute-def:norEduOrgUnitUniqueNumber': 'norEduOrgUnitUniqueNumber', + 'urn:mace:dir:attribute-def:norEduPersonBirthDate': 'norEduPersonBirthDate', + 'urn:mace:dir:attribute-def:norEduPersonLIN': 'norEduPersonLIN', + 'urn:mace:dir:attribute-def:norEduPersonNIN': 'norEduPersonNIN', + 'urn:mace:dir:attribute-def:o': 'o', + 'urn:mace:dir:attribute-def:objectClass': 'objectClass', + 'urn:mace:dir:attribute-def:organizationName': 'organizationName', + 'urn:mace:dir:attribute-def:organizationalStatus': 'organizationalStatus', + 'urn:mace:dir:attribute-def:organizationalUnitName': 'organizationalUnitName', + 'urn:mace:dir:attribute-def:otherMailbox': 'otherMailbox', + 'urn:mace:dir:attribute-def:ou': 'ou', + 'urn:mace:dir:attribute-def:owner': 'owner', + 'urn:mace:dir:attribute-def:pager': 'pager', + 'urn:mace:dir:attribute-def:pagerTelephoneNumber': 'pagerTelephoneNumber', + 'urn:mace:dir:attribute-def:personalSignature': 'personalSignature', + 'urn:mace:dir:attribute-def:personalTitle': 'personalTitle', + 'urn:mace:dir:attribute-def:photo': 'photo', + 'urn:mace:dir:attribute-def:physicalDeliveryOfficeName': 'physicalDeliveryOfficeName', + 'urn:mace:dir:attribute-def:pkcs9email': 'pkcs9email', + 'urn:mace:dir:attribute-def:postOfficeBox': 'postOfficeBox', + 'urn:mace:dir:attribute-def:postalAddress': 'postalAddress', + 'urn:mace:dir:attribute-def:postalCode': 'postalCode', + 'urn:mace:dir:attribute-def:preferredDeliveryMethod': 'preferredDeliveryMethod', + 'urn:mace:dir:attribute-def:preferredLanguage': 'preferredLanguage', + 'urn:mace:dir:attribute-def:presentationAddress': 'presentationAddress', + 'urn:mace:dir:attribute-def:protocolInformation': 'protocolInformation', + 'urn:mace:dir:attribute-def:pseudonym': 'pseudonym', + 'urn:mace:dir:attribute-def:registeredAddress': 'registeredAddress', + 'urn:mace:dir:attribute-def:rfc822Mailbox': 'rfc822Mailbox', + 'urn:mace:dir:attribute-def:roleOccupant': 'roleOccupant', + 'urn:mace:dir:attribute-def:roomNumber': 'roomNumber', + 'urn:mace:dir:attribute-def:sOARecord': 'sOARecord', + 'urn:mace:dir:attribute-def:searchGuide': 'searchGuide', + 'urn:mace:dir:attribute-def:secretary': 'secretary', + 'urn:mace:dir:attribute-def:seeAlso': 'seeAlso', + 'urn:mace:dir:attribute-def:serialNumber': 'serialNumber', + 'urn:mace:dir:attribute-def:singleLevelQuality': 'singleLevelQuality', + 'urn:mace:dir:attribute-def:sn': 'sn', + 'urn:mace:dir:attribute-def:st': 'st', + 'urn:mace:dir:attribute-def:stateOrProvinceName': 'stateOrProvinceName', + 'urn:mace:dir:attribute-def:street': 'street', + 'urn:mace:dir:attribute-def:streetAddress': 'streetAddress', + 'urn:mace:dir:attribute-def:subtreeMaximumQuality': 'subtreeMaximumQuality', + 'urn:mace:dir:attribute-def:subtreeMinimumQuality': 'subtreeMinimumQuality', + 'urn:mace:dir:attribute-def:supportedAlgorithms': 'supportedAlgorithms', + 'urn:mace:dir:attribute-def:supportedApplicationContext': 'supportedApplicationContext', + 'urn:mace:dir:attribute-def:surname': 'surname', + 'urn:mace:dir:attribute-def:telephoneNumber': 'telephoneNumber', + 'urn:mace:dir:attribute-def:teletexTerminalIdentifier': 'teletexTerminalIdentifier', + 'urn:mace:dir:attribute-def:telexNumber': 'telexNumber', + 'urn:mace:dir:attribute-def:textEncodedORAddress': 'textEncodedORAddress', + 'urn:mace:dir:attribute-def:title': 'title', + 'urn:mace:dir:attribute-def:uid': 'uid', + 'urn:mace:dir:attribute-def:uniqueIdentifier': 'uniqueIdentifier', + 'urn:mace:dir:attribute-def:uniqueMember': 'uniqueMember', + 'urn:mace:dir:attribute-def:userCertificate': 'userCertificate', + 'urn:mace:dir:attribute-def:userClass': 'userClass', + 'urn:mace:dir:attribute-def:userPKCS12': 'userPKCS12', + 'urn:mace:dir:attribute-def:userPassword': 'userPassword', + 'urn:mace:dir:attribute-def:userSMIMECertificate': 'userSMIMECertificate', + 'urn:mace:dir:attribute-def:userid': 'userid', + 'urn:mace:dir:attribute-def:x121Address': 'x121Address', + 'urn:mace:dir:attribute-def:x500UniqueIdentifier': 'x500UniqueIdentifier', + }, + "to": { + 'aRecord': 'urn:mace:dir:attribute-def:aRecord', + 'aliasedEntryName': 'urn:mace:dir:attribute-def:aliasedEntryName', + 'aliasedObjectName': 'urn:mace:dir:attribute-def:aliasedObjectName', + 'associatedDomain': 'urn:mace:dir:attribute-def:associatedDomain', + 'associatedName': 'urn:mace:dir:attribute-def:associatedName', + 'audio': 'urn:mace:dir:attribute-def:audio', + 'authorityRevocationList': 'urn:mace:dir:attribute-def:authorityRevocationList', + 'buildingName': 'urn:mace:dir:attribute-def:buildingName', + 'businessCategory': 'urn:mace:dir:attribute-def:businessCategory', + 'c': 'urn:mace:dir:attribute-def:c', + 'cACertificate': 'urn:mace:dir:attribute-def:cACertificate', + 'cNAMERecord': 'urn:mace:dir:attribute-def:cNAMERecord', + 'carLicense': 'urn:mace:dir:attribute-def:carLicense', + 'certificateRevocationList': 'urn:mace:dir:attribute-def:certificateRevocationList', + 'cn': 'urn:mace:dir:attribute-def:cn', + 'co': 'urn:mace:dir:attribute-def:co', + 'commonName': 'urn:mace:dir:attribute-def:commonName', + 'countryName': 'urn:mace:dir:attribute-def:countryName', + 'crossCertificatePair': 'urn:mace:dir:attribute-def:crossCertificatePair', + 'dITRedirect': 'urn:mace:dir:attribute-def:dITRedirect', + 'dSAQuality': 'urn:mace:dir:attribute-def:dSAQuality', + 'dc': 'urn:mace:dir:attribute-def:dc', + 'deltaRevocationList': 'urn:mace:dir:attribute-def:deltaRevocationList', + 'departmentNumber': 'urn:mace:dir:attribute-def:departmentNumber', + 'description': 'urn:mace:dir:attribute-def:description', + 'destinationIndicator': 'urn:mace:dir:attribute-def:destinationIndicator', + 'displayName': 'urn:mace:dir:attribute-def:displayName', + 'distinguishedName': 'urn:mace:dir:attribute-def:distinguishedName', + 'dmdName': 'urn:mace:dir:attribute-def:dmdName', + 'dnQualifier': 'urn:mace:dir:attribute-def:dnQualifier', + 'documentAuthor': 'urn:mace:dir:attribute-def:documentAuthor', + 'documentIdentifier': 'urn:mace:dir:attribute-def:documentIdentifier', + 'documentLocation': 'urn:mace:dir:attribute-def:documentLocation', + 'documentPublisher': 'urn:mace:dir:attribute-def:documentPublisher', + 'documentTitle': 'urn:mace:dir:attribute-def:documentTitle', + 'documentVersion': 'urn:mace:dir:attribute-def:documentVersion', + 'domainComponent': 'urn:mace:dir:attribute-def:domainComponent', + 'drink': 'urn:mace:dir:attribute-def:drink', + 'eduOrgHomePageURI': 'urn:mace:dir:attribute-def:eduOrgHomePageURI', + 'eduOrgIdentityAuthNPolicyURI': 'urn:mace:dir:attribute-def:eduOrgIdentityAuthNPolicyURI', + 'eduOrgLegalName': 'urn:mace:dir:attribute-def:eduOrgLegalName', + 'eduOrgSuperiorURI': 'urn:mace:dir:attribute-def:eduOrgSuperiorURI', + 'eduOrgWhitePagesURI': 'urn:mace:dir:attribute-def:eduOrgWhitePagesURI', + 'eduPersonAffiliation': 'urn:mace:dir:attribute-def:eduPersonAffiliation', + 'eduPersonEntitlement': 'urn:mace:dir:attribute-def:eduPersonEntitlement', + 'eduPersonNickname': 'urn:mace:dir:attribute-def:eduPersonNickname', + 'eduPersonOrgDN': 'urn:mace:dir:attribute-def:eduPersonOrgDN', + 'eduPersonOrgUnitDN': 'urn:mace:dir:attribute-def:eduPersonOrgUnitDN', + 'eduPersonPrimaryAffiliation': 'urn:mace:dir:attribute-def:eduPersonPrimaryAffiliation', + 'eduPersonPrimaryOrgUnitDN': 'urn:mace:dir:attribute-def:eduPersonPrimaryOrgUnitDN', + 'eduPersonPrincipalName': 'urn:mace:dir:attribute-def:eduPersonPrincipalName', + 'eduPersonScopedAffiliation': 'urn:mace:dir:attribute-def:eduPersonScopedAffiliation', + 'eduPersonTargetedID': 'urn:mace:dir:attribute-def:eduPersonTargetedID', + 'email': 'urn:mace:dir:attribute-def:email', + 'emailAddress': 'urn:mace:dir:attribute-def:emailAddress', + 'employeeNumber': 'urn:mace:dir:attribute-def:employeeNumber', + 'employeeType': 'urn:mace:dir:attribute-def:employeeType', + 'enhancedSearchGuide': 'urn:mace:dir:attribute-def:enhancedSearchGuide', + 'facsimileTelephoneNumber': 'urn:mace:dir:attribute-def:facsimileTelephoneNumber', + 'favouriteDrink': 'urn:mace:dir:attribute-def:favouriteDrink', + 'fax': 'urn:mace:dir:attribute-def:fax', + 'federationFeideSchemaVersion': 'urn:mace:dir:attribute-def:federationFeideSchemaVersion', + 'friendlyCountryName': 'urn:mace:dir:attribute-def:friendlyCountryName', + 'generationQualifier': 'urn:mace:dir:attribute-def:generationQualifier', + 'givenName': 'urn:mace:dir:attribute-def:givenName', + 'gn': 'urn:mace:dir:attribute-def:gn', + 'homePhone': 'urn:mace:dir:attribute-def:homePhone', + 'homePostalAddress': 'urn:mace:dir:attribute-def:homePostalAddress', + 'homeTelephoneNumber': 'urn:mace:dir:attribute-def:homeTelephoneNumber', + 'host': 'urn:mace:dir:attribute-def:host', + 'houseIdentifier': 'urn:mace:dir:attribute-def:houseIdentifier', + 'info': 'urn:mace:dir:attribute-def:info', + 'initials': 'urn:mace:dir:attribute-def:initials', + 'internationaliSDNNumber': 'urn:mace:dir:attribute-def:internationaliSDNNumber', + 'janetMailbox': 'urn:mace:dir:attribute-def:janetMailbox', + 'jpegPhoto': 'urn:mace:dir:attribute-def:jpegPhoto', + 'knowledgeInformation': 'urn:mace:dir:attribute-def:knowledgeInformation', + 'l': 'urn:mace:dir:attribute-def:l', + 'labeledURI': 'urn:mace:dir:attribute-def:labeledURI', + 'localityName': 'urn:mace:dir:attribute-def:localityName', + 'mDRecord': 'urn:mace:dir:attribute-def:mDRecord', + 'mXRecord': 'urn:mace:dir:attribute-def:mXRecord', + 'mail': 'urn:mace:dir:attribute-def:mail', + 'mailPreferenceOption': 'urn:mace:dir:attribute-def:mailPreferenceOption', + 'manager': 'urn:mace:dir:attribute-def:manager', + 'member': 'urn:mace:dir:attribute-def:member', + 'mobile': 'urn:mace:dir:attribute-def:mobile', + 'mobileTelephoneNumber': 'urn:mace:dir:attribute-def:mobileTelephoneNumber', + 'nSRecord': 'urn:mace:dir:attribute-def:nSRecord', + 'name': 'urn:mace:dir:attribute-def:name', + 'norEduOrgAcronym': 'urn:mace:dir:attribute-def:norEduOrgAcronym', + 'norEduOrgNIN': 'urn:mace:dir:attribute-def:norEduOrgNIN', + 'norEduOrgSchemaVersion': 'urn:mace:dir:attribute-def:norEduOrgSchemaVersion', + 'norEduOrgUniqueIdentifier': 'urn:mace:dir:attribute-def:norEduOrgUniqueIdentifier', + 'norEduOrgUniqueNumber': 'urn:mace:dir:attribute-def:norEduOrgUniqueNumber', + 'norEduOrgUnitUniqueIdentifier': 'urn:mace:dir:attribute-def:norEduOrgUnitUniqueIdentifier', + 'norEduOrgUnitUniqueNumber': 'urn:mace:dir:attribute-def:norEduOrgUnitUniqueNumber', + 'norEduPersonBirthDate': 'urn:mace:dir:attribute-def:norEduPersonBirthDate', + 'norEduPersonLIN': 'urn:mace:dir:attribute-def:norEduPersonLIN', + 'norEduPersonNIN': 'urn:mace:dir:attribute-def:norEduPersonNIN', + 'o': 'urn:mace:dir:attribute-def:o', + 'objectClass': 'urn:mace:dir:attribute-def:objectClass', + 'organizationName': 'urn:mace:dir:attribute-def:organizationName', + 'organizationalStatus': 'urn:mace:dir:attribute-def:organizationalStatus', + 'organizationalUnitName': 'urn:mace:dir:attribute-def:organizationalUnitName', + 'otherMailbox': 'urn:mace:dir:attribute-def:otherMailbox', + 'ou': 'urn:mace:dir:attribute-def:ou', + 'owner': 'urn:mace:dir:attribute-def:owner', + 'pager': 'urn:mace:dir:attribute-def:pager', + 'pagerTelephoneNumber': 'urn:mace:dir:attribute-def:pagerTelephoneNumber', + 'personalSignature': 'urn:mace:dir:attribute-def:personalSignature', + 'personalTitle': 'urn:mace:dir:attribute-def:personalTitle', + 'photo': 'urn:mace:dir:attribute-def:photo', + 'physicalDeliveryOfficeName': 'urn:mace:dir:attribute-def:physicalDeliveryOfficeName', + 'pkcs9email': 'urn:mace:dir:attribute-def:pkcs9email', + 'postOfficeBox': 'urn:mace:dir:attribute-def:postOfficeBox', + 'postalAddress': 'urn:mace:dir:attribute-def:postalAddress', + 'postalCode': 'urn:mace:dir:attribute-def:postalCode', + 'preferredDeliveryMethod': 'urn:mace:dir:attribute-def:preferredDeliveryMethod', + 'preferredLanguage': 'urn:mace:dir:attribute-def:preferredLanguage', + 'presentationAddress': 'urn:mace:dir:attribute-def:presentationAddress', + 'protocolInformation': 'urn:mace:dir:attribute-def:protocolInformation', + 'pseudonym': 'urn:mace:dir:attribute-def:pseudonym', + 'registeredAddress': 'urn:mace:dir:attribute-def:registeredAddress', + 'rfc822Mailbox': 'urn:mace:dir:attribute-def:rfc822Mailbox', + 'roleOccupant': 'urn:mace:dir:attribute-def:roleOccupant', + 'roomNumber': 'urn:mace:dir:attribute-def:roomNumber', + 'sOARecord': 'urn:mace:dir:attribute-def:sOARecord', + 'searchGuide': 'urn:mace:dir:attribute-def:searchGuide', + 'secretary': 'urn:mace:dir:attribute-def:secretary', + 'seeAlso': 'urn:mace:dir:attribute-def:seeAlso', + 'serialNumber': 'urn:mace:dir:attribute-def:serialNumber', + 'singleLevelQuality': 'urn:mace:dir:attribute-def:singleLevelQuality', + 'sn': 'urn:mace:dir:attribute-def:sn', + 'st': 'urn:mace:dir:attribute-def:st', + 'stateOrProvinceName': 'urn:mace:dir:attribute-def:stateOrProvinceName', + 'street': 'urn:mace:dir:attribute-def:street', + 'streetAddress': 'urn:mace:dir:attribute-def:streetAddress', + 'subtreeMaximumQuality': 'urn:mace:dir:attribute-def:subtreeMaximumQuality', + 'subtreeMinimumQuality': 'urn:mace:dir:attribute-def:subtreeMinimumQuality', + 'supportedAlgorithms': 'urn:mace:dir:attribute-def:supportedAlgorithms', + 'supportedApplicationContext': 'urn:mace:dir:attribute-def:supportedApplicationContext', + 'surname': 'urn:mace:dir:attribute-def:surname', + 'telephoneNumber': 'urn:mace:dir:attribute-def:telephoneNumber', + 'teletexTerminalIdentifier': 'urn:mace:dir:attribute-def:teletexTerminalIdentifier', + 'telexNumber': 'urn:mace:dir:attribute-def:telexNumber', + 'textEncodedORAddress': 'urn:mace:dir:attribute-def:textEncodedORAddress', + 'title': 'urn:mace:dir:attribute-def:title', + 'uid': 'urn:mace:dir:attribute-def:uid', + 'uniqueIdentifier': 'urn:mace:dir:attribute-def:uniqueIdentifier', + 'uniqueMember': 'urn:mace:dir:attribute-def:uniqueMember', + 'userCertificate': 'urn:mace:dir:attribute-def:userCertificate', + 'userClass': 'urn:mace:dir:attribute-def:userClass', + 'userPKCS12': 'urn:mace:dir:attribute-def:userPKCS12', + 'userPassword': 'urn:mace:dir:attribute-def:userPassword', + 'userSMIMECertificate': 'urn:mace:dir:attribute-def:userSMIMECertificate', + 'userid': 'urn:mace:dir:attribute-def:userid', + 'x121Address': 'urn:mace:dir:attribute-def:x121Address', + 'x500UniqueIdentifier': 'urn:mace:dir:attribute-def:x500UniqueIdentifier', + } +} \ No newline at end of file diff --git a/example_setup/sp/sp/saml2_config/attribute-maps/saml_uri.py b/example_setup/sp/sp/saml2_config/attribute-maps/saml_uri.py new file mode 100644 index 0000000..8693d68 --- /dev/null +++ b/example_setup/sp/sp/saml2_config/attribute-maps/saml_uri.py @@ -0,0 +1,205 @@ +__author__ = 'rolandh' + +EDUPERSON_OID = "urn:oid:1.3.6.1.4.1.5923.1.1.1." +X500ATTR_OID = "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.1." +UMICH = "urn:oid:1.3.6.1.4.1.250.1.57." + +MAP = { + "identifier": "urn:oasis:names:tc:SAML:2.0:attrname-format: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_OID+'53': 'deltaRevocationList', + X500ATTR_OID+'52': 'supportedAlgorithms', + X500ATTR_OID+'51': 'houseIdentifier', + X500ATTR_OID+'50': 'uniqueMember', + X500ATTR_OID+'19': 'physicalDeliveryOfficeName', + X500ATTR_OID+'18': 'postOfficeBox', + X500ATTR_OID+'17': 'postalCode', + X500ATTR_OID+'16': 'postalAddress', + X500ATTR_OID+'15': 'businessCategory', + X500ATTR_OID+'14': 'searchGuide', + EDUPERSON_OID+'5': 'eduPersonPrimaryAffiliation', + X500ATTR_OID+'12': 'title', + X500ATTR_OID+'11': 'ou', + X500ATTR_OID+'10': 'o', + X500ATTR_OID+'37': 'cACertificate', + X500ATTR_OID+'36': 'userCertificate', + X500ATTR_OID+'31': 'member', + X500ATTR_OID+'30': 'supportedApplicationContext', + X500ATTR_OID+'33': 'roleOccupant', + X500ATTR_OID+'32': 'owner', + NETSCAPE_LDAP+'1': 'carLicense', + PKCS_9+'1': 'email', + NETSCAPE_LDAP+'3': 'employeeNumber', + NETSCAPE_LDAP+'2': 'departmentNumber', + X500ATTR_OID+'39': 'certificateRevocationList', + X500ATTR_OID+'38': 'authorityRevocationList', + NETSCAPE_LDAP+'216': 'userPKCS12', + EDUPERSON_OID+'8': 'eduPersonPrimaryOrgUnitDN', + X500ATTR_OID+'9': 'street', + X500ATTR_OID+'8': 'st', + NETSCAPE_LDAP+'39': 'preferredLanguage', + EDUPERSON_OID+'7': 'eduPersonEntitlement', + X500ATTR_OID+'2': 'knowledgeInformation', + X500ATTR_OID+'7': 'l', + X500ATTR_OID+'6': 'c', + X500ATTR_OID+'5': 'serialNumber', + X500ATTR_OID+'4': 'sn', + UCL_DIR_PILOT+'60': 'jpegPhoto', + X500ATTR_OID+'65': 'pseudonym', + NOREDUPERSON_OID+'5': 'norEduPersonNIN', + UCL_DIR_PILOT+'3': 'mail', + UCL_DIR_PILOT+'25': 'dc', + X500ATTR_OID+'40': 'crossCertificatePair', + X500ATTR_OID+'42': 'givenName', + X500ATTR_OID+'43': 'initials', + X500ATTR_OID+'44': 'generationQualifier', + X500ATTR_OID+'45': 'x500UniqueIdentifier', + X500ATTR_OID+'46': 'dnQualifier', + X500ATTR_OID+'47': 'enhancedSearchGuide', + X500ATTR_OID+'48': 'protocolInformation', + X500ATTR_OID+'54': 'dmdName', + NETSCAPE_LDAP+'4': 'employeeType', + X500ATTR_OID+'22': 'teletexTerminalIdentifier', + X500ATTR_OID+'23': 'facsimileTelephoneNumber', + X500ATTR_OID+'20': 'telephoneNumber', + X500ATTR_OID+'21': 'telexNumber', + X500ATTR_OID+'26': 'registeredAddress', + X500ATTR_OID+'27': 'destinationIndicator', + X500ATTR_OID+'24': 'x121Address', + X500ATTR_OID+'25': 'internationaliSDNNumber', + X500ATTR_OID+'28': 'preferredDeliveryMethod', + X500ATTR_OID+'29': 'presentationAddress', + EDUPERSON_OID+'3': 'eduPersonOrgDN', + NOREDUPERSON_OID+'3': 'norEduPersonBirthDate', + UMICH+'57': 'labeledURI', + UCL_DIR_PILOT+'1': 'uid', + # Custom entries + 'first_name': 'first_name', + 'last_name': 'last_name', + 'email': 'email', + 'is_staff': 'is_staff', + 'is_superuser': 'is_superuser', + }, + "to": { + 'roleOccupant': X500ATTR_OID+'33', + 'gn': X500ATTR_OID+'42', + 'norEduPersonNIN': NOREDUPERSON_OID+'5', + 'title': X500ATTR_OID+'12', + 'facsimileTelephoneNumber': X500ATTR_OID+'23', + 'mail': UCL_DIR_PILOT+'3', + 'postOfficeBox': X500ATTR_OID+'18', + 'fax': X500ATTR_OID+'23', + 'telephoneNumber': X500ATTR_OID+'20', + 'norEduPersonBirthDate': NOREDUPERSON_OID+'3', + 'rfc822Mailbox': UCL_DIR_PILOT+'3', + 'dc': UCL_DIR_PILOT+'25', + 'countryName': X500ATTR_OID+'6', + 'emailAddress': PKCS_9+'1', + 'employeeNumber': NETSCAPE_LDAP+'3', + 'organizationName': X500ATTR_OID+'10', + 'eduPersonAssurance': EDUPERSON_OID+'11', + 'norEduOrgAcronym': NOREDUPERSON_OID+'6', + 'registeredAddress': X500ATTR_OID+'26', + 'physicalDeliveryOfficeName': X500ATTR_OID+'19', + 'associatedDomain': UCL_DIR_PILOT+'37', + 'l': X500ATTR_OID+'7', + 'stateOrProvinceName': X500ATTR_OID+'8', + 'federationFeideSchemaVersion': NOREDUPERSON_OID+'9', + 'pkcs9email': PKCS_9+'1', + 'givenName': X500ATTR_OID+'42', + 'givenname': X500ATTR_OID+'42', + 'x500UniqueIdentifier': X500ATTR_OID+'45', + 'eduPersonNickname': EDUPERSON_OID+'2', + 'houseIdentifier': X500ATTR_OID+'51', + 'street': X500ATTR_OID+'9', + 'supportedAlgorithms': X500ATTR_OID+'52', + 'preferredLanguage': NETSCAPE_LDAP+'39', + 'postalAddress': X500ATTR_OID+'16', + 'email': PKCS_9+'1', + 'norEduOrgUnitUniqueIdentifier': NOREDUPERSON_OID+'8', + 'eduPersonPrimaryOrgUnitDN': EDUPERSON_OID+'8', + 'c': X500ATTR_OID+'6', + 'teletexTerminalIdentifier': X500ATTR_OID+'22', + 'o': X500ATTR_OID+'10', + 'cACertificate': X500ATTR_OID+'37', + 'telexNumber': X500ATTR_OID+'21', + 'ou': X500ATTR_OID+'11', + 'initials': X500ATTR_OID+'43', + 'eduPersonOrgUnitDN': EDUPERSON_OID+'4', + 'deltaRevocationList': X500ATTR_OID+'53', + 'norEduPersonLIN': NOREDUPERSON_OID+'4', + 'supportedApplicationContext': X500ATTR_OID+'30', + 'eduPersonEntitlement': EDUPERSON_OID+'7', + 'generationQualifier': X500ATTR_OID+'44', + 'eduPersonAffiliation': EDUPERSON_OID+'1', + 'eduPersonPrincipalName': EDUPERSON_OID+'6', + 'edupersonprincipalname': EDUPERSON_OID+'6', + 'localityName': X500ATTR_OID+'7', + 'owner': X500ATTR_OID+'32', + 'norEduOrgUnitUniqueNumber': NOREDUPERSON_OID+'2', + 'searchGuide': X500ATTR_OID+'14', + 'certificateRevocationList': X500ATTR_OID+'39', + 'organizationalUnitName': X500ATTR_OID+'11', + 'userCertificate': X500ATTR_OID+'36', + 'preferredDeliveryMethod': X500ATTR_OID+'28', + 'internationaliSDNNumber': X500ATTR_OID+'25', + 'uniqueMember': X500ATTR_OID+'50', + 'departmentNumber': NETSCAPE_LDAP+'2', + 'enhancedSearchGuide': X500ATTR_OID+'47', + 'userPKCS12': NETSCAPE_LDAP+'216', + 'eduPersonTargetedID': EDUPERSON_OID+'10', + 'norEduOrgUniqueNumber': NOREDUPERSON_OID+'1', + 'x121Address': X500ATTR_OID+'24', + 'destinationIndicator': X500ATTR_OID+'27', + 'eduPersonPrimaryAffiliation': EDUPERSON_OID+'5', + 'surname': X500ATTR_OID+'4', + 'jpegPhoto': UCL_DIR_PILOT+'60', + 'eduPersonScopedAffiliation': EDUPERSON_OID+'9', + 'edupersonscopedaffiliation': EDUPERSON_OID+'9', + 'protocolInformation': X500ATTR_OID+'48', + 'knowledgeInformation': X500ATTR_OID+'2', + 'employeeType': NETSCAPE_LDAP+'4', + 'userSMIMECertificate': NETSCAPE_LDAP+'40', + 'member': X500ATTR_OID+'31', + 'streetAddress': X500ATTR_OID+'9', + 'dmdName': X500ATTR_OID+'54', + 'postalCode': X500ATTR_OID+'17', + 'pseudonym': X500ATTR_OID+'65', + 'dnQualifier': X500ATTR_OID+'46', + 'crossCertificatePair': X500ATTR_OID+'40', + 'eduPersonOrgDN': EDUPERSON_OID+'3', + 'authorityRevocationList': X500ATTR_OID+'38', + 'displayName': NETSCAPE_LDAP+'241', + 'businessCategory': X500ATTR_OID+'15', + 'serialNumber': X500ATTR_OID+'5', + 'norEduOrgUniqueIdentifier': NOREDUPERSON_OID+'7', + 'st': X500ATTR_OID+'8', + 'carLicense': NETSCAPE_LDAP+'1', + 'presentationAddress': X500ATTR_OID+'29', + 'sn': X500ATTR_OID+'4', + 'domainComponent': UCL_DIR_PILOT+'25', + 'labeledURI': UMICH+'57', + 'uid': UCL_DIR_PILOT+'1' + } +} \ No newline at end of file diff --git a/example_setup/sp/sp/saml2_config/attribute-maps/shibboleth.py b/example_setup/sp/sp/saml2_config/attribute-maps/shibboleth.py new file mode 100644 index 0000000..d26bf00 --- /dev/null +++ b/example_setup/sp/sp/saml2_config/attribute-maps/shibboleth.py @@ -0,0 +1,190 @@ +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 diff --git a/example_setup/sp/sp/saml2_config/idp_metadata.xml b/example_setup/sp/sp/saml2_config/idp_metadata.xml index e37949e..6c4c27f 100644 --- a/example_setup/sp/sp/saml2_config/idp_metadata.xml +++ b/example_setup/sp/sp/saml2_config/idp_metadata.xml @@ -1,48 +1,43 @@ - - - - - - - - - - - - - - - - - - - - - - - - -MIIDCzCCAfOgAwIBAgIJAJ7dO0/bFrGwMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNV BAMMEWlkcC5sb2NhbGhvc3QuY29tMB4XDTE3MDMxMTE5NTAwNVoXDTE3MDQxMDE5 NTAwNVowHDEaMBgGA1UEAwwRaWRwLmxvY2FsaG9zdC5jb20wggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDrGDvKXlX4T+9aqI94xgZOmCFaUJ2eTGPm0c5y SNuD0rnLrAg92Y3bI95mXl06wUbCd7AA1uzh1omz8+fRBjLJpzFAcDEmcEl7X3+D aZ2SnDcIqmwc3HZgAmT5to+xmI3pylm/BkO6+DfgL5WRECNPeJSPK8CGrFH7HR7l FIeQnCtfPCf2KN4wSbujCABmKqqpQdoAlWaN/c3WCvwxjmOJP6MH62eTZDRZ9d2P QrB1rpP46vDdh1SzhQeW+wKxO//XSoWovOGjDYLI3qtsWOBcoMfdu0ubDb5e/09P kx9yCl7k/JyspwjwXC0HoBH5rP3qaaFDZPvAIRZvGCsPab0RAgMBAAGjUDBOMB0G A1UdDgQWBBQ7THKyabWi+oBi2t37QuUhPeP0DTAfBgNVHSMEGDAWgBQ7THKyabWi +oBi2t37QuUhPeP0DTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBV L/i54ZD0Ll2jLgWrFNDLP3JtqM381ji8iBJzV9+Sic3vi5gCoOk/xNiGBYVwSdY1 zlhTUqDGSu86+i55Of94hq13IkMjGPhOC5PchF4Up4z7wbLHRX5uPCUWbNbzrMuS Xqo3ioyltYheISLA9N8cqM6Z2lrtlyiXxfaWb00QBCnYbUI8Jd5Mr42h0jcitlDp dBPPi+Rp0lU9HKnmBL2nXGl7NbOtDehhk08zgXWC3Iqzp2RnA1y/fo/MEZ14sV1t KdCFQYJ70URQCkQbF9kFeY8tJ6jtrcT2kn1lyIdqIfdgSLNEBIDKsntZ0g5L68rk VRId1gcHubSTCpOBSuQ8 - - - - - - - - -MIIDCzCCAfOgAwIBAgIJAJ7dO0/bFrGwMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNV BAMMEWlkcC5sb2NhbGhvc3QuY29tMB4XDTE3MDMxMTE5NTAwNVoXDTE3MDQxMDE5 NTAwNVowHDEaMBgGA1UEAwwRaWRwLmxvY2FsaG9zdC5jb20wggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDrGDvKXlX4T+9aqI94xgZOmCFaUJ2eTGPm0c5y SNuD0rnLrAg92Y3bI95mXl06wUbCd7AA1uzh1omz8+fRBjLJpzFAcDEmcEl7X3+D aZ2SnDcIqmwc3HZgAmT5to+xmI3pylm/BkO6+DfgL5WRECNPeJSPK8CGrFH7HR7l FIeQnCtfPCf2KN4wSbujCABmKqqpQdoAlWaN/c3WCvwxjmOJP6MH62eTZDRZ9d2P QrB1rpP46vDdh1SzhQeW+wKxO//XSoWovOGjDYLI3qtsWOBcoMfdu0ubDb5e/09P kx9yCl7k/JyspwjwXC0HoBH5rP3qaaFDZPvAIRZvGCsPab0RAgMBAAGjUDBOMB0G A1UdDgQWBBQ7THKyabWi+oBi2t37QuUhPeP0DTAfBgNVHSMEGDAWgBQ7THKyabWi +oBi2t37QuUhPeP0DTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBV L/i54ZD0Ll2jLgWrFNDLP3JtqM381ji8iBJzV9+Sic3vi5gCoOk/xNiGBYVwSdY1 zlhTUqDGSu86+i55Of94hq13IkMjGPhOC5PchF4Up4z7wbLHRX5uPCUWbNbzrMuS Xqo3ioyltYheISLA9N8cqM6Z2lrtlyiXxfaWb00QBCnYbUI8Jd5Mr42h0jcitlDp dBPPi+Rp0lU9HKnmBL2nXGl7NbOtDehhk08zgXWC3Iqzp2RnA1y/fo/MEZ14sV1t KdCFQYJ70URQCkQbF9kFeY8tJ6jtrcT2kn1lyIdqIfdgSLNEBIDKsntZ0g5L68rk VRId1gcHubSTCpOBSuQ8 - - - - - -urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress - - -urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified - - - - + + + + + + + + + + + + + + + + + + + + + + + + MIIDCzCCAfOgAwIBAgIJAJ7dO0/bFrGwMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNV BAMMEWlkcC5sb2NhbGhvc3QuY29tMB4XDTE3MDMxMTE5NTAwNVoXDTE3MDQxMDE5 NTAwNVowHDEaMBgGA1UEAwwRaWRwLmxvY2FsaG9zdC5jb20wggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDrGDvKXlX4T+9aqI94xgZOmCFaUJ2eTGPm0c5y SNuD0rnLrAg92Y3bI95mXl06wUbCd7AA1uzh1omz8+fRBjLJpzFAcDEmcEl7X3+D aZ2SnDcIqmwc3HZgAmT5to+xmI3pylm/BkO6+DfgL5WRECNPeJSPK8CGrFH7HR7l FIeQnCtfPCf2KN4wSbujCABmKqqpQdoAlWaN/c3WCvwxjmOJP6MH62eTZDRZ9d2P QrB1rpP46vDdh1SzhQeW+wKxO//XSoWovOGjDYLI3qtsWOBcoMfdu0ubDb5e/09P kx9yCl7k/JyspwjwXC0HoBH5rP3qaaFDZPvAIRZvGCsPab0RAgMBAAGjUDBOMB0G A1UdDgQWBBQ7THKyabWi+oBi2t37QuUhPeP0DTAfBgNVHSMEGDAWgBQ7THKyabWi +oBi2t37QuUhPeP0DTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBV L/i54ZD0Ll2jLgWrFNDLP3JtqM381ji8iBJzV9+Sic3vi5gCoOk/xNiGBYVwSdY1 zlhTUqDGSu86+i55Of94hq13IkMjGPhOC5PchF4Up4z7wbLHRX5uPCUWbNbzrMuS Xqo3ioyltYheISLA9N8cqM6Z2lrtlyiXxfaWb00QBCnYbUI8Jd5Mr42h0jcitlDp dBPPi+Rp0lU9HKnmBL2nXGl7NbOtDehhk08zgXWC3Iqzp2RnA1y/fo/MEZ14sV1t KdCFQYJ70URQCkQbF9kFeY8tJ6jtrcT2kn1lyIdqIfdgSLNEBIDKsntZ0g5L68rk VRId1gcHubSTCpOBSuQ8 + + + + + + + MIIDCzCCAfOgAwIBAgIJAJ7dO0/bFrGwMA0GCSqGSIb3DQEBCwUAMBwxGjAYBgNV BAMMEWlkcC5sb2NhbGhvc3QuY29tMB4XDTE3MDMxMTE5NTAwNVoXDTE3MDQxMDE5 NTAwNVowHDEaMBgGA1UEAwwRaWRwLmxvY2FsaG9zdC5jb20wggEiMA0GCSqGSIb3 DQEBAQUAA4IBDwAwggEKAoIBAQDrGDvKXlX4T+9aqI94xgZOmCFaUJ2eTGPm0c5y SNuD0rnLrAg92Y3bI95mXl06wUbCd7AA1uzh1omz8+fRBjLJpzFAcDEmcEl7X3+D aZ2SnDcIqmwc3HZgAmT5to+xmI3pylm/BkO6+DfgL5WRECNPeJSPK8CGrFH7HR7l FIeQnCtfPCf2KN4wSbujCABmKqqpQdoAlWaN/c3WCvwxjmOJP6MH62eTZDRZ9d2P QrB1rpP46vDdh1SzhQeW+wKxO//XSoWovOGjDYLI3qtsWOBcoMfdu0ubDb5e/09P kx9yCl7k/JyspwjwXC0HoBH5rP3qaaFDZPvAIRZvGCsPab0RAgMBAAGjUDBOMB0G A1UdDgQWBBQ7THKyabWi+oBi2t37QuUhPeP0DTAfBgNVHSMEGDAWgBQ7THKyabWi +oBi2t37QuUhPeP0DTAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQBV L/i54ZD0Ll2jLgWrFNDLP3JtqM381ji8iBJzV9+Sic3vi5gCoOk/xNiGBYVwSdY1 zlhTUqDGSu86+i55Of94hq13IkMjGPhOC5PchF4Up4z7wbLHRX5uPCUWbNbzrMuS Xqo3ioyltYheISLA9N8cqM6Z2lrtlyiXxfaWb00QBCnYbUI8Jd5Mr42h0jcitlDp dBPPi+Rp0lU9HKnmBL2nXGl7NbOtDehhk08zgXWC3Iqzp2RnA1y/fo/MEZ14sV1t KdCFQYJ70URQCkQbF9kFeY8tJ6jtrcT2kn1lyIdqIfdgSLNEBIDKsntZ0g5L68rk VRId1gcHubSTCpOBSuQ8 + + + + urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress + urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified + + + \ No newline at end of file diff --git a/example_setup/sp/sp/settings.py b/example_setup/sp/sp/settings.py index 1dfe6bb..477f2c2 100644 --- a/example_setup/sp/sp/settings.py +++ b/example_setup/sp/sp/settings.py @@ -1,4 +1,4 @@ -""" +''' Django settings for sp project. Generated by 'django-admin startproject' using Django 1.10.6. @@ -8,7 +8,7 @@ For the full list of settings and their values, see https://docs.djangoproject.com/en/1.10/ref/settings/ -""" +''' import os @@ -120,11 +120,13 @@ STATIC_URL = '/static/' -### Added settings for djangosaml2 +### Everything above are default settings made by django-admin startproject +### The following is added for djangosaml2 SP configuration. +### See their docs for explanation of all options. import saml2 from saml2.saml import NAMEID_FORMAT_EMAILADDRESS -import os +from saml2.sigver import get_xmlsec_binary AUTHENTICATION_BACKENDS = ( 'django.contrib.auth.backends.ModelBackend', @@ -135,48 +137,37 @@ LOGOUT_URL = '/logout/' LOGIN_REDIRECT_URL = '/' LOGOUT_REDIRECT_URL = '/' -SESSION_EXPIRE_AT_BROWSER_CLOSE = True -SAML_USE_NAME_ID_AS_USERNAME = True -SAML_DJANGO_USER_MAIN_ATTRIBUTE = 'username' -SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP = '__iexact' -SAML_CREATE_UNKNOWN_USER = True -SAML_ATTRIBUTE_MAPPING = { - # SAML: DJANGO - 'email': ('email', ), - 'first_name': ('first_name', ), - 'last_name': ('last_name', ), - 'is_staff': ('is_staff', ), - 'is_superuser': ('is_superuser', ), -} + +BASE_URL = 'http://localhost:8000/saml2' SAML_CONFIG = { 'debug' : DEBUG, - 'xmlsec_binary': '/usr/bin/xmlsec1', # For Unix (Alpine/Debian) - 'entityid': 'http://localhost:8000/saml2/metadata/', + 'xmlsec_binary': get_xmlsec_binary(['/opt/local/bin', '/usr/bin/xmlsec1']), + 'entityid': '%s/metadata/' % BASE_URL, 'service': { 'sp': { - 'name': 'http://localhost:8000/saml2/metadata/', - "allow_unsolicited": 'true', - 'name_id_format': NAMEID_FORMAT_EMAILADDRESS, + 'name': '%s/metadata/' % BASE_URL, 'endpoints': { 'assertion_consumer_service': [ - ('http://localhost:8000/saml2/acs/', saml2.BINDING_HTTP_POST), + ('%s/acs/' % BASE_URL, saml2.BINDING_HTTP_POST), ], 'single_logout_service': [ - ('http://localhost:8000/saml2/ls/', saml2.BINDING_HTTP_REDIRECT), - ('http://localhost:8000/saml2/ls/post', saml2.BINDING_HTTP_POST), + ('%s/ls/' % BASE_URL, saml2.BINDING_HTTP_REDIRECT), + ('%s/ls/post' % BASE_URL, saml2.BINDING_HTTP_POST), ], }, + 'name_id_format': [NAMEID_FORMAT_EMAILADDRESS], 'authn_requests_signed': True, 'want_assertions_signed': True, + 'allow_unsolicited': True, }, }, + 'attribute_map_dir': os.path.join(os.path.join(os.path.join(BASE_DIR, 'sp'), 'saml2_config'), 'attribute-maps'), 'metadata': { 'local': [os.path.join(os.path.join(os.path.join(BASE_DIR, 'sp'), 'saml2_config'), 'idp_metadata.xml')], }, - # Certificates created with: openssl req -x509 -sha256 -newkey rsa:2048 -keyout private_key.pem -out public_key.pem -nodes -subj '/CN=sp.localhost.com' # Signing 'key_file': BASE_DIR + '/certificates/private_key.pem', 'cert_file': BASE_DIR + '/certificates/public_key.pem', @@ -185,9 +176,20 @@ 'key_file': BASE_DIR + '/certificates/private_key.pem', 'cert_file': BASE_DIR + '/certificates/public_key.pem', }], - 'valid_for': 24, + 'valid_for': 365, } -from sys import platform -if platform == "darwin": - SAML_CONFIG["xmlsec_binary"] = "/opt/local/bin/xmlsec1" \ No newline at end of file +SAML_USE_NAME_ID_AS_USERNAME = True +SAML_DJANGO_USER_MAIN_ATTRIBUTE = 'username' +SAML_DJANGO_USER_MAIN_ATTRIBUTE_LOOKUP = '__iexact' +SAML_CREATE_UNKNOWN_USER = True + +SAML_ATTRIBUTE_MAPPING = { + # SAML: DJANGO + # Must also be present in attribute-maps! + 'email': ('email', ), + 'first_name': ('first_name', ), + 'last_name': ('last_name', ), + 'is_staff': ('is_staff', ), + 'is_superuser': ('is_superuser', ), +} diff --git a/example_setup/sp/sp/views.py b/example_setup/sp/sp/views.py index 48cdda7..bd75ac1 100644 --- a/example_setup/sp/sp/views.py +++ b/example_setup/sp/sp/views.py @@ -6,7 +6,7 @@ def index(request): - """ Print user attributes if logged in. + """ Barebone 'diagnistics' view, print user attributes if logged in + login/logout links. """ if request.user.is_authenticated: out = "LOGGED IN: LOGOUT
".format(settings.LOGOUT_URL) @@ -18,6 +18,7 @@ def index(request): return HttpResponse("LOGGED OUT: LOGIN".format(settings.LOGIN_URL)) +# TODO fix this in IdP side? @receiver(pre_user_save, sender=User) def custom_update_user(sender, instance, attributes, user_modified, **kargs): """ Default behaviour does not play nice with booleans encoded in SAML as u'true'/u'false'. diff --git a/tests/settings.py b/tests/settings.py index 2d0f3be..58afec9 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -33,55 +33,3 @@ ) ROOT_URLCONF = 'tests.urls' - -LOGIN_REDIRECT_URL = '/idp/sso/post/response/preview/' - -# SAML2IDP metadata settings -SAML2IDP_CONFIG = { - 'autosubmit': False, - 'issuer': 'http://127.0.0.1:8000', - 'signing': True, - 'certificate_file': PROJECT_ROOT + '/tests/keys/sample/sample-certificate.pem', - 'private_key_file': PROJECT_ROOT + '/tests/keys/sample/sample-private-key.pem', -} - -demoSpConfig = { - 'acs_url': 'http://127.0.0.1:9000/sp/acs/', - 'processor': 'djangosaml2idp.processors.Processor', - 'links': [ # a list of (resource, pattern) tuples, or a {resource: pattern} dict - #NOTE: This should still work, due to the "simple" 'login_init' URL in urls.py: - #TEST BY BROWSING TO: http://127.0.0.1:8000/sp/test/ - ('deeplink', 'http://127.0.0.1:9000/sp/%s/'), - # The following are "new" deeplink mappings that let you specify more than one capture group: - # This is equivalent to the above, using the 'new' deeplink mapping: - #TEST BY BROWSING TO: http://127.0.0.1:8000/sp/test/ - (r'deeplink/(?P\w+)', 'http://127.0.0.1:9000/sp/%(target)s/'), - # Using two capture groups: - #TEST BY BROWSING TO: http://127.0.0.1:8000/sp/test/ - (r'deeplink/(?P\w+)/(?P\w+)', 'http://127.0.0.1:9000/%(target)s/%(page)s/'), - # Deeplink to a resource that requires query parameters: - #NOTE: In the pattern, always use %(variable)s, because the captured - # parameters will always be in unicode. - #TEST BY BROWSING TO: http://127.0.0.1:8000/sp/test/123/ - (r'deeplink/(?P\w+)/(?P\w+)/(?P\d+)', - 'http://127.0.0.1:9000/%(target)s/%(page)s/?param=%(param)s'), - ], -} -attrSpConfig = { - 'acs_url': 'http://127.0.0.1:9000/sp/acs/', - 'processor': 'djangosaml2idp.processors.AttributeProcessor', - 'links': { - 'attr': 'http://127.0.0.1:9000/sp/%s/', - }, -} -SAML2IDP_REMOTES = { - # Group of SP CONFIGs. - # friendlyname: SP config - 'attr_demo': attrSpConfig, - 'demo': demoSpConfig, -} - -# Setup logging. -import logging -logging.basicConfig(filename=PROJECT_ROOT + '/saml2idp.log', format='%(asctime)s: %(message)s', level=logging.DEBUG) -logging.info('Logging setup.')