8000 fix/ldap_anonymous_bind by tpw56j · Pull Request #2831 · cobbler/cobbler · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

fix/ldap_anonymous_bind #2831

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

Merged
merged 17 commits into from
Dec 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cobbler.spec
Original file line number Diff line number Diff line change
Expand Up @@ -234,9 +234,9 @@ Requires: python%{python3_pkgversion}-distro
Requires: python%{python3_pkgversion}-schema
Requires: %{py3_module_file}
%if 0%{?suse_version}
Recommends: python%{python3_pkgversion}-ldap3
Recommends: python%{python3_pkgversion}-ldap
%else
Requires: python%{python3_pkgversion}-ldap3
Requires: python%{python3_pkgversion}-ldap
%endif
%endif

Expand Down
10 changes: 10 additions & 0 deletions cobbler/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,13 @@ class MirrorType(enum.Enum):
METALINK = "metalink"
MIRRORLIST = "mirrorlist"
BASEURL = "baseurl"


class TlsRequireCert(enum.Enum):
"""
This enum represents all TLS validation server cert types which Cobbler can manage.
"""
NEVER = "never"
ALLOW = "allow"
DEMAND = "demand"
HARD = "hard"
44 changes: 35 additions & 9 deletions cobbler/modules/authentication/ldap.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import traceback

from cobbler.cexceptions import CX
from cobbler import validate
from cobbler import enums


def register() -> str:
Expand Down Expand Up @@ -56,9 +58,13 @@ def authenticate(api_handle, username, password) -> bool:
prefix = api_handle.settings().ldap_search_prefix

# Support for LDAP client certificates
tls = api_handle.settings().ldap_tls
tls_cacertdir = api_handle.settings().ldap_tls_cacertfile
tls_cacertfile = api_handle.settings().ldap_tls_cacertfile
tls_keyfile = api_handle.settings().ldap_tls_keyfile
tls_certfile = api_handle.settings().ldap_tls_certfile
tls_cipher_suite = api_handle.settings().ldap_tls_cipher_suite
tls_reqcert = api_handle.settings().ldap_tls_reqcert

# allow multiple servers split by a space
if server.find(" "):
Expand All @@ -69,13 +75,6 @@ def authenticate(api_handle, username, password) -> bool:
# to get ldap working with Active Directory
ldap.set_option(ldap.OPT_REFERRALS, 0)

if tls_cacertfile:
ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile)
if tls_keyfile:
ldap.set_option(ldap.OPT_X_TLS_KEYFILE, tls_keyfile)
if tls_certfile:
ldap.set_option(ldap.OPT_X_TLS_CERTFILE, tls_certfile)

uri = ""
for server in servers:
# form our ldap uri based on connection port
Expand All @@ -92,17 +91,44 @@ def authenticate(api_handle, username, password) -> bool:
# connect to LDAP host
dir = ldap.initialize(uri)

if port == '636':
ldaps_tls = ldap
else:
ldaps_tls = dir

if tls or port == '636':
if tls_cacertdir:
ldaps_tls.set_option(ldap.OPT_X_TLS_CACERTDIR, tls_cacertdir)
if tls_cacertfile:
ldaps_tls.set_option(ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile)
if tls_keyfile:
ldaps_tls.set_option(ldap.OPT_X_TLS_KEYFILE, tls_keyfile)
if tls_certfile:
ldaps_tls.set_option(ldap.OPT_X_TLS_CERTFILE, tls_certfile)
if tls_reqcert:
req_cert = validate.validate_ldap_tls_reqcert(tls_reqcert)
reqcert_types = {enums.TlsRequireCert.NEVER: ldap.OPT_X_TLS_NEVER,
enums.TlsRequireCert.ALLOW: ldap.OPT_X_TLS_ALLOW,
enums.TlsRequireCert.DEMAND: ldap.OPT_X_TLS_DEMAND,
enums.TlsRequireCert.HARD: ldap.OPT_X_TLS_HARD}
ldaps_tls.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, reqcert_types[req_cert])
if tls_cipher_suite:
ldaps_tls.set_option(ldap.OPT_X_TLS_CIPHER_SUITE, tls_cipher_suite)

# start_tls if tls is 'on', 'true' or 'yes' and we're not already using old-SSL
if port != '636':
if api_handle.settings().ldap_tls:
if tls:
try:
dir.set_option(ldap.OPT_X_TLS_NEWCTX, 0)
dir.start_tls_s()
except:
traceback.print_exc()
return False
else:
ldap.set_option(ldap.OPT_X_TLS_NEWCTX, 0)

# if we're not allowed to search anonymously, grok the search bind settings and attempt to bind
if api_handle.settings().ldap_anonymous_bind:
if not api_handle.settings().ldap_anonymous_bind:
searchdn = api_handle.settings().ldap_search_bind_dn
searchpw = api_handle.settings().ldap_search_passwd

Expand Down
3 changes: 3 additions & 0 deletions cobbler/settings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,9 +107,12 @@ def __init__(self):
self.ldap_search_prefix = 'uid='
self.ldap_server = "grimlock.devel.redhat.com"
self.ldap_tls = True
self.ldap_tls_cacertdir = ""
self.ldap_tls_cacertfile = ""
self.ldap_tls_certfile = ""
self.ldap_tls_keyfile = ""
self.ldap_tls_reqcert = "hard"
self.ldap_tls_cipher_suite = ""
self.bind_manage_ipmi = False
# TODO: Remove following line
self.manage_dhcp = False
Expand Down
170 changes: 164 additions & 6 deletions cobbler/settings/migrations/V3_3_1.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,165 @@
# SPDX-FileCopyrightText: Copyright SUSE LLC


from schema import SchemaError
from schema import Optional, Schema, SchemaError

from cobbler.settings.migrations import V3_3_0
from cobbler.settings.migrations import helper

schema = V3_3_0.schema
schema = Schema({
"auto_migrate_settings": bool,
"allow_duplicate_hostnames": bool,
"allow_duplicate_ips": bool,
"allow_duplicate_macs": bool,
"allow_dynamic_settings": bool,
"always_write_dhcp_entries": bool,
"anamon_enabled": bool,
"auth_token_expiration": int,
"authn_pam_service": str,
"autoinstall_snippets_dir": str,
"autoinstall_templates_dir": str,
"bind_chroot_path": str,
"bind_zonefile_path": str,
"bind_master": str,
"boot_loader_conf_template_dir": str,
Optional("bootloaders_dir", default="/var/lib/cobbler/loaders"): str,
Optional("bootloaders_formats", default={
'aarch64': {'binary_name': 'grubaa64.efi'},
'arm': {'binary_name': 'bootarm.efi'},
'arm64-efi': {'binary_name': 'grubaa64.efi', 'extra_modules': ['efinet']},
'i386': {'binary_name': 'bootia32.efi'},
'i386-pc-pxe': {'binary_name': 'grub.0', 'mod_dir': 'i386-pc',
'extra_modules': ['chain', 'pxe', 'biosdisk']},
'i686': {'binary_name': 'bootia32.efi'},
'IA64': {'binary_name': 'bootia64.efi'},
'powerpc-ieee1275': {'binary_name': 'grub.ppc64le', 'extra_modules': ['net', 'ofnet']},
'x86_64-efi': {'binary_name': 'grubx86.efi', 'extra_modules': ['chain', 'efinet']}}
): dict,
Optional("bootloaders_modules", default=[
'btrfs', 'ext2', 'xfs', 'jfs', 'reiserfs', 'all_video', 'boot',
'cat', 'configfile', 'echo', 'fat', 'font', 'gfxmenu', 'gfxterm',
'gzio', 'halt', 'iso9660', 'jpeg', 'linux', 'loadenv', 'minicmd',
'normal', 'part_apple', 'part_gpt', 'part_msdos', 'password_pbkdf2',
'png', 'reboot', 'search', 'search_fs_file', 'search_fs_uuid',
'search_label', 'sleep', 'test', 'true', 'video', 'mdraid09',
'mdraid1x', 'lvm', 'serial', 'regexp', 'tr', 'tftp', 'http', 'luks',
'gcry_rijndael', 'gcry_sha1', 'gcry_sha256'
]): list,
Optional("syslinux_dir", default="/usr/share/syslinux"): str,
Optional("grub2_mod_dir", default="/usr/share/grub"): str,
Optional("grubconfig_dir", default="/var/lib/cobbler/grub_config"): str,
"build_reporting_enabled": bool,
"build_reporting_email": [str],
"build_reporting_ignorelist": [str],
"build_reporting_sender": str,
"build_reporting_smtp_server": str,
"build_reporting_subject": str,
Optional("buildisodir", default="/var/cache/cobbler/buildiso"): str,
"cheetah_import_whitelist": [str],
"client_use_https": bool,
"client_use_localhost": bool,
Optional("cobbler_master", default=""): str,
Optional("convert_server_to_ip", default=False): bool,
"createrepo_flags": str,
"autoinstall": str,
"default_name_servers": [str],
"default_name_servers_search": [str],
"default_ownership": [str],
"default_password_crypted": str,
"default_template_type": str,
"default_virt_bridge": str,
Optional("default_virt_disk_driver", default="raw"): str,
"default_virt_file_size": int,
"default_virt_ram": int,
"default_virt_type": str,
"enable_ipxe": bool,
"enable_menu": bool,
"http_port": int,
"include": [str],
Optional("iso_template_dir", default="/etc/cobbler/iso"): str,
Optional("jinja2_includedir", default="/var/lib/cobbler/jinja2"): str,
"kernel_options": dict,
"ldap_anonymous_bind": bool,
"ldap_base_dn": str,
"ldap_port": int,
"ldap_search_bind_dn": str,
"ldap_search_passwd": str,
"ldap_search_prefix": str,
"ldap_server": str,
"ldap_tls": bool,
"ldap_tls_cacertdir": str,
"ldap_tls_cacertfile": str,
"ldap_tls_certfile": str,
"ldap_tls_keyfile": str,
"ldap_tls_reqcert": str,
"ldap_tls_cipher_suite": str,
Optional("bind_manage_ipmi", default=False): bool,
# TODO: Remove following line
"manage_dhcp": bool,
"manage_dhcp_v4": bool,
"manage_dhcp_v6": bool,
"manage_dns": bool,
"manage_forward_zones": [str],
"manage_reverse_zones": [str],
Optional("manage_genders", False): bool,
"manage_rsync": bool,
"manage_tftpd": bool,
"mgmt_classes": [str],
# TODO: Validate Subdict
"mgmt_parameters": dict,
"next_server_v4": str,
"next_server_v6": str,
Optional("nsupdate_enabled", False): bool,
Optional("nsupdate_log", default="/var/log/cobbler/nsupdate.log"): str,
Optional("nsupdate_tsig_algorithm", default="hmac-sha512"): str,
Optional("nsupdate_tsig_key", default=[]): [str],
"power_management_default_type": str,
"proxy_url_ext": str,
"proxy_url_int": str,
"puppet_auto_setup": bool,
Optional("puppet_parameterized_classes", default=True): bool,
Optional("puppet_server", default="puppet"): str,
Optional("puppet_version", default=2): int,
"puppetca_path": str,
"pxe_just_once": bool,
"nopxe_with_triggers": bool,
"redhat_management_permissive": bool,
"redhat_management_server": str,
"redhat_management_key": str,
"register_new_installs": bool,
"remove_old_puppet_certs_automatically": bool,
"replicate_repo_rsync_options": str,
"replicate_rsync_options": str,
"reposync_flags": str,
"reposync_rsync_flags": str,
"restart_dhcp": bool,
"restart_dns": bool,
"run_install_triggers": bool,
"scm_track_enabled": bool,
"scm_track_mode": str,
"scm_track_author": str,
"scm_push_script": str,
"serializer_pretty_json": bool,
"server": str,
"sign_puppet_certs_automatically": bool,
Optional("signature_path", default="/var/lib/cobbler/distro_signatures.json"): str,
Optional("signature_url", default="https://cobbler.github.io/signatures/3.0.x/latest.json"): str,
"tftpboot_location": str,
"virt_auto_boot": bool,
"webdir": str,
"webdir_whitelist": [str],
"xmlrpc_port": int,
"yum_distro_priority": int,
"yum_post_install_mirror": bool,
"yumdownloader_flags": str,
Optional("windows_enabled", default=False): bool,
Optional("windows_template_dir", default="/etc/cobbler/windows"): str,
Optional("samba_distro_share", default="DISTRO"): str,
}, ignore_extra_keys=False)


def validate(settings: dict) -> bool:
"""
Checks that a given settings dict is valid according to the reference V3.3.0 schema ``schema``.
Checks that a given settings dict is valid according to the reference V3.3.1 schema ``schema``.

:param settings: The settings dict to validate.
:return: True if valid settings dict otherwise False.
Expand All @@ -39,16 +188,25 @@ def normalize(settings: dict) -> dict:

def migrate(settings: dict) -> dict:
"""
Migration of the settings ``settings`` to version V3.3.0 settings
Migration of the settings ``settings`` to version V3.3.1 settings

:param settings: The settings dict to migrate
:return: The migrated dict
"""

# rename keys and update their value
# add missing keys
# name - value pairs
missing_keys = {'auto_migrate_settings': True,
'ldap_tls_cacertdir': "",
'ldap_tls_reqcert': "hard",
'ldap_tls_cipher_suite': ""}
for (key, value) in missing_keys.items():
new_setting = helper.Setting(key, value)
helper.key_add(new_setting, settings)

# delete removed keys

if not validate(settings):
raise SchemaError("V3.3.0: Schema error while validating")
raise SchemaError("V3.3.1: Schema error while validating")
return normalize(settings)
20 changes: 20 additions & 0 deletions cobbler/validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -677,3 +677,23 @@ def validate_obj_id(object_id: str) -> bool:
object_id = object_id[9:]
(otype, oname) = object_id.split("::", 1)
return validate_obj_type(otype) and validate_obj_name(oname)


def validate_ldap_tls_reqcert(ldap_tls_reqcert: Union[enums.TlsRequireCert, str]) -> enums.TlsRequireCert:
"""
Validation strategy for server cert

:param ldap_tls_reqcert: May be one of "never", "allow", "demand" or "hard"
"""
if not isinstance(ldap_tls_reqcert, (str, enums.TlsRequireCert)):
raise TypeError("TLS require cert needs to be of type str or enums.TlsRequireCert")
# Convert an tls_reqcert which came in as a string
if isinstance(ldap_tls_reqcert, str):
try:
ldap_tls_reqcert = enums.TlsRequireCert[ldap_tls_reqcert.upper()]
except KeyError as error:
raise ValueError("ldap_tls_reqcert choices include: %s" % list(map(str, enums.TlsRequireCert))) from error
# Now it must be of the enum Type
if ldap_tls_reqcert not in enums.TlsRequireCert:
raise ValueError("invalid TLS require cert type (%s)" % ldap_tls_reqcert)
return ldap_tls_reqcert
2 changes: 1 addition & 1 deletion docker/debs/Debian_10/Debian10.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RUN apt-get update -qq && \
python3-dns \
python3-dnsq \
python3-magic \
python3-ldap3 \
python3-ldap \
python3-netaddr \
python3-pip \
python3-pycodestyle \
Expand Down
2 changes: 1 addition & 1 deletion docker/debs/Debian_11/Debian11.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ RUN apt-get update -qq && \
python3-dns \
python3-dnsq \
python3-magic \
python3-ldap3 \
python3-ldap \
python3-netaddr \
python3-pip \
python3-pycodestyle \
Expand Down
2 changes: 1 addition & 1 deletion docker/debs/build-and-install-debs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ then
# Also on Debian mod_wsgi is installed as "libapache2-mod-wsgi-py3"
echo "==> Running tests ..."
docker exec -it cobbler bash -c 'pip3 install coverage distro future setuptools sphinx requests future'
docker exec -it cobbler bash -c 'pip3 install pyyaml netaddr Cheetah3 pymongo distro ldap3 librepo'
docker exec -it cobbler bash -c 'pip3 install pyyaml netaddr Cheetah3 pymongo distro librepo'
docker exec -it cobbler bash -c 'pip3 install dnspython pyflakes pycodestyle pytest pytest-cov codecov'
docker exec -it cobbler bash -c 'pytest-3'
fi
Expand Down
2 changes: 1 addition & 1 deletion docker/debs/install-debs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ then
# Most of these requirement are already satisfied in the Dockerfiles!
# Also on Debian mod_wsgi is installed as "libapache2-mod-wsgi-py3"
docker exec -it cobbler bash -c 'pip3 install coverage distro future setuptools sphinx requests future'
docker exec -it cobbler bash -c 'pip3 install pyyaml netaddr Cheetah3 pymongo distro ldap3 librepo'
docker exec -it cobbler bash -c 'pip3 install pyyaml netaddr Cheetah3 pymongo distro librepo'
docker exec -it cobbler bash -c 'pip3 install dnspython pyflakes pycodestyle pytest pytest-cov codecov'
docker exec -it cobbler bash -c 'pytest-3'
fi
Expand Down
1 change: 0 additions & 1 deletion docker/develop/develop.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ RUN pip3 install \
dnspython \
file-magic \
Jinja2 \
ldap3 \
netaddr \
pycodestyle \
pyflakes \
Expand Down
Loading
0