Skip to content

Commit

Permalink
Merge pull request #89 from maykinmedia/feature/88-readthedocs
Browse files Browse the repository at this point in the history
📝 [#88] Setting up config for readthedocs
  • Loading branch information
stevenbal authored Feb 22, 2024
2 parents 6dfc902 + 56939f3 commit c6b33c2
Show file tree
Hide file tree
Showing 12 changed files with 400 additions and 264 deletions.
2 changes: 2 additions & 0 deletions .bumpversion.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ current_version = 0.15.0
[bumpversion:file:setup.cfg]

[bumpversion:file:README.rst]

[bumpversion:file:docs/conf.py]
2 changes: 1 addition & 1 deletion .github/workflows/code_quality.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
toxenv: [isort, black]
toxenv: [isort, black, docs]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
Expand Down
20 changes: 20 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

version: 2

sphinx:
configuration: docs/conf.py

build:
os: 'ubuntu-22.04'
tools:
python: '3.10'

python:
install:
- method: pip
path: .
extra_requirements:
- docs
257 changes: 8 additions & 249 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to mozilla_django_oidc_db's documentation!
==================================================
mozilla-django-oidc-db
======================

:Version: 0.15.0
:Source: https://github.com/maykinmedia/mozilla-django-oidc-db
Expand Down Expand Up @@ -37,251 +37,10 @@ Additionally, ``mozilla-django-oidc-db`` by default uses the ``sub`` (subject) c
instead of the ``email`` claim as the unique identifier for users in the RP (Relying Party) application.
Using ``email`` as the unique identifier is not recommended, as mentioned in the `OpenID Connect specification`_.

Installation
============

Requirements
------------

* See the badges for the supported Python and Django versions
* A PostgreSQL database (we use ``django.contrib.postgres.fields.ArrayField``)

Install
-------

.. code-block:: bash
pip install mozilla-django-oidc-db
This will also install the following packages:

- ``mozilla-django-oidc``
- ``django-solo``
- ``django-jsonform``

Django settings
---------------

Make sure the following libraries are added to your ``INSTALLED_APPS``:

.. code-block:: python
INSTALLED_APPS = [
...
"django_jsonform",
"solo",
"mozilla_django_oidc",
"mozilla_django_oidc_db",
...
]
Add ``mozilla_django_oidc_db.backends.OIDCAuthenticationBackend`` to the ``AUTHENTICATION_BACKENDS``,
this backend replaces ``mozilla_django_oidc.auth.OIDCAuthenticationBackend``:

.. code-block:: python
AUTHENTICATION_BACKENDS = [
...
"mozilla_django_oidc_db.backends.OIDCAuthenticationBackend",
...
]
Ensure that ``LOGIN_REDIRECT_URL`` and ``LOGOUT_REDIRECT_URL`` are configured. For example:

.. code-block:: python
LOGIN_REDIRECT_URL = reverse_lazy("admin:index")
LOGOUT_REDIRECT_URL = reverse_lazy("admin:index")
To enable validation of ID tokens by renewing them, add ``mozilla_django_oidc_db.middleware.SessionRefresh``
to the middleware, this middleware replaces ``mozilla_django_oidc.middleware.SessionRefresh``:

.. code-block:: python
MIDDLEWARE = [
# middleware involving session and authentication must come first
...
"mozilla_django_oidc_db.middleware.SessionRefresh",
...
]
Furthermore, ensure the following settings are configured:

.. code-block:: python
OIDC_AUTHENTICATE_CLASS = "mozilla_django_oidc_db.views.OIDCAuthenticationRequestView"
OIDC_CALLBACK_CLASS = "mozilla_django_oidc_db.views.OIDCCallbackView"
MOZILLA_DJANGO_OIDC_DB_CACHE = "oidc"
MOZILLA_DJANGO_OIDC_DB_CACHE_TIMEOUT = 1
In order to properly catch admin login errors, add the following to urlpatterns:

.. code-block:: python
from mozilla_django_oidc_db.views import AdminLoginFailure
urlpatterns = [
...
path("admin/login/failure/", AdminLoginFailure.as_view(), name="admin-oidc-error"),
...
]
``MOZILLA_DJANGO_OIDC_DB_CACHE`` is used to cache the configuration that is stored in the database,
to prevent a lot of database lookups. Ensure this cache is configured in ``CACHES`` (using the backend of choice):

.. code-block:: python
CACHES = {
"default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"},
...
"oidc": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"},
}
Add the urlpatterns:

.. code-block:: python
urlpatterns = [
...
path("oidc/", include("mozilla_django_oidc.urls")),
...
]
Add the login link to your templates:

.. code-block:: django
{% get_solo 'mozilla_django_oidc_db.OpenIDConnectConfig' as oidc_config %}
{% if oidc_config.enabled %}
<div class="submit-row">
<a href="{% url 'oidc_authentication_init' %}">{% trans "Login with OIDC" %}</a>
</div>
{% endif %}
Usage
=====

Now OpenID Connect can be enabled/disabled via the admin (disabled by default)
and the following settings from ``mozilla-django-oidc`` for OpenID Connect can be configured in the admin:

- ``OIDC_RP_CLIENT_ID``
- ``OIDC_RP_CLIENT_SECRET``
- ``OIDC_RP_SIGN_ALGO``
- ``OIDC_RP_SCOPES`` (via ``oidc_rp_scopes_list``)
- ``OIDC_OP_JWKS_ENDPOINT``
- ``OIDC_OP_AUTHORIZATION_ENDPOINT``
- ``OIDC_OP_TOKEN_ENDPOINT``
- ``OIDC_OP_USER_ENDPOINT``
- ``OIDC_TOKEN_USE_BASIC_AUTH``
- ``OIDC_RP_IDP_SIGN_KEY``
- ``OIDC_USE_NONCE``
- ``OIDC_STATE_SIZE``
- ``OIDC_EXEMPT_URLS``

In case no value is provided for one of these variables, the default from ``mozilla-django-oidc``
will be used (if there is one). A detailed description of all settings can be found in the `mozilla-django-oidc settings documentation`_.

OIDC discovery endpoint
-----------------------

Instead of setting each OIDC endpoint as shown above manually, these endpoints can be
derived by setting the **Discovery endpoint** (ending with a slash).
The path ``.well-known/openid-configuration`` will be added to this URL automatically.

For more information about the discovery endpoint, refer to the the `OIDC spec`_.

Custom username claim
---------------------

The name of the claim that is used for the ``User.username`` property
can be configured via the admin (**Username claim**). By default, the username is derived from the ``sub`` claim that
is returned by the OIDC provider.

If the desired claim is nested in one or more objects, its path can be specified with dots, e.g.:

.. code-block:: json
{
"some": {
"nested": {
"claim": "foo"
}
}
}
Can be retrieved by setting the username claim to ``some.nested.claim``

**NOTE**: the username claim does not support claims that have dots in their name, it cannot be configured to retrieve the following claim for instance:

.. code-block:: json
{
"some.dotted.claim": "foo"
}
User profile
------------

In order to set other attributes on the ``User`` object, a **Claim mapping**
can be specified via the admin. This maps the names of claims returned by the OIDC provider to
fields on the ``User`` model, and whenever a ``User`` is created/updated, these
fields will be set to the values of these claims.

User information claims source
------------------------------

There are currently two methods to extract information about the authenticated user, controlled by the **User information claims extracted from** (``userinfo_claims_source``) option.

- `Userinfo endpoint`, this is the default method (this is also the default behavior in `mozilla-django-oidc`)
- `ID token`, to extract the claims from the ID token. This could be preferable in the case where
the authentication server passes sensitive claims (that should not be stored in the authentication server itself)
via the ID token

Assigning users to groups
-------------------------

When users are created/updated, they can be automatically assigned to ``Groups``
by setting the appropriate value for **Groups claim**, which is the name of the claim that
contains the groups the user is assigned to by the OIDC provider. If **Synchronize groups** is
enabled, local Django user groups will be created for group names present in the groups claim, if they do not exist yet locally.

Additionally, a **Groups glob pattern** can be supplied to only sync groups with
specific names (default ``*``, to match all groups).

**NOTE**: The names of the groups in the environment of the OIDC provider must match *exactly*
with the names of the ``Groups`` in Django for this to work.

In order to assign specific Django groups to *every* OIDC authenticated user, the **Default groups** option can be used.

User permissions
----------------

If the **Make users staff** is enabled, *every* OIDC authenticated user will automatically be made a staff user,
allowing them to login to the admin interface.

In order to promote OIDC authenticated users to superusers, the **Superuser group names** option can be used. This
takes a list of group names and will set ``is_superuser`` to ``True`` if an authenticated user
has at least one of these groups in their **Groups claim**. If a user does not have any of these
groups in their **Groups claim**, ``is_superuser`` will be set to ``False`` for that user.

**NOTE**: if **Superuser group names** is left empty, the superuser status of users will never be altered upon login,
allowing for manual management of superusers.

Claim obfuscation
-----------------

By default, the received claims will be logged when verifying them during the authentication process.
In order to not log information from sensitive claims (identifiers, etc.),
claims can be obfuscated by setting ``OIDCAuthenticationBackend.sensitive_claim_names``
or overriding ``OIDCAuthenticationBackend.get_sensitive_claim_names``.
By default, the configured ``OIDCAuthenticationBackend.config_identifier_field`` will be obfuscated.

Customizing the configuration
-----------------------------

The database-stored configuration class can easily be extended by inheriting from the
``OpenIDConnectConfigBase`` class and then setting the ``OIDCAuthenticationRequestView.config_class``
and ``OIDCAuthenticationBackend.config_class`` to be this new class.
Please see the hosted `documentation`_ for installation, configuration and usage instructions.

.. |build-status| image:: https://github.com/maykinmedia/mozilla-django-oidc-db/workflows/Run%20CI/badge.svg?branch=master
:target: https://github.com/maykinmedia/mozilla-django-oidc-db/actions?query=workflow%3A%22Run+CI%22+branch%3Amaster
Expand All @@ -300,12 +59,12 @@ and ``OIDCAuthenticationBackend.config_class`` to be this new class.
.. |pypi-version| image:: https://img.shields.io/pypi/v/mozilla_django_oidc_db.svg
:target: https://pypi.org/project/mozilla_django_oidc_db/

.. _mozilla-django-oidc: https://github.com/mozilla/mozilla-django-oidc

.. _mozilla-django-oidc settings documentation: https://mozilla-django-oidc.readthedocs.io/en/stable/settings.html
.. |docs| image:: https://readthedocs.org/projects/mozilla-django-oidc-db/badge/?version=latest
:target: https://mozilla-django-oidc-db.readthedocs.io/en/latest/?badge=latest
:alt: Documentation Status

.. _mozilla-django-oidc documentation: https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html
.. _mozilla-django-oidc: https://github.com/mozilla/mozilla-django-oidc

.. _OpenID Connect specification: https://openid.net/specs/openid-connect-core-1_0.html#ClaimStability

.. _OIDC spec: https://openid.net/specs/openid-connect-discovery-1_0.html#WellKnownRegistry
.. _documentation: https://mozilla-django-oidc-db.readthedocs.io/en/latest/
20 changes: 20 additions & 0 deletions docs/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
1 change: 1 addition & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. include:: ../CHANGELOG.rst
Loading

0 comments on commit c6b33c2

Please sign in to comment.