Skip to main content

SAML authentication for plone sites

Project description

wcs.samlauth

wcs.samlauth is a saml authentication plugin based on python3-saml for plone 6. It turns your plone site into a SP (Service Provider). IDP (Identity Provider) is not supported.

The package is tested with plone 6.x and python 3.11/3.12. It does not officially support other versions.

Goal

Make it as easy as possible to configure plone as a SP (Service Provider), without having a in depth knowledge of SAML and how it works under the hood. This package uses the high level API of python3-saml, which makes it easy to configure and use.

TL;DR

  1. Install wcs.samlauth plugin
  2. Add PAS plugin via ZMI (in acl_users)
  3. Go to http://localhost:8080/Plone/acl_users/saml/idp_metadata
  4. Fetch or upload IDP metadata -> Click "Get and store metadata"
  5. Go to http://localhost:8080/Plone/acl_users/saml/metadata and configure your IDP
  6. Use http://localhost:8080/Plone/acl_users/saml/sls to login via IDP

Architecure

The plugin is based on a similar architecture/concept as pas.plugins.oidc. It basically means that all endpoints are directly on the plugin. The plugin does not override plones login/logout views. This is up to you. If you only have one saml plugin it's possible to enable the Challenge plugin, which redirects to the saml login endpoint.

This enables you to add multiple saml plugins as well.

Dependecies:

See python3-saml Make especially sure the following packages can be installed, since the have some system dependencies as well:

For example, on a recent Ubuntu, you should run:

apt install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl

Endpoints

Given the ID of the SAML plugin is "saml":

Features

  • Fetch and store IDP metadata via IDP metadata endpoint
  • Upload and store IDP metadata via file upload
  • Multiple saml plugins at the same time
  • Implements almost everything from python3-saml, this includes SP signing of the AuthnRequest and metadata
  • Create a plone session and/or restapi token
  • Enable/Disable the creation of a plone user
  • Enable/Disable updating user properties (after creation)
  • Automatically updates user data (hardcoded, currently limited to email and fullname)
  • Enable/Disable the validation of authn requests (Uses temporarly a __saml cookie)
  • Prevent Redirect attacks, by validating the RelayState parameter and a and an "allowed" list of domains, where we can redirect to
  • E2E tests with Keykloak as IDP in different configuration variations
  • Manually tested with Azure AD as IDP
  • Documentation use azure and keycloak as IDP
  • Configure attribute mapping via ISAMLUserPropertiesMutator adapters.
  • Expose generated api token via redirect url (Potential security risk, only use it if you know what you are doing).

Installation

Add plugin to your buildout

[buildout]

...

eggs =
    wcs.samlauth

Add wcs.samlauth to plone docker image

$ docker run -p 8080:8080 -e SITE="mysite" -e ADDONS="wcs.samlauth" plone

From the ZMI go to acl_users and add the saml plugin.

Development

It's best to use a local IDP, for example keycloak in order to make changes to this package.

Start a local keycloak server using docker:

$ docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:22.0.2 start-dev

Install and run a test plone instance:

$ git clone git@github.com:webcloud7/wcs.samlauth.git && cd wcs.samlauth
$ make install
$ make run

Custom attribute mapping

With version 1.1.0 wcs.samlauth now supports the mapping of custom saml attributes to plone user properties.

Example:

from wcs.samlauth.interfaces import ISAMLUserPropertiesMutator
from wcs.samlauth.plugin import ISamlAuthPlugin
from wcs.samlauth.utils import make_string
from zope.component import adapter
from zope.interface import implementer
from zope.interface import Interface


@implementer(ISAMLUserPropertiesMutator)
@adapter(ISamlAuthPlugin, Interface)
class PhoneUserPropertiesMutator:

    _order = 2

    def __init__(self, plugin, request):
        self.plugin = plugin
        self.request = request

    def mutate(self, user, userinfo, properties):
        if "Phone" in userinfo:
            properties["phone"] = make_string(userinfo["Phone"])

ZCML:

<adapter factory="PhoneUserPropertiesMutator"/>

A default adapter, which supports mapping email and fullname is registered by the plugin. Any other attributes need to be implemented via custom adapters.

You can register multiple adapters and you can also override the values given by the default adapter. Just make sure _order attribut on the adapter is higher than 1.

Test

You need a local docker installation to run tests.

The package provides a docker test layer, which spins up keycloak and loads various configuration files into keycloak.

$ make test

Run individual tests:

$ ./bin/test -t test_whatever

HowTo's

The tests/assets folder contains some keycloak configurations you can use for your test setup. It inclues examples with SP signed autn requests and metadata.

The examples below do not use this specific saml feature which is required by most IDP.

Manuall configuiration

You can configure everythin manully as well. Please see the python3-saml documentation for details

The configuration needs to be applied directly on the property tab of the saml plugin.

Configure with keycloak as IDP

For both create a new saml pas plugin via ZMI in acl_users

IDP part on keycloak

  1. Login to your Keycloak admin console.

  2. Create a new realm or use one that's already there. If not there create a test user.

  3. With the data from http://localhost:8080/Plone/acl_users/saml/metadata create a new Client.

    Client type is SAML.

    Important note here: The client ID is identical to the SAML EntityID For example http://localhost:8080/keycloak/acl_users/saml/metadata

    Create keycloak client

    Click "next"

  4. Configure Home URL and Valid redirect URLs

    Configure keycloak

    Click "Save"

  5. Go to "Keys" tab and disable "Client signature required"

    Disable signing

  6. Configure attribute bindings

    Unter "Client scopes" click on URL which ends with /metadata-dedicated

    Disable signing

    Click on "Add predefined mapper"

    Chose the following mappers Disable signing

    Click "Add"

  7. Go to the Advance tab and configure the logout service redirect binding (python3-saml only supports the redirect binding here)

    Configure keycloak advanced

  8. Copy the metadataa saml config URL

    copy url

SP part on your Plone site

  1. Go to URL: http://localhost:8080/Plone/acl_users/saml/idp_metadata

    Enter the Url and Click on "Get and store metadata"

    copy url

    Hints: Keycloak has authnRequestsSigned: true hardcoded.

THATS IT!! Go To http://localhost:8080/Plone/acl_users/saml/sls to login via azure

If this is the only saml plugin on your site and want all users to login via saml, then you can enable the Challenge Plugin and change the login and logout actions on your plone site to use the saml endpoints.

Configure with Azure as IDP

This is a tutorial how to configure an azure cloud enterprise app as IDP for this plugin.

IDP part on azure cloud

  1. Go to your azure AD and create a new enterprise app.

    Create azure enterprise app

  2. Go to the "Single Sign on" section.

    SSO section

  3. Add SAML authentification to app.

    Add SAML

  4. Gather the metadata from the SAML plugin.

    URL: http://localhost:8080/Plone/acl_users/saml/metadata

    Get metadata

  5. Manually edit "Basic SAML Configuration" (Info's can be taken from the SP metadata xml)

    Add EntityID and ACS. Optionally also add the Logout URL. Azure wants https there, so depending on your setup just leave it blank.

    Edit basic saml

  6. Edit "Attributes & Claims"

    The plugin only supports the email address, given name and surename You can configure more attributes, but they will be ignored.

    Important: The clame names need to be givenName, surename and email. Also remove the namespace and leave empty.

    Edit attrs

  7. Download Federation metadata XML

    Download metadata

SP part on your Plone site

  1. Go to URL: http://localhost:8080/Plone/acl_users/saml/idp_metadata

    Upload and store configuration from IDP (azure)

    Upload xml

  2. The upload form also shows you what information has been gathered from the Metadata XML and what will be stored in your saml plugin

    Info xml

THATS IT!! Go To http://localhost:8080/Plone/acl_users/saml/sls to login via azure

If this is the only saml plugin on your site and want all users to login via saml, then you can enable the Challenge Plugin and change the login and logout actions on your plone site to use the saml endpoints.

Changelog

1.3.0 (2026-01-29)

  • Update package metadata. [mathias.leimgruber]

1.3.0b1 (2026-01-28)

  • Fire UserLoggedInEvent [mathias.leimgruber]

1.3.0a2 (2025-11-13)

  • Fix native namespace and build of module. [mathias.leimgruber]

1.3.0a1 (2025-11-12)

  • Move to native namespaces [mathias.leimgruber]
  • BugFix: Fix updating user properties when user already exists. [mathias.leimgruber]
  • Feature: Updating user properties can now be disabled by setting the "update_user" flag to "False" in the plugin settings. [mathias.leimgruber]

1.2.0 (2025-05-19)

  • Add option to expose api token via redirect URL. [mathias.leimgruber]

1.1.0 (2025-05-02)

  • Add ISAMLUserPropertiesMutator interface to allow custom user properties. [mathias.leimgruber]

1.0.0 (2025-04-24)

  • Update classifiers and make official first stable release. [mathias.leimgruber]

1.0.0b1 (2024-11-01)

  • Support Plone 6.1 and Python 3.12. [mathias.leimgruber]

1.0.0a4 (2024-02-20)

  • Do not use SCRIPT_NAME for the callback URL. [mathias.leimgruber]

1.0.0a3 (2023-09-28)

  • Fix typo for boolean property. [mathias.leimgruber]

1.0.0a2 (2023-09-28)

  • Disable csrf protection on acs (callback view). [mathias.leimgruber]

1.0.0a1 (2023-09-28)

  • Init release [mathias.leimgruber]

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wcs_samlauth-1.3.0.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wcs_samlauth-1.3.0-py3-none-any.whl (100.5 kB view details)

Uploaded Python 3

File details

Details for the file wcs_samlauth-1.3.0.tar.gz.

File metadata

  • Download URL: wcs_samlauth-1.3.0.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for wcs_samlauth-1.3.0.tar.gz
Algorithm Hash digest
SHA256 14e527e0e534c3c8b8357513811e6ae1f447c40de7eab03461fb1197441e6d40
MD5 a03be7ac803d67080c9210a560c022a7
BLAKE2b-256 65b32bc0153106dac5494ae10e929191d0f11a1429e619a36a22767914ac7776

See more details on using hashes here.

File details

Details for the file wcs_samlauth-1.3.0-py3-none-any.whl.

File metadata

  • Download URL: wcs_samlauth-1.3.0-py3-none-any.whl
  • Upload date:
  • Size: 100.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.8

File hashes

Hashes for wcs_samlauth-1.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ab3b3c982daf1c4095ddc038afc5d47e197043c08e636a042ee8e9b6cfc94906
MD5 34115e619315aa6a25de22ec43351835
BLAKE2b-256 c182ca02141cc686e8b1404a151488df0720f2ac37e986f7dec12c3c0454ea20

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page