{"id":20156106,"url":"https://github.com/openfun/social-edu-federation","last_synced_at":"2025-04-09T22:21:04.453Z","repository":{"id":36955079,"uuid":"501645295","full_name":"openfun/social-edu-federation","owner":"openfun","description":"🔑 An SAML authentication backend for python-social-auth dedicated to education federation (RENATER)","archived":false,"fork":false,"pushed_at":"2023-09-29T07:11:33.000Z","size":613,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":9,"default_branch":"main","last_synced_at":"2025-03-20T11:48:14.185Z","etag":null,"topics":["django","python","python-social-auth","renater","saml"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/openfun.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2022-06-09T12:33:22.000Z","updated_at":"2024-01-26T13:57:47.000Z","dependencies_parsed_at":"2023-01-17T08:02:25.128Z","dependency_job_id":null,"html_url":"https://github.com/openfun/social-edu-federation","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fsocial-edu-federation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fsocial-edu-federation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fsocial-edu-federation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/openfun%2Fsocial-edu-federation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/openfun","download_url":"https://codeload.github.com/openfun/social-edu-federation/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248120061,"owners_count":21050886,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","python","python-social-auth","renater","saml"],"created_at":"2024-11-13T23:37:36.063Z","updated_at":"2025-04-09T22:21:04.433Z","avatar_url":"https://github.com/openfun.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# social-edu-federation: An SAML authentication backend for python-social-auth dedicated to education federation (RENATER)\n\n[![Python version](https://img.shields.io/badge/Python-3.8%20|%203.9%20|%203.10%20|%203.11-blue.svg)](https://www.python.org/)\n[![Django version](https://img.shields.io/badge/Django-3.2%20|%204.0%20|%204.1%20|%204.2-green.svg)](https://www.djangoproject.com/)\n[![CircleCI](https://circleci.com/gh/openfun/social-edu-federation/tree/main.svg?style=svg)](https://circleci.com/gh/openfun/social-edu-federation/tree/main)\n\n## Overview\n\nThis library provides an authentication backend which can be used with\n[Python Social Auth](https://github.com/python-social-auth/social-core)\nand optionally\n[Python Social Auth - Django](https://github.com/python-social-auth/social-app-django)\nto connect your application to an education SAML federation.\n\nBefore beginning, you must read the above documentations.\n\nFor now, it is only limited to the\n[RENATER](https://services.renater.fr/federation/en/documentation/generale/metadata/index)'s\n\"Féderation Éducation-Recherche\" (FER) federation.\n\n\n## Architecture\n\n`social-edu-federation` is divided in two parts:\n- The SAML backend and metadata parser, customized for the FER federation,\n  usable with Python Social Auth.\n- The Django integration which provides: base views to provide metadata, list available\n  Identity Providers and testing material for local development.\n\n\n### Authentication behavior\n\nThis library parses the metadata to extract base SAML authentication for each identity\nprovider in the federation metadata plus some extra information\n(see below *Setup - Core* section)\n\nThe authentication process can be summarized in few steps:\n\n- The federation metadata are parsed to fetch the identity providers list.\n- User choose an identity provider in the list with which they have an account and want to login.\n- The backend makes an SAML authentication request and redirects the user to the identity provider\n  \"single login\" page.\n- The user logs in on the identity provider website and is redirected to our (Service Provider) site.\n- The SAML FER backend will extract authentication data it needs from the authentication response\n  assertions.\n  The used assertions are:\n  - **urn:oid:2.5.4.4** (sn) aka (surname)\n    This represents the user's first name.\n  - **urn:oid:2.5.4.42** (givenName) aka (gn)\n    This represents the user's last name.\n  - **urn:oid:2.16.840.1.113730.3.1.241** (displayName)\n    This represents the user's full name.\n  - **urn:oid:0.9.2342.19200300.100.1.3** (mail)\n    Provides us the user email, we use it as email address and username.\n  - **urn:oid:1.3.6.1.4.1.5923.1.1.1.1** (eduPersonAffiliation)\n    Provides us the user's role(s) list.\n    This is not mandatory.\n\n  Fields we do not use:\n   - **urn:oid:1.3.6.1.4.1.7135.1.2.1.14** (supannEtablissement)\n\n  All fields are documented on\n  [Renater supann](https://services.renater.fr/documentation/supann/supann2021/recommandations/attributs/liste_des_attributs).\n- The authentication response passes through the \"Social auth\" pipeline.\n  `social-edu-federation` provides one extra step to replace the\n  `social_core.pipeline.user.create_user` original one. This step allows to have a fallback\n  on the user's *full name* if one of the *first name* or *last name* is not available.\n\n## Setup\n\n### Core\n\nYou may install only the library core which will provide you with:\n- The FER metadata parser (see `social_edu_federation.parser.FederationMetadataParser`)\n  which is an extension of the original `python3-saml`'s `OneLogin_Saml2_IdPMetadataParser`\n  and provides extra features as:\n  - Extract all the identity providers at once\n  - Extract extra information from each identity provider metadata (\n    the identity provider's display name,\n    the identity provider's organization name,\n    the identity provider's organization display name)\n- A basic \"metadata store\" which is not really helpful but organizes the process of fetching\n  the metadata and convert it to a Python Social Auth like object, usable by the authentication\n  backend.\n- The SAML authentication backend which is preconfigured to be used with the FER federation.\n\n```shell\n$ pip install social-edu-federation\n```\n\n### Django integration\n\nIf you also want to add this library into a Django project you may explicitly add the `django` extra while installing the library:\n\n```shell\n$ pip install social-edu-federation[django]\n```\n\nIt is also recommended to add `social_edu_federation.django.apps.PythonSocialEduFedAuthConfig`\nto your `INSTALLED_APPS` to get the following features:\n\n- A Django check which asserts the default \"metadata store\" is overridden.\n- The `prefetch_saml_fer_metadata` management command (see *Cache management* below).\n- The static files and Django views default templates (see *Using the default views* below).\n\n#### Cache management\n\nWhen using the Django integration, it is highly recommended to define a Django setting to\ntell `social_edu_federation` to use the \"metadata store with cache\". This will avoid fetching\nthe whole federation metadata everytime we need an information about one identity\nprovider.\n\n```python\n# settings.py\nSOCIAL_AUTH_SAML_FER_FEDERATION_SAML_METADATA_STORE = \"social_edu_federation.django.metadata_store.CachedMetadataStore\"\n```\n\nThis \"metadata store\" will use the Django `default` cache which can be easily replaced by\nthe cache backend of your choice:\n\n```python\n# settings.py\nSOCIAL_AUTH_SAML_FER_DJANGO_CACHE = \"redis\"\n\nassert SOCIAL_AUTH_SAML_FER_DJANGO_CACHE in CACHES, \"cache backend name is not in settings.CACHES\"\n```\n\nIf you installed the `social_edu_federation` Django application, you will be able to\nfill the cache asynchronously using the `prefetch_saml_fer_metadata` management\ncommand, by defining a cron job which will call\n`django-admin prefetch_saml_fer_metadata saml_fer` to refresh the FER cache.\nUsing this make sure that no actual user has to wait for the full federation metadata to load\nloading time.\n\n#### Project setup\n\nFor a basic use of the FER backend for authentication you will need to define:\n\n```python\n# settings.py\nINSTALLED_APPS = [\n    # ...\n    \"social_django.apps.PythonSocialAuthConfig\",  # see python-social-auth\n    \"social_edu_federation.django.apps.PythonSocialEduFedAuthConfig\",\n]\nMIDDLEWARE = [\n    # ...\n    \"social_django.middleware.SocialAuthExceptionMiddleware\",  # At the end\n]\n\nAUTHENTICATION_BACKENDS = [\n    \"social_edu_federation.backends.saml_fer.FERSAMLAuth\",\n    \"django.contrib.auth.backends.ModelBackend\",  # only if you keep Django basic auth\n]\n\n# Python social auth\nSOCIAL_AUTH_JSONFIELD_ENABLED = True\n\nSOCIAL_AUTH_SAML_FER_SECURITY_CONFIG = {\n    \"authnRequestsSigned\": True,\n    \"signMetadata\": True,\n    \"wantAssertionsSigned\": True,\n    \"rejectDeprecatedAlgorithm\": True,\n}\n\n# Specific social_edu_federation\nSOCIAL_AUTH_SAML_FER_FEDERATION_SAML_METADATA_STORE = \"social_edu_federation.django.metadata_store.CachedMetadataStore\"\n\n# SOCIAL_AUTH_SAML_FER_SP_ENTITY_ID should be a URL that includes a domain name you own\nSOCIAL_AUTH_SAML_FER_SP_ENTITY_ID = \"https://you-site.example/saml/metadata/\"\n# SOCIAL_AUTH_SAML_FER_SP_PUBLIC_CERT X.509 certificate for the key pair that\n# your app will use\nSOCIAL_AUTH_SAML_FER_SP_PUBLIC_CERT = \"MII...\"\n# SOCIAL_AUTH_SAML_FER_SP_PRIVATE_KEY The private key to be used by your app\nSOCIAL_AUTH_SAML_FER_SP_PRIVATE_KEY = \"MII...\"\n\n# Next certificate management, keep empty when next certificate is still not known\nSOCIAL_AUTH_SAML_FER_SP_NEXT_PUBLIC_CERT = None\nSOCIAL_AUTH_SAML_FER_SP_EXTRA = (\n    {\n        \"x509certNew\": SOCIAL_AUTH_SAML_FER_SP_NEXT_PUBLIC_CERT,\n    }\n    if SOCIAL_AUTH_SAML_FER_SP_NEXT_PUBLIC_CERT\n    else {}\n)\n\nSOCIAL_AUTH_SAML_FER_ORG_INFO = {  # specify values for English at a minimum\n    \"en-US\": {\n        \"name\": \"Organization name\",\n        \"displayname\": \"Organization display name\",\n        \"url\": \"https://you-site.example\",\n    }\n}\n# SOCIAL_AUTH_SAML_FER_TECHNICAL_CONTACT technical contact responsible for your app\nSOCIAL_AUTH_SAML_FER_TECHNICAL_CONTACT = {\n    \"givenName\": \"Dev team\",\n    \"emailAddress\": \"dev@example.com\",\n}\n# SOCIAL_AUTH_SAML_FER_SUPPORT_CONTACT support contact for your app\nSOCIAL_AUTH_SAML_FER_SUPPORT_CONTACT = {\n    \"givenName\": \"Dev team\",\n    \"emailAddress\": \"dev@example.com\",\n}\n# SOCIAL_AUTH_SAML_FER_ENABLED_IDPS is not required since the\n# SAML FER backend is overridden to allow dynamic IdPs.\n# see social_edu_federation.backends.saml_fer.FERSAMLAuth.get_idp(idp_name)\n\n# Custom parameter to define the FER Federation Metadata\nSOCIAL_AUTH_SAML_FER_FEDERATION_SAML_METADATA_URL = (\n    \"https://metadata.federation.renater.fr/renater/main/main-idps-renater-metadata.xml\"\n)\n\n# Use (or not) the default pipeline with the first/last name cleanup step\nfrom social_edu_federation.pipeline import DEFAULT_EDU_FED_AUTH_PIPELINE\nSOCIAL_AUTH_SAML_FER_PIPELINE = DEFAULT_EDU_FED_AUTH_PIPELINE\n```\n\n#### Using the default views\n\nTo make your Service Provider metadata publicly available, you will need to add\nthe following URL:\n\n```python\n# some_module/urls.py\nfrom django.urls import path\n\nfrom social_edu_federation.django.views import EduFedMetadataView\n\n\nurlpatterns = [\n    # ...\n    path(\n        \"saml/metadata/\",\n        EduFedMetadataView.as_view(backend_name=\"saml_fer\"),\n        name=\"saml_fer_metadata\",\n    ),\n]\n```\n\nYou may also want to have a look at the provided `EduFedIdpChoiceView` which serves\nthe list of identity providers in the federation. It includes a cookie mechanism for the\nuser to easily find the last used identity providers.\n\nAn easy way to use it:\n\n```python\n# some_module/views.py\nfrom social_edu_federation.django.views import EduFedIdpChoiceView\n\n\nclass CustomizedEduFederationIdpChoiceView(EduFedIdpChoiceView):\n    \"\"\"Display the list of all available Identity providers using our own template.\"\"\"\n\n    template_extends = \"my_site/base.html\"\n\n\n# some_module/urls.py\nfrom django.urls import path\n\nfrom . import views\n\nurlpatterns = [\n    # ...\n    path(\n        \"saml/renater_fer_idp_choice/\",\n        views.CustomizedEduFederationIdpChoiceView.as_view(backend_name=\"saml_fer\"),\n        name=\"saml_fer_idp_choice\",\n    ),\n]\n```\n\n#### Testing views\n\n`social-edu-federation` comes along with testing views to ease the development process.\nThose testing views are to be used when you want to test the whole authentication loop on\nyour local computer.\n\nHow to plug the testing views in your project is not detailed here, but you can\ntry them (or see how they are plugged) by running the `social-edu-federation` tests suite.\n\nFetch the project:\n\n```shell\ngit clone git@github.com:openfun/social-edu-federation.git\n```\n\nCreate a virtual environment and install requirements:\n\n```shell\ncd social-edu-federation\npip install .[dev,django]\n```\n\nRun the standalone Django project:\n\n```shell\nmake run_django\n```\n\nOpen it in your browser.\n\n##### Docker\n\nIn case you want to plug the testing views in your own project which is run in a Docker container\nyou will probably need to define the port used in the generated metadata. By default,\nit will use the Django application port (let's say 8000) but if your mapping to the container\nuses another port you have to define `SOCIAL_AUTH_SAML_FER_IDP_FAKER_DOCKER_PORT` setting\nto provide the proper port.\n\nE.g.:\n - Without override: metadata will be for `http://testserver:8000/saml/idp/sso/`\n - With `SOCIAL_AUTH_SAML_FER_IDP_FAKER_DOCKER_PORT=11000`,\n   metadata will be for `http://testserver:11000/saml/idp/sso/`.\n\n\n## Contributing\n\nThis project is intended to be community-driven, so please, do not hesitate to get in touch if you\nhave any question related to our implementation or design decisions.\n\nWe try to raise our code quality standards and expect contributors to follow the recommandations\nfrom our [handbook](https://openfun.gitbooks.io/handbook/content).\n\n\n## Versioning\n\nThis project follows [Semantic Versioning 2.0.0](http://semver.org/spec/v2.0.0.html).\n\n\n## License\n\nThis work is released under the MIT License (see [LICENSE](./LICENSE)).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfun%2Fsocial-edu-federation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenfun%2Fsocial-edu-federation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenfun%2Fsocial-edu-federation/lists"}