Skip to content

Commit

Permalink
Merge pull request #1579 from petervarkoly/master
Browse files Browse the repository at this point in the history
Implementing ssl connection for ldap auth
  • Loading branch information
pbiering authored Sep 23, 2024
2 parents fdb014d + e887b06 commit 499b37f
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 4 deletions.
23 changes: 22 additions & 1 deletion DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -834,10 +834,31 @@ Default: `(cn={0})`

##### ldap_load_groups

Load the ldap groups of the authenticated user. These groups can be used later on to define rights.
Load the ldap groups of the authenticated user. These groups can be used later on to define rights. This also gives you access to the group calendars, if they exist.
* The group calendar will be placed under collection_root_folder/GROUPS
* The name of the calendar directory is the base64 encoded group name.
* The group calneder folders will not be created automaticaly. This must be created manualy. [Here](https://github.com/Kozea/Radicale/wiki/LDAP-authentication) you can find a script to create group calneder folders https://github.com/Kozea/Radicale/wiki/LDAP-authentication

Default: False

##### ldap_use_ssl

Use ssl on the ldap connection

Default: False

##### ldap_ssl_verify_mode

The certifikat verification mode. NONE, OPTIONAL or REQUIRED

Default: REQUIRED

##### ldap_ssl_ca_file

The path to the CA file in pem format which is used to certificate the server certificate

Default:

##### lc_username

Сonvert username to lowercase, must be true for case-insensitive auth
Expand Down
11 changes: 10 additions & 1 deletion config
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,16 @@
#ldap_load_groups = True

# The filter to find the DN of the user. This filter must contain a python-style placeholder for the login
#ldap_filter = (&(objectClass=person)(cn={0}))
#ldap_filter = (&(objectClass=person)(uid={0}))

# Use ssl on the ldap connection
#ldap_use_ssl = False

# The certifikat verification mode. NONE, OPTIONAL, default is REQUIRED
#ldap_ssl_verify_mode = REQUIRED

# The path to the CA file in pem format which is used to certificate the server certificate
#ldap_ssl_ca_file =

# Htpasswd filename
#htpasswd_filename = /etc/radicale/users
Expand Down
31 changes: 29 additions & 2 deletions radicale/auth/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,20 @@
# along with Radicale. If not, see <http://www.gnu.org/licenses/>.
"""
Authentication backend that checks credentials with a ldap server.
Following parameters are needed in the configuration
Following parameters are needed in the configuration:
ldap_uri The ldap url to the server like ldap://localhost
ldap_base The baseDN of the ldap server
ldap_reader_dn The DN of a ldap user with read access to get the user accounts
ldap_secret The password of the ldap_reader_dn
ldap_filter The search filter to find the user to authenticate by the username
ldap_load_groups If the groups of the authenticated users need to be loaded
Following parameters controls SSL connections:
ldap_use_ssl If the connection
ldap_ssl_verify_mode The certifikat verification mode. NONE, OPTIONAL, default is REQUIRED
ldap_ssl_ca_file
"""
import ssl

from radicale import auth, config
from radicale.log import logger
Expand All @@ -36,6 +42,9 @@ class Auth(auth.BaseAuth):
_ldap_filter: str
_ldap_load_groups: bool
_ldap_version: int = 3
_ldap_use_ssl: bool = False
_ldap_ssl_verify_mode: int = ssl.CERT_REQUIRED
_ldap_ssl_ca_file: str = ""

def __init__(self, configuration: config.Configuration) -> None:
super().__init__(configuration)
Expand All @@ -55,6 +64,15 @@ def __init__(self, configuration: config.Configuration) -> None:
self._ldap_load_groups = configuration.get("auth", "ldap_load_groups")
self._ldap_secret = configuration.get("auth", "ldap_secret")
self._ldap_filter = configuration.get("auth", "ldap_filter")
if self._ldap_version == 3:
self._ldap_use_ssl = configuration.get("auth", "ldap_use_ssl")
if self._ldap_use_ssl:
self._ldap_ssl_ca_file = configuration.get("auth", "ldap_ssl_ca_file")
tmp = configuration.get("auth", "ldap_ssl_verify_mode")
if tmp == "NONE":
self._ldap_ssl_verify_mode = ssl.CERT_NONE
elif tmp == "OPTIONAL":
self._ldap_ssl_verify_mode = ssl.CERT_OPTIONAL

def _login2(self, login: str, password: str) -> str:
try:
Expand Down Expand Up @@ -98,7 +116,16 @@ def _login3(self, login: str, password: str) -> str:
"""Connect the server"""
try:
logger.debug(f"_login3 {self._ldap_uri}, {self._ldap_reader_dn}")
server = self.ldap3.Server(self._ldap_uri)
if self._ldap_use_ssl:
tls = self.ldap3.Tls(validate=self._ldap_ssl_verify_mode)
if self._ldap_ssl_ca_file != "":
tls = self.ldap3.Tls(
validate=self._ldap_ssl_verify_mode,
ca_certs_file=self._ldap_ssl_ca_file
)
server = self.ldap3.Server(self._ldap_uri, use_ssl=True, tls=tls)
else:
server = self.ldap3.Server(self._ldap_uri)
conn = self.ldap3.Connection(server, self._ldap_reader_dn, password=self._ldap_secret)
except self.ldap3.core.exceptions.LDAPSocketOpenError:
raise RuntimeError("Unable to reach ldap server")
Expand Down
12 changes: 12 additions & 0 deletions radicale/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,18 @@ def json_str(value: Any) -> dict:
"value": "False",
"help": "load the ldap groups of the authenticated user",
"type": bool}),
("ldap_use_ssl", {
"value": "False",
"help": "Use ssl on the ldap connection",
"type": bool}),
("ldap_ssl_verify_mode", {
"value": "REQUIRED",
"help": "The certifikat verification mode. NONE, OPTIONAL, default is REQUIRED",
"type": str}),
("ldap_ssl_ca_file", {
"value": "",
"help": "The path to the CA file in pem format which is used to certificate the server certificate",
"type": str}),
("strip_domain", {
"value": "False",
"help": "strip domain from username",
Expand Down

0 comments on commit 499b37f

Please sign in to comment.