Skip to content

Commit

Permalink
doc changes for SAML auth (ex Microsoft IdP)
Browse files Browse the repository at this point in the history
  • Loading branch information
pbartusch committed Oct 23, 2023
1 parent 303b8b4 commit 0eecf70
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 131 deletions.
147 changes: 78 additions & 69 deletions docs/source/smui/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,6 @@ The following settings are optional and define the general SMUI behaviour:
* - ``toggle.predefined-tags-file``
- Path to optional file, that provides pre-defined rule tags (see “Configure predefined rule tags”).
-
* - ``smui.auth.ui-concept.simple-logout-button-target-url``
- Target URL of simple logout button (see "Configure Authentication").
-
* - ``toggle.activate-spelling``
- Activate spelling items: Add spelling items to maintain common misspellings using the Querqy replace rewriter. The spelling items are exported in a separate replace_rules.txt that is uploaded to Solr.
- ``false``
Expand Down Expand Up @@ -305,96 +302,108 @@ The links are rendered using the magic ``$QUERY`` symbol in the URL template.
Authentication
--------------

SMUI is shipped with HTTP Basic and JWT Authentication support.
In version 4 SMUI has dropped support for its proprietary authentication implementation and adopted the
`pac4j <https://www.pac4j.org/>`_ library. pac4j offers a wide range of authentication and authorization mechanisms.
At the moment, only SAML authentication is provided (tested against MS Azure AD / Entra, other SAML identity
providers should work) but additional authentication mechanisms can be added quickly. Please
`create a Github issue <https://github.com/querqy/smui/issues/new/choose>`_, a
`pull request <https://github.com/querqy/smui/compare>`_, or
`drop us an email <[email protected]>`_.


Basic Authentication
SAML Authentication
~~~~~~~~~~~~~~~~~~~~

This is telling every controller method (Home and ApiController) to use
the according authentication method as well as it tells SMUI’s
``BasicAuthAuthenticatedAction`` username and password it should use.
Basic Auth can be turned on in the extension by configuring an
``smui.authAction`` in the config file, e.g.:
Enabling SAML authentication requires a few steps of preparation. We describe the steps below using Microsoft Entra
(ex Azure Active Directory) as the Identity Provider (IdP).

::
First, create a new SMUI application in your IdP. In MS Entra this can be achieved in the `Application` /
`Enterprise Applications` / `New application` dialogue. You will create a new "non-gallery" application.

# For Basic Auth authentication, use SMUI's BasicAuthAuthenticatedAction (or leave it blanked / commented out for no authentication), e.g.:
smui.authAction = controllers.auth.BasicAuthAuthenticatedAction
smui.BasicAuthAuthenticatedAction.user = smui_user
smui.BasicAuthAuthenticatedAction.pass = smui_pass
.. figure:: smui_saml_1.png
:alt: MS Entra Configuration: New Application

**WARNING:** Deprecated as of v3.14. BasicAuth support will be removed soon (see `github.com comment on PR#83 <https://github.com/querqy/smui/pull/83#issuecomment-1023284550>`_).
Second, enable SAML Single sign-on for SMUI. In MS Entra this is done by Selecting the SAML option in the
`Manage` / `Single sign-on` menu of your newly created application.

JWT Authentication
~~~~~~~~~~~~~~~~~~
.. figure:: smui_saml_2.png
:alt: MS Entra Configuration: Enable SAML SSO for the new application

::
Third, assign an entity ID to your new application. This identifier is also called the `Audience Restriction`
or `Audience URI` in other identity providers. In MS Entra this is configured in the `Single sign-on` section of your
newly created application. There, the `Basic SAML Configuration` sub-section's `Identifier (Entity ID)` entry should
contain the ID. There is `some recommendation <https://spaces.at.internet2.edu/display/federation/saml-metadata-entityid>`_
to use a URI for SAML entity IDs but in general any globally unique identifier will work.

smui.authAction="controllers.auth.JWTJsonAuthenticatedAction"
.. figure:: smui_saml_3.png
:alt: MS Entra Configuration: Configure identifier (the SAML entity ID) for the new application, add Reply URL

.. list-table:: SMUI advanced application settings
:widths: 20 50 30
:header-rows: 1
Fourth, configure your IdP to return your browser back to a SMUI callback endpoint after successful authentication.
In MS Entra, this happens in the same section as above with the `Reply URL (Assertion Customer Service)` setting.
Here you will need to use your SMUI host's URL appended with `/callback?client_name=SAML2Client`. Please note, that
SAML requires this to be a HTTPS URL. Example: `https://smui.intranet.mycompany.com/callback?client_name=SAML2Client`

* - Config key
- Description
- Default
* - ``smui.JWTJsonAuthenticatedAction.login.url``
- The URL to the login page (e.g. https://loginexample.com/login.html?callback=https://redirecturl.com)
-
* - ``smui.JWTJsonAuthenticatedAction.cookie.name``
- Name of cookie that contains the Json Web Token (JWT)
- ``jwt_token``
* - ``smui.JWTJsonAuthenticatedAction.public.key``
- The public key to verify the token signature.
-
* - ``smui.JWTJsonAuthenticatedAction.algorithm``
- The algorithms that should be used for decoding (options: ‘rsa’, ‘hmac’, ‘asymmetric’, ‘ecdsa’)
- ``rsa``
* - ``smui.JWTJsonAuthenticatedAction.authorization.active``
- Activation of authorization check
- ``false``
* - ``smui.JWTJsonAuthenticatedAction.authorization.json.path``
- The JSON path to the roles saved in the JWT
- ``$.roles``
* - ``smui.JWTJsonAuthenticatedAction.authorization.roles``
- Roles (comma separated) of roles, that are authorized to access SMUI
- ``admin``
Fifth, prepare the identity provider's metadata XML. This includes required signatures and SSO URL configurations
and follows a standard format. In MS Entra you can download the `Federation Metadata XML` in the
`SAML Certificates Section` of the application's Single sign-on configuration dialog. For pac4j only the
`Signature` and `IDPSSODescriptor` elements in the XML are used and you would need to remove (!) additional XML
`RoleDescriptor` elements as we had issues with pac4j complaining about unexpected elements.

Example of decoded Json Web Token:
Sixth, assign users and/or groups to that new application to enable your users to allow authenticating your SMUI users
against this new application.

.. code:: json
.. figure:: smui_saml_4.png
:alt: MS Entra Configuration: Assign users/groups to the application

{
"user": "Test Admin",
"roles": [
"admin"
]
}
After the above steps you are able to run SMUI with enabled SAML authentication with the following environment variables:

Logout
~~~~~~
::

In this setup, SMUI can provide a simple logout button that simply sends
the user to a configured target URL:
# This triggers SMUI to use the SAML2Client
SMUI_AUTH_CLIENT=SAML2Client

::
# This sets the SMUI base URL, required for callbacks etc.
# Should just be the protocol+hostname+port you run SMUI on
SMUI_AUTH_BASEURL=https://<add-you-host-here>

smui.auth.ui-concept.simple-logout-button-target-url="https://www.example.com/logoutService/"
# The SAML entity ID configured in step three above
SMUI_SAML_SERVICE_PROVIDER_ENTITY_ID=<unique-configured-id>

Custom Authentication
~~~~~~~~~~~~~~~~~~~~~
# Path to the identity provider metadata XML obtained in step five above
SMUI_SAML_IDENTITY_PROVIDER_METADATA_PATH=/path/to/idp.xml

You can also implement a custom authentication action and tell SMUI to
decorate its controllers with that, e.g.:
# Path to a keystore for a public/private key pair that SMUI uses to sign SAML messages.
# If it does not exist it is created during SMUI startup
SMUI_SAML_KEYSTORE=/tmp/smui_saml_keystore.jks

::
# The password to the keystore above. It needs to match the actual keystore password
# if an existing keystore is provided, otherwise it will be the password SMUI uses
# when creating the new keystore file.
SMUI_SAML_KEYSTORE_PASSWORD=keystore-password

smui.authAction = myOwnPackage.myOwnAuthenticatedAction
# The password to the private key within the keystore. It needs to match the actual
# private key password if an existing keystore is provided, otherwise it will be the
# password SMUI uses when creating the new keystore file.
SMUI_SAML_PRIVATE_KEY_PASSWORD=private-key-password

# SMUI will generate an XML file for its own metadata and post that during the SAML
# authentication process. This is the path where this file will be stored. Please note,
# that you might need to manually delete this file if you change any of the above configuration.
SMUI_SAML_SERVICE_PROVIDER_METADATA_PATH=/tmp/smui_sp_metadata.xml

# SMUI will store authenticated user info in a browser cookie. You can set the maximum
# duration of this session before requiring re-authentication using this value.
SMUI_SESSION_MAXAGE=1 day


Session and Logout
~~~~~~~~~~~~~~~~~~~~

See :ref:`Developing Custom Authentication<smui-dev-custom-auth>` for details.
An authenticated user will stay logged in as long as their cookie is valid (see ``SMUI_SESSION_MAXAGE` value above).
As we currently only support external authentication there is currently no active logout implemented (any logout
would immediately redirect to the identity provider and, if the session with the identity provider still exists,
re-login the user).
.. _smui-rules-deployment-details:
Options for rules deployment
----------------------------
Expand Down
71 changes: 9 additions & 62 deletions docs/source/smui/dev-setup.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,15 @@ Here are some frequently used command:

.. _smui-dev-config:

Running SMUI with SSL locally
-----------------------------

For local development that requires accessing SMUI using a HTTPS URL (e.g. to implement external authentication)
we recommend using the Caddy reverse proxy.

::
caddy reverse-proxy --internal-certs --from https://localhost --to :9000

Development configuration
-------------------------

Expand Down Expand Up @@ -206,68 +215,6 @@ Note: Setting the MySQL root password is only for making potential root access e

Also note: When developing with an Apple Silicon (M1 based) device, there does not seem to exist a suitable arm image for MySQL (as of Jan 2022). Therefore, the x86 architecture needs to be specified explicitly: ``docker run --platform linux/x86_64 --name smui-mysql [...]``

Developing Custom Authentication
--------------------------------

Authentication Backend
~~~~~~~~~~~~~~~~~~~~~~

If you want to extend SMUI’s authentication behaviour, you can do so by
supplying your own authentication implementation into the classpath of
SMUI’s play application instance and referencing it in the
``application.conf``. Your custom authentication action offers a maximum
of flexibility as it is based upon play’s ``ActionBuilderImpl``. In
addition your custom action gets the current environment’s
``appConfig``, so it can use configurations defined there as well.
Comply with the following protocol:

::

import play.api.Configuration
import play.api.mvc._
import scala.concurrent.ExecutionContext
class myOwnAuthenticatedAction(parser: BodyParsers.Default,
appConfig: Configuration)(implicit ec: ExecutionContext) extends ActionBuilderImpl(parser) {
override def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
...
}

As an example implementation, you can check `BasicAuthAuthenticatedAction.scala`_ as well.

.. _BasicAuthAuthenticatedAction.scala: https://github.com/querqy/smui/blob/master/app/controllers/auth/BasicAuthAuthenticatedAction.scala

**WARNING:** Deprecated as of v3.14. BasicAuth support will be removed soon (see `github.com comment on PR#83 <https://github.com/querqy/smui/pull/83#issuecomment-1023284550>`_).

Frontend Behaviour for Authentication
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Angular frontend comes with a built-in HTTP request authentication
interceptor. Every API request is observed for returned 401 status
codes. In case the backend returns 401, the backend can pass an
behaviour instruction to the frontend by complying with spec defined by
``SmuiAuthViolation`` within `http-auth-interceptor.ts`_, e.g.:

.. _http-auth-interceptor.ts: https://github.com/querqy/smui/blob/master/app/assets/app/helpers/http-auth-interceptor.ts

::

{
"action": "redirect",
"params": "https://www.example.com/loginService/?urlCallback={{CURRENT_SMUI_URL}}"
}

.. note::

The authentication interceptor only joins the game, in case the
Angular application is successfully bootstrapped. So for SMUI’s ``/``
route, your custom authentication method might choose a different
behaviour (e.g. 302).

Within exemplary ``redirect`` action above, you can work with the
``{{CURRENT_SMUI_URL}}`` placeholder, that SMUI will replace with its
current location as an absolute URL before the redirect gets executed.
Through this, it becomes possible for the remote login service to
redirect back to SMUI once the login has succeeded.

Developing git deployment method
--------------------------------
Expand Down
Binary file added docs/source/smui/smui_saml_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/smui/smui_saml_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/smui/smui_saml_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/smui/smui_saml_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 0eecf70

Please sign in to comment.