Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

All: Add SAML support #11865

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from

Conversation

ttcchhmm
Copy link

This PR adds SAML support to Joplin.

Server

Based on the samlify library that provides the SAML logic flow for Joplin Server.

This adds the following environment variables used as configuration parameters to Joplin Server :

  • SAML_ENABLED: If set to true, enables SAML support.
  • DISABLE_BUILTIN_LOGIN_FLOW: If set to true, all auth requests MUST go though SAML. Users can't log-in using Joplin-specific credentials and/or LDAP.
  • SAML_IDP_CONFIG_FILE: Should be a path to an XML file containing the metadata for the Identity Provider (IDP).
  • SAML_SP_CONFIG_FILE: Should be a path to an XML file containing the metadata for the Service Provider (SP, in this case Joplin).
  • SAML_ORGANIZATION_DISPLAY_NAME: Name of the organization, as shown on the log-in screen. Optional.

The XML files are standard SAML IDP/SP metadata that should be created by the identity solution.

Clients

As for the clients themselves, no additional libraries are needed, since the actual log-in process is happening in a web browser, outside of Joplin itself.

It also adds a new sync target, based on the one for Joplin Server: "Joplin Server (Beta, SAML)". We kept "Beta" in the name for this since the main Joplin Server target itself is currently considered as such.

Important

The log-in flow uses a callback to a joplin:// URL, and thus requires that only one instance of Joplin is running at any given time. This is important for the desktop client, since the single instance lock is not enforced in the dev environment.

Log-in flow

The log-in process differs slightly if started from within a client or within the server web interface.

    graph TB;
        12([From the server web interface]) --> 13[The user clicks 'Sign-in using your organization account']

        13 --> 5

        0([From a client]) --> 1

        1[The user chooses the SAML sync target] --> 2[They enter the server's address]
        2 --> 3[They click 'Sign-in using your organization account']
        3 --> 4[The Joplin client opens the default web browser to an URL pointing to Joplin Server]
        4 --> 5[Joplin Server reads its configuration and redirects the browser to the Identity Provider sign-in page]
        5 --> 6[The user signs-in]
        6 --> 7[The Identity Provider generates and signs a SAML payload, and redirects the browser to Joplin Server]
        7 --> 8[Joplin Server validates the payload signature]

        8 -- Client --- 9[If the signature is valid, Joplin Server creates a new token for this user]
        9 --> 10[Using a joplin:// URL, the browser calls back into the client, with the new token]

        8 -- Server web interface --- 11[If the signature is valid, a new session is created]
Loading

Testing and development

For development purposes, we used saml-idp as the Identity Provider, as it allows to quickly create new users on the fly and is simple to set up. After generating the keypair (look at the saml-idp documentation to see how), just running npx saml-idp --acsUrl 'http://localhost:22300/api/saml' --audience http://localhost:22300 --issuer 'saml-idp' is enough to get a test Identity Provider running, assuming that Joplin Server is running on localhost:22300.

Since saml-idp does not support generating SP metadata, here is a sample configuration for the Service Provider part :

<?xml version="1.0"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
                     validUntil="2024-12-15T08:05:25Z"
                     cacheDuration="PT604800S"
                     entityID="Joplin">
    <md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
        <md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                                     Location="http://localhost:22300/api/saml"
                                     index="1" />
    </md:SPSSODescriptor>
</md:EntityDescriptor>

This is due to changes in the lib package caused by adding SAML support. Currently, the CLI does not support SAML auth, this only fixes regular Joplin Server sync.
Copy link
Contributor

github-actions bot commented Feb 20, 2025

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@ttcchhmm
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

github-actions bot added a commit that referenced this pull request Feb 20, 2025
@laurent22
Copy link
Owner

Thanks for creating this pull request! At the moment it has some issues related to the linter, which you should be able to fix by running yarn linter ./ from the root. Would you mind fixing this so that CI passes? As it's a large PR it might take a while before we can review it but as a first step it would help if it doesn't have any CI error

@ttcchhmm
Copy link
Author

I fixed the issues related to the linter.

However, the server image does not build since the XML schema validator (@authenio/samlify-xsd-schema-validator) has a dependency on a Java environment that is missing in the CI. If needed I can replace this dependency with something else since samlify supports several validators, but this validator is the one recommended in the samlify README file, so I hope this is not an issue?

@laurent22
Copy link
Owner

Hmm, if it's just to validate an XML schema I guess it's not worth adding a Java dependency? From their doc it looks like there's a TypeScript package too?

xsd-schema-validator is replaced with xmllint-wasm, to remove any dependency to another program
@ttcchhmm
Copy link
Author

I got rid of the Java dependency, and replaced the schema validator with @authenio/samlify-xmllint-wasm, which doesn't require any native code. This allows the server image to build.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants