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

Server: Added ldap authentication #9150

Merged
merged 7 commits into from
Nov 8, 2023

Conversation

marcorombach
Copy link
Contributor

@marcorombach marcorombach commented Oct 27, 2023

This provides the option to use up to two LDAP directories as authentication source for Joplin Server.
If activated user also will be created on the fly if LDAP authentication was successful.
The mail address is used to search the user in the directories.

Following ENV variables are available to configure the LDAP authentication:

LDAP_1_ENABLED=false
LDAP_1_USER_AUTO_CREATION=true
LDAP_1_HOST='' // ldap server in following format ldap(s)://servername:port
LDAP_1_MAIL_ATTRIBUTE='mail'
LDAP_1_FULLNAME_ATTRIBUTE='displayName'
LDAP_1_BASE_DN=''
LDAP_1_BIND_DN=''  // used for user search - leave empty if ldap server allows anonymous bind
LDAP_1_BIND_PW='' // used for user search - leave empty if ldap server allows anonymous bind

For a second LDAP server just replace 1 with 2 in the variable name.
BIND_DN and BIND_PW are optional - if not provided, a anonymous bind against the LDAP server will be tried.
MAIL_ATTRIBUTE and FULLNAME_ATTRIBUTE may vary for different LDAP servers, the preset values works for ActiveDirectory.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 27, 2023

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

@marcorombach
Copy link
Contributor Author

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

github-actions bot added a commit that referenced this pull request Oct 27, 2023
Copy link
Owner

@laurent22 laurent22 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @marcorombach, that looks good overall. You'll need to run yarn install and commit because CI is not passing at the moment.

Also would it be possible to add tests for this feature?

packages/server/src/config.ts Outdated Show resolved Hide resolved
packages/server/src/env.ts Outdated Show resolved Hide resolved
packages/server/src/models/UserModel.ts Outdated Show resolved Hide resolved
packages/server/src/models/UserModel.ts Outdated Show resolved Hide resolved
packages/server/src/utils/ldap.ts Outdated Show resolved Hide resolved
packages/server/src/utils/ldap.ts Outdated Show resolved Hide resolved
packages/server/src/utils/ldap.ts Outdated Show resolved Hide resolved
packages/server/src/utils/ldap.ts Outdated Show resolved Hide resolved
packages/server/src/utils/ldap.ts Outdated Show resolved Hide resolved
try {
await client.bind(searchResults.searchEntries[0].dn, password);
} catch (ex) {
return null;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't silence errors in general. Maybe wrap the error like above and rethrow it?

Copy link
Contributor Author

@marcorombach marcorombach Oct 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed it as suggested. But now I remembered why I did it that way.
Now the user will be confronted with an error like "LdapErr: DSID-0c090439 ..."
By returning null the user gets "invalid username or password" which is almost always the cause for throwing an error here.

What would you prefer? Maybe returning null but logging the error message?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general we need to distinguish between user errors and server errors. If the call here is to check the user password, is it possible to look at the exception error and return null if it's an invalid login, and throw an exception if, for example, the server is unreachable? Does the error object has some code attached to it that we could look at for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found the error code for invalid credentials. If an error with this code is thrown, it now will return null and otherwise it will return the error.

@marcorombach
Copy link
Contributor Author

Also would it be possible to add tests for this feature?

Tests would need a mock ldap server like https://www.npmjs.com/package/ldap-server-mock to work.
This should be possible but I'd prefer to implement this at a later time if that's okay, as it will be much work to do this properly.

@laurent22
Copy link
Owner

Implementing a whole mock server would be overkill, but we need at least tests for the login method since this is a very important part of the software. You can do that relatively easily in api/sessions.test.ts and by mocking the ldapLogin call. For example you can make it return a user, or no user, or make it throw an exception, and verify that everything works as expected.

@marcorombach
Copy link
Contributor Author

Implementing a whole mock server would be overkill, but we need at least tests for the login method since this is a very important part of the software. You can do that relatively easily in api/sessions.test.ts and by mocking the ldapLogin call. For example you can make it return a user, or no user, or make it throw an exception, and verify that everything works as expected.

Added some tests, are they sufficient?

@laurent22
Copy link
Owner

It looks good now, thanks for adding the test @marcorombach! There's now a conflict on yarn.lock - would you mind fixing it? You just need to run yarn install and commit the result

@marcorombach
Copy link
Contributor Author

@laurent22 the conflict on yarn.lock is now resolved. Somehow there where changes to supportedLocales.js after running yarn install that where commited. There is a entry in .gitignore, so I don't know why that was commited. I reverted these changes and it seems like everything is ok now.

@laurent22
Copy link
Owner

Ok that's strange, because that file should actually be named supportedLocales.js and it's indeed automatically built. But there's nothing in the codebase about a supportedLanguages.js file. It definitely makes sense to exclude that file in any case. Thanks for making these changes, I'm going to wait for CI to run and I'll merge

@laurent22 laurent22 merged commit f50019d into laurent22:dev Nov 8, 2023
@tompaah
Copy link

tompaah commented Dec 20, 2023

Unable to get this to work with joplin/server:2.13.5-beta in Docker and using Authentik LDAP Outpost.
The LDAP server answers questions correctly using ldapsearch or other LDAP enabled applications.

The web interface says only is an invalid LDAP URL (protocol) in the red error field, nothing more.
Container logs

07:09:11 0|app  | 2023-12-20 07:09:11: LDAP: Starting authentication with Server 
07:09:11 0|app  | 2023-12-20 07:09:11: App: POST /login (500) (23ms)
07:09:11 0|app  | 2023-12-20 07:09:11: App: GET /css/bulma.min.css (200) (106ms)
07:09:11 0|app  | 2023-12-20 07:09:11: App: GET /css/fontawesome/css/all.min.css (200) (81ms)
07:09:11 0|app  | 2023-12-20 07:09:11: App: GET /js/jquery.min.js (200) (28ms)
07:09:11 0|app  | 2023-12-20 07:09:11: App: GET /css/main.css (200) (95ms)
07:09:11 0|app  | 2023-12-20 07:09:11: App: GET /js/main.js (200) (29ms)
07:09:11 0|app  | 2023-12-20 07:09:11: App: GET /images/server_logo.png (200) (26ms)
07:09:11 0|app  | 2023-12-20 07:09:11: App: GET /images/icons/server/manifest.webmanifest (200) (12ms)

Docker stack environment variables for LDAP are

      - LDAP_1_ENABLED=true
      - LDAP_1_CREATE_USER=false
      - LDAP_1_SERVER=ldap://192.168.xx.xx:389
      - LDAP_1_MAIL_ATTRIBUTE='mail'
      - LDAP_1_FULLNAME_ATTRIBUTE='displayName'
      - LDAP_1_BASE_DN='dc=xxxx,dc=xxxxx,dc=xxx'
      - LDAP_1_BIND_DN='cn=xxxxxx,ou=users,DC=xxxx,DC=xxxxx,DC=xxx
      - LDAP_1_BIND_PW='xxx'

Is there any way of enabling extended debug/error logging? Right now the only clue is that it appears to have problem with the LDAP_1_SERVER url but not idea as to why. Tried having the variable in single, double quotes or no quotes, this makes no difference.

@marcorombach
Copy link
Contributor Author

Seems like you took the env vars from my initial PR comment. These are not the final variable names. I'll try to edit this comment.

In the meanwhile you can find the correct variables including a brief description in this file: https://github.com/laurent22/joplin/blob/dev/packages/server/src/env.ts#L111

@tompaah
Copy link

tompaah commented Dec 20, 2023

Seems like you took the env vars from my initial PR comment. These are not the final variable names. I'll try to edit this comment.

In the meanwhile you can find the correct variables including a brief description in this file: https://github.com/laurent22/joplin/blob/dev/packages/server/src/env.ts#L111

Thank you for the help and your contribution to the code, it's working now with the correct variable names. 😊

@marcorombach
Copy link
Contributor Author

You're welcome! Glad it works for you now :)

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.

3 participants