The way were were doing it was implicitly sorting the query items and it
was causing millions of items to be sorted (even though the result should
only have one) making it slow.
By switching away from `get()` and `first()` we are telling django to
not try to sort.
This commit adds code to allow users that prefer to do user management
via LDAP to do so. Since Etebase does not store the password (proof) in
a LDAP compatible fashion, we compromise and instead two checks: One while
registering an account to see if the username is the LDAP directory and
one whenever the API is accessed. To prevent too many LDAP requests, the
result of the request is cached for an configurable amount of hours.
Make sure you have python-ldap installed and can successfully import
ldap. Then, if you use the easy config, add the following to your
config:
```
; [...]
; Regular etesync configuration
[ldap]
bind_dn = <Your LDAP "user" to bind as. See Note 1>
bind_pw = <The password to authenticate as your bind user>
; Or if you have the password in a file:
; bind_pw_file = /path/to/the/file.txt
server = <The URL to your LDAP server>
search_base = <Your search base>
filter = <Your LDAP filter query. See Note 2>
; In case a cache TTL of 1 hour is too short for you, set `cache_ttl` to
the preferred
; amount of hours a cache entry should be viewed as valid:
; cache_ttl = 5
```
With this config, I am able to make the EteSync server check with my
LDAP server if a user should be able to login or register.
Note that if a user is allowed to login or register, the password of the
LDAP user will be ignored. This LDAP patch is nothing more than an
additional check before the actual authentication.
A successful LDAP check will be cached, if not configured (correctly),
for one hour, after which the LDAP query will be performed again.
Note 1: This commit only works with a bind user
Note 2: The query must be specified. If an LDAP query returns more than
one or no result, then the authentication fails. If your query needs to
include the username that currently tries to perform a login or
registration, you can use %%s, which will be subsituted for the used
username.
This is quite a big one, so it probably makes sense to review it commit-by-commit (there shouldn't be any overlap).
Summarized:
- The `etebase_fastapi` module was moved to `etebase_server.fastapi`
- The `myauth` module was moved to `etebase_server.myauth`
- The `django_etebase` module was moved to `etebase_server.django`
- The `templates/` directory was moved into `etebase_server/`
- A `setup.py` was added to allow packaging the `etebase_server` module as a python package.
From the source:
> The providing_args argument is deprecated. As it is purely
> documentational, it has no replacement. If you rely on this
> argument as documentation, you can move the text to a code
> comment or docstring.
self.redis isn't None, it's actually unset, so accessing it results
in an exception:
```
ERROR: Traceback (most recent call last):
File "./.venv/lib/python3.9/site-packages/starlette/routing.py", line 624, in lifespan
await receive()
File "./.venv/lib/python3.9/site-packages/starlette/routing.py", line 521, in __aexit__
await self._router.shutdown()
File "./.venv/lib/python3.9/site-packages/starlette/routing.py", line 608, in shutdown
await handler()
File "./etebase_fastapi/main.py", line 72, in on_shutdown
await redisw.close()
File "./etebase_fastapi/redis.py", line 18, in close
if self.redis is not None:
AttributeError: 'RedisWrapper' object has no attribute 'redis'
```
This one is to fix my own PR #125, the requirement files contained the following sentence:
"To update, run: pip-compile --output-file=requirements.txt requirements.in/base.txt"
But that was misleading, after reading pip-tools documentation I found that
"If pip-compile finds an existing requirements.txt file that fulfils the dependencies then no changes will be made, even if updates are available."
That was my mistake, generated the files again and made new builds using python 3.10 that worked as expected. Once again sorry for the mistake!