From 742922be70807498d147e8facc25c68058c5e2b5 Mon Sep 17 00:00:00 2001 From: Mark Reynolds Date: Mar 04 2020 17:54:23 +0000 Subject: Issue 50928 - Unable to create a suffix with countryName Bug Description: It is not possible to create a suffix using 'c' as the RDN attribute. Fix Description: Support 'c' when creating an instance or backend. Also fixed a few python warnings. reletes: https://pagure.io/389-ds-base/issue/50928 Reviewed by: ? --- diff --git a/src/lib389/lib389/cli_conf/backend.py b/src/lib389/lib389/cli_conf/backend.py index 10208bd..68e3893 100644 --- a/src/lib389/lib389/cli_conf/backend.py +++ b/src/lib389/lib389/cli_conf/backend.py @@ -1,5 +1,5 @@ # --- BEGIN COPYRIGHT BLOCK --- -# Copyright (C) 2019 Red Hat, Inc. +# Copyright (C) 2020 Red Hat, Inc. # Copyright (C) 2019 William Brown # All rights reserved. # @@ -13,23 +13,17 @@ from lib389.configurations.sample import ( create_base_org, create_base_orgunit, create_base_cn, + create_base_c, ) from lib389.chaining import (ChainingLinks) -from lib389.index import Index, VLVIndex, VLVSearches from lib389.monitor import MonitorLDBM from lib389.replica import Replicas from lib389.utils import ensure_str, is_a_dn, is_dn_parent from lib389._constants import * from lib389.cli_base import ( - populate_attr_arguments, - _generic_list, _generic_get, _generic_get_dn, - _generic_create, - _generic_delete, _get_arg, - _get_args, - _get_attributes, _warn, ) import json @@ -181,8 +175,9 @@ def backend_create(inst, basedn, log, args): be.create(properties=props) if args.create_suffix and not args.create_entries: # Set basic ACIs (taken from instance/setup.py) + c_aci = '(targetattr="c || description || objectClass")(targetfilter="(objectClass=country)")(version 3.0; acl "Enable anyone c read"; allow (read, search, compare)(userdn="ldap:///anyone");)' o_aci = '(targetattr="o || description || objectClass")(targetfilter="(objectClass=organization)")(version 3.0; acl "Enable anyone o read"; allow (read, search, compare)(userdn="ldap:///anyone");)' - dc_aci = '(targetattr="dc || description || objectClass")(targetfilter="(objectClass=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search, compare)(userdn="ldap:///anyone");)', + dc_aci = '(targetattr="dc || description || objectClass")(targetfilter="(objectClass=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search, compare)(userdn="ldap:///anyone");)' ou_aci = '(targetattr="ou || description || objectClass")(targetfilter="(objectClass=organizationalUnit)")(version 3.0; acl "Enable anyone ou read"; allow (read, search, compare)(userdn="ldap:///anyone");)' cn_aci = '(targetattr="cn || description || objectClass")(targetfilter="(objectClass=nscontainer)")(version 3.0; acl "Enable anyone cn read"; allow (read, search, compare)(userdn="ldap:///anyone");)' suffix_rdn_attr = args.suffix.split('=')[0].lower() @@ -198,6 +193,9 @@ def backend_create(inst, basedn, log, args): elif suffix_rdn_attr == 'cn': cn = create_base_cn(inst, args.suffix) cn.add('aci', cn_aci) + elif suffix_rdn_attr == 'c': + c = create_base_c(inst, args.suffix) + c.add('aci', c_aci) else: # Unsupported rdn raise ValueError("Suffix RDN is not supported for creating suffix object. Only 'dc', 'o', 'ou', and 'cn' are supported.") @@ -291,7 +289,7 @@ def is_db_link(inst, rdn): def is_db_replicated(inst, suffix): replicas = Replicas(inst) try: - replica = replicas.get(suffix) + replicas.get(suffix) return True except: return False diff --git a/src/lib389/lib389/configurations/config_001004002.py b/src/lib389/lib389/configurations/config_001004002.py index ffc1b1d..b57ca2e 100644 --- a/src/lib389/lib389/configurations/config_001004002.py +++ b/src/lib389/lib389/configurations/config_001004002.py @@ -1,19 +1,17 @@ # --- BEGIN COPYRIGHT BLOCK --- -# Copyright (C) 2017 Red Hat, Inc. +# Copyright (C) 2020 Red Hat, Inc. # All rights reserved. # # License: GPL (version 3 or any later version). # See LICENSE for details. # --- END COPYRIGHT BLOCK --- -from .config import baseconfig, configoperation +from .config import baseconfig from .sample import sampleentries - from lib389.idm.organizationalunit import OrganizationalUnits from lib389.idm.group import Groups from lib389.idm.posixgroup import PosixGroups from lib389.idm.user import nsUserAccounts -from lib389.idm.services import ServiceAccounts from lib389.idm.nscontainer import nsHiddenContainers @@ -30,7 +28,7 @@ class c001004002_sample_entries(sampleentries): # Create the 389 service container # This could also move to be part of core later .... hidden_containers = nsHiddenContainers(self._instance, self._basedn) - ns389container = hidden_containers.create(properties={ + hidden_containers.create(properties={ 'cn': '389_ds_system' }) diff --git a/src/lib389/lib389/configurations/sample.py b/src/lib389/lib389/configurations/sample.py index 62fb816..0a20f91 100644 --- a/src/lib389/lib389/configurations/sample.py +++ b/src/lib389/lib389/configurations/sample.py @@ -1,5 +1,5 @@ # --- BEGIN COPYRIGHT BLOCK --- -# Copyright (C) 2017 Red Hat, Inc. +# Copyright (C) 2020 Red Hat, Inc. # All rights reserved. # # License: GPL (version 3 or any later version). @@ -12,6 +12,7 @@ from lib389.idm.domain import Domain from lib389.idm.organization import Organization from lib389.idm.organizationalunit import OrganizationalUnit from lib389.idm.nscontainer import nsContainer +from lib389.idm.country import Country from lib389.utils import ensure_str @@ -82,6 +83,20 @@ def create_base_cn(instance, basedn): return cn +def create_base_c(instance, basedn): + """Create the base country object""" + + c = Country(instance, dn=basedn) + # Explode the dn to get the first bit. + avas = dn.str2dn(basedn) + c_ava = avas[0][0][1] + + c.create(properties={ + 'c': c_ava, + }) + + return c + class sampleentries(object): def __init__(self, instance, basedn): @@ -99,6 +114,9 @@ class sampleentries(object): if suffix_rdn_attr == 'dc': suffix_obj = create_base_domain(self._instance, self._basedn) aci_vals = ['dc', 'domain'] + elif suffix_rdn_attr == 'c': + suffix_obj = create_base_c(self._instance, self._basedn) + aci_vals = ['c', 'country'] elif suffix_rdn_attr == 'o': suffix_obj = create_base_org(self._instance, self._basedn) aci_vals = ['o', 'organization'] @@ -110,7 +128,7 @@ class sampleentries(object): aci_vals = ['cn', 'nscontainer'] else: # Unsupported rdn - raise ValueError("Suffix RDN is not supported for creating sample entries. Only 'dc', 'o', 'ou', and 'cn' are supported.") + raise ValueError("Suffix RDN '{}' in '{}' is not supported. Supported RDN's are: 'c', 'cn', 'dc', 'o', and 'ou'".format(suffix_rdn_attr, self._basedn)) if add_acis: suffix_obj.add('aci', [ diff --git a/src/lib389/lib389/idm/country.py b/src/lib389/lib389/idm/country.py new file mode 100644 index 0000000..b0d0e9b --- /dev/null +++ b/src/lib389/lib389/idm/country.py @@ -0,0 +1,53 @@ +# --- BEGIN COPYRIGHT BLOCK --- +# Copyright (C) 2020 Red Hat, Inc. +# All rights reserved. +# +# License: GPL (version 3 or any later version). +# See LICENSE for details. +# --- END COPYRIGHT BLOCK --- + +from lib389._mapped_object import DSLdapObject, DSLdapObjects + +MUST_ATTRIBUTES = [ + 'c', +] +RDN = 'c' + + +class Country(DSLdapObject): + """A single instance of Country entry + + :param instance: An instance + :type instance: lib389.DirSrv + :param dn: Entry DN + :type dn: str + """ + + def __init__(self, instance, dn=None): + super(Country, self).__init__(instance, dn) + self._rdn_attribute = RDN + self._must_attributes = MUST_ATTRIBUTES + self._create_objectclasses = [ + 'top', + 'country', + ] + self._protected = False + + +class Countries(DSLdapObjects): + """DSLdapObjects that represents Country entries + + :param instance: An instance + :type instance: lib389.DirSrv + :param basedn: Base DN for all group entries below + :type basedn: str + """ + + def __init__(self, instance, basedn): + super(Countries, self).__init__(instance) + self._objectclasses = [ + 'country', + ] + self._filterattrs = [RDN] + self._childobject = Country + self._basedn = basedn diff --git a/src/lib389/lib389/instance/setup.py b/src/lib389/lib389/instance/setup.py index 8c0273f..555c8e7 100644 --- a/src/lib389/lib389/instance/setup.py +++ b/src/lib389/lib389/instance/setup.py @@ -1,5 +1,5 @@ # --- BEGIN COPYRIGHT BLOCK --- -# Copyright (C) 2019 Red Hat, Inc. +# Copyright (C) 2020 Red Hat, Inc. # Copyright (C) 2019 William Brown # All rights reserved. # @@ -8,7 +8,6 @@ # --- END COPYRIGHT BLOCK --- import os -import logging import sys import shutil import pwd @@ -24,7 +23,13 @@ from lib389.properties import * from lib389.passwd import password_hash, password_generate from lib389.nss_ssl import NssSsl from lib389.configurations import get_config -from lib389.configurations.sample import create_base_domain +from lib389.configurations.sample import ( + create_base_domain, + create_base_org, + create_base_orgunit, + create_base_cn, + create_base_c, +) from lib389.instance.options import General2Base, Slapd2Base, Backend2Base from lib389.paths import Paths from lib389.saslmap import SaslMappings @@ -896,14 +901,31 @@ class SetupDs(object): create_suffix_entry_in_props = backend.pop('create_suffix_entry', False) ds_instance.backends.create(properties=backend) if not is_sample_entries_in_props and create_suffix_entry_in_props: - domain = create_base_domain(ds_instance, backend['nsslapd-suffix']) - # Set basic ACI - domain.add('aci', [ - # Allow reading the base domain object - '(targetattr="dc || description || objectClass")(targetfilter="(objectClass=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search, compare)(userdn="ldap:///anyone");)', - # Allow reading the ou - '(targetattr="ou || objectClass")(targetfilter="(objectClass=organizationalUnit)")(version 3.0; acl "Enable anyone ou read"; allow (read, search, compare)(userdn="ldap:///anyone");)' - ]) + # Set basic ACIs + c_aci = '(targetattr="c || description || objectClass")(targetfilter="(objectClass=country)")(version 3.0; acl "Enable anyone c read"; allow (read, search, compare)(userdn="ldap:///anyone");)' + o_aci = '(targetattr="o || description || objectClass")(targetfilter="(objectClass=organization)")(version 3.0; acl "Enable anyone o read"; allow (read, search, compare)(userdn="ldap:///anyone");)' + dc_aci = '(targetattr="dc || description || objectClass")(targetfilter="(objectClass=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search, compare)(userdn="ldap:///anyone");)' + ou_aci = '(targetattr="ou || description || objectClass")(targetfilter="(objectClass=organizationalUnit)")(version 3.0; acl "Enable anyone ou read"; allow (read, search, compare)(userdn="ldap:///anyone");)' + cn_aci = '(targetattr="cn || description || objectClass")(targetfilter="(objectClass=nscontainer)")(version 3.0; acl "Enable anyone cn read"; allow (read, search, compare)(userdn="ldap:///anyone");)' + suffix_rdn_attr = backend['nsslapd-suffix'].split('=')[0].lower() + if suffix_rdn_attr == 'dc': + domain = create_base_domain(ds_instance, backend['nsslapd-suffix']) + domain.add('aci', dc_aci) + elif suffix_rdn_attr == 'o': + org = create_base_org(ds_instance, backend['nsslapd-suffix']) + org.add('aci', o_aci) + elif suffix_rdn_attr == 'ou': + orgunit = create_base_orgunit(ds_instance, backend['nsslapd-suffix']) + orgunit.add('aci', ou_aci) + elif suffix_rdn_attr == 'cn': + cn = create_base_cn(ds_instance, backend['nsslapd-suffix']) + cn.add('aci', cn_aci) + elif suffix_rdn_attr == 'c': + c = create_base_c(ds_instance, backend['nsslapd-suffix']) + c.add('aci', c_aci) + else: + # Unsupported rdn + raise ValueError("Suffix RDN '{}' in '{}' is not supported. Supported RDN's are: 'c', 'cn', 'dc', 'o', and 'ou'".format(suffix_rdn_attr, backend['nsslapd-suffix'])) # Initialise ldapi socket information. IPA expects this .... ldapi_path = os.path.join(slapd['local_state_dir'], "run/slapd-%s.socket" % slapd['instance_name'])