summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Dennis <jdennis@redhat.com>2012-05-13 07:36:35 -0400
committerRob Crittenden <rcritten@redhat.com>2012-08-12 16:23:24 -0400
commit94d457e83c172320707fbf13f7a1587dad128ece (patch)
treee1e2d88ee436114f1f82f2ba4141c6318089765a
parentbe9614654ee8232323a19ec56e551c4f66e6cc72 (diff)
downloadfreeipa-94d457e83c172320707fbf13f7a1587dad128ece.tar.gz
freeipa-94d457e83c172320707fbf13f7a1587dad128ece.tar.xz
freeipa-94d457e83c172320707fbf13f7a1587dad128ece.zip
Use DN objects instead of strings
* Convert every string specifying a DN into a DN object * Every place a dn was manipulated in some fashion it was replaced by the use of DN operators * Add new DNParam parameter type for parameters which are DN's * DN objects are used 100% of the time throughout the entire data pipeline whenever something is logically a dn. * Many classes now enforce DN usage for their attributes which are dn's. This is implmented via ipautil.dn_attribute_property(). The only permitted types for a class attribute specified to be a DN are either None or a DN object. * Require that every place a dn is used it must be a DN object. This translates into lot of:: assert isinstance(dn, DN) sprinkled through out the code. Maintaining these asserts is valuable to preserve DN type enforcement. The asserts can be disabled in production. The goal of 100% DN usage 100% of the time has been realized, these asserts are meant to preserve that. The asserts also proved valuable in detecting functions which did not obey their function signatures, such as the baseldap pre and post callbacks. * Moved ipalib.dn to ipapython.dn because DN class is shared with all components, not just the server which uses ipalib. * All API's now accept DN's natively, no need to convert to str (or unicode). * Removed ipalib.encoder and encode/decode decorators. Type conversion is now explicitly performed in each IPASimpleLDAPObject method which emulates a ldap.SimpleLDAPObject method. * Entity & Entry classes now utilize DN's * Removed __getattr__ in Entity & Entity clases. There were two problems with it. It presented synthetic Python object attributes based on the current LDAP data it contained. There is no way to validate synthetic attributes using code checkers, you can't search the code to find LDAP attribute accesses (because synthetic attriutes look like Python attributes instead of LDAP data) and error handling is circumscribed. Secondly __getattr__ was hiding Python internal methods which broke class semantics. * Replace use of methods inherited from ldap.SimpleLDAPObject via IPAdmin class with IPAdmin methods. Directly using inherited methods was causing us to bypass IPA logic. Mostly this meant replacing the use of search_s() with getEntry() or getList(). Similarly direct access of the LDAP data in classes using IPAdmin were replaced with calls to getValue() or getValues(). * Objects returned by ldap2.find_entries() are now compatible with either the python-ldap access methodology or the Entity/Entry access methodology. * All ldap operations now funnel through the common IPASimpleLDAPObject giving us a single location where we interface to python-ldap and perform conversions. * The above 4 modifications means we've greatly reduced the proliferation of multiple inconsistent ways to perform LDAP operations. We are well on the way to having a single API in IPA for doing LDAP (a long range goal). * All certificate subject bases are now DN's * DN objects were enhanced thusly: - find, rfind, index, rindex, replace and insert methods were added - AVA, RDN and DN classes were refactored in immutable and mutable variants, the mutable variants are EditableAVA, EditableRDN and EditableDN. By default we use the immutable variants preserving important semantics. To edit a DN cast it to an EditableDN and cast it back to DN when done editing. These issues are fully described in other documentation. - first_key_match was removed - DN equalty comparison permits comparison to a basestring * Fixed ldapupdate to work with DN's. This work included: - Enhance test_updates.py to do more checking after applying update. Add test for update_from_dict(). Convert code to use unittest classes. - Consolidated duplicate code. - Moved code which should have been in the class into the class. - Fix the handling of the 'deleteentry' update action. It's no longer necessary to supply fake attributes to make it work. Detect case where subsequent update applies a change to entry previously marked for deletetion. General clean-up and simplification of the 'deleteentry' logic. - Rewrote a couple of functions to be clearer and more Pythonic. - Added documentation on the data structure being used. - Simplfy the use of update_from_dict() * Removed all usage of get_schema() which was being called prior to accessing the .schema attribute of an object. If a class is using internal lazy loading as an optimization it's not right to require users of the interface to be aware of internal optimization's. schema is now a property and when the schema property is accessed it calls a private internal method to perform the lazy loading. * Added SchemaCache class to cache the schema's from individual servers. This was done because of the observation we talk to different LDAP servers, each of which may have it's own schema. Previously we globally cached the schema from the first server we connected to and returned that schema in all contexts. The cache includes controls to invalidate it thus forcing a schema refresh. * Schema caching is now senstive to the run time context. During install and upgrade the schema can change leading to errors due to out-of-date cached schema. The schema cache is refreshed in these contexts. * We are aware of the LDAP syntax of all LDAP attributes. Every attribute returned from an LDAP operation is passed through a central table look-up based on it's LDAP syntax. The table key is the LDAP syntax it's value is a Python callable that returns a Python object matching the LDAP syntax. There are a handful of LDAP attributes whose syntax is historically incorrect (e.g. DistguishedNames that are defined as DirectoryStrings). The table driven conversion mechanism is augmented with a table of hard coded exceptions. Currently only the following conversions occur via the table: - dn's are converted to DN objects - binary objects are converted to Python str objects (IPA convention). - everything else is converted to unicode using UTF-8 decoding (IPA convention). However, now that the table driven conversion mechanism is in place it would be trivial to do things such as converting attributes which have LDAP integer syntax into a Python integer, etc. * Expected values in the unit tests which are a DN no longer need to use lambda expressions to promote the returned value to a DN for equality comparison. The return value is automatically promoted to a DN. The lambda expressions have been removed making the code much simpler and easier to read. * Add class level logging to a number of classes which did not support logging, less need for use of root_logger. * Remove ipaserver/conn.py, it was unused. * Consolidated duplicate code wherever it was found. * Fixed many places that used string concatenation to form a new string rather than string formatting operators. This is necessary because string formatting converts it's arguments to a string prior to building the result string. You can't concatenate a string and a non-string. * Simplify logic in rename_managed plugin. Use DN operators to edit dn's. * The live version of ipa-ldap-updater did not generate a log file. The offline version did, now both do. https://fedorahosted.org/freeipa/ticket/1670 https://fedorahosted.org/freeipa/ticket/1671 https://fedorahosted.org/freeipa/ticket/1672 https://fedorahosted.org/freeipa/ticket/1673 https://fedorahosted.org/freeipa/ticket/1674 https://fedorahosted.org/freeipa/ticket/1392 https://fedorahosted.org/freeipa/ticket/2872
-rw-r--r--API.txt14
-rw-r--r--contrib/RHEL4/ipa-client-setup8
-rw-r--r--install/certmonger/dogtag-ipa-retrieve-agent-submit4
-rw-r--r--install/migration/migration.py5
-rw-r--r--install/restart_scripts/renew_ca_cert4
-rw-r--r--install/restart_scripts/renew_ra_cert8
-rwxr-xr-xinstall/tools/ipa-adtrust-install1
-rwxr-xr-xinstall/tools/ipa-compat-manage7
-rw-r--r--install/tools/ipa-compliance5
-rwxr-xr-xinstall/tools/ipa-csreplica-manage41
-rwxr-xr-xinstall/tools/ipa-dns-install2
-rwxr-xr-xinstall/tools/ipa-managed-entries19
-rwxr-xr-xinstall/tools/ipa-nis-manage7
-rwxr-xr-xinstall/tools/ipa-replica-install19
-rwxr-xr-xinstall/tools/ipa-replica-manage69
-rwxr-xr-xinstall/tools/ipa-replica-prepare14
-rwxr-xr-xinstall/tools/ipa-server-certinstall5
-rwxr-xr-xinstall/tools/ipa-server-install18
-rw-r--r--install/tools/ipa-upgradeconfig2
-rwxr-xr-xinstall/tools/ipactl15
-rwxr-xr-xipa-client/ipa-install/ipa-client-automount2
-rwxr-xr-xipa-client/ipa-install/ipa-client-install18
-rw-r--r--ipa-client/ipaclient/ipadiscovery.py4
-rw-r--r--ipalib/__init__.py2
-rwxr-xr-xipalib/aci.py26
-rw-r--r--ipalib/config.py5
-rw-r--r--ipalib/constants.py73
-rw-r--r--ipalib/encoder.py213
-rw-r--r--ipalib/parameters.py19
-rw-r--r--ipalib/plugins/aci.py52
-rw-r--r--ipalib/plugins/automember.py25
-rw-r--r--ipalib/plugins/automount.py6
-rw-r--r--ipalib/plugins/baseldap.py188
-rw-r--r--ipalib/plugins/config.py7
-rw-r--r--ipalib/plugins/dns.py34
-rw-r--r--ipalib/plugins/entitle.py9
-rw-r--r--ipalib/plugins/group.py8
-rw-r--r--ipalib/plugins/hbacrule.py9
-rw-r--r--ipalib/plugins/host.py15
-rw-r--r--ipalib/plugins/hostgroup.py8
-rw-r--r--ipalib/plugins/krbtpolicy.py5
-rw-r--r--ipalib/plugins/migration.py86
-rw-r--r--ipalib/plugins/netgroup.py7
-rw-r--r--ipalib/plugins/passwd.py3
-rw-r--r--ipalib/plugins/permission.py19
-rw-r--r--ipalib/plugins/pkinit.py5
-rw-r--r--ipalib/plugins/pwpolicy.py26
-rw-r--r--ipalib/plugins/range.py8
-rw-r--r--ipalib/plugins/selinuxusermap.py7
-rw-r--r--ipalib/plugins/service.py7
-rw-r--r--ipalib/plugins/sudorule.py16
-rw-r--r--ipalib/plugins/trust.py8
-rw-r--r--ipalib/plugins/user.py18
-rw-r--r--ipalib/plugins/virtual.py3
-rw-r--r--ipalib/rpc.py5
-rw-r--r--ipalib/session.py2
-rw-r--r--ipalib/util.py9
-rw-r--r--ipalib/x509.py2
-rw-r--r--ipapython/dn.py (renamed from ipalib/dn.py)722
-rw-r--r--ipapython/entity.py32
-rw-r--r--ipapython/ipa_log_manager.py4
-rw-r--r--ipapython/ipautil.py43
-rw-r--r--ipaserver/conn.py69
-rw-r--r--ipaserver/dcerpc.py6
-rw-r--r--ipaserver/install/adtrustinstance.py63
-rw-r--r--ipaserver/install/bindinstance.py28
-rw-r--r--ipaserver/install/cainstance.py64
-rw-r--r--ipaserver/install/certs.py26
-rw-r--r--ipaserver/install/dsinstance.py42
-rw-r--r--ipaserver/install/httpinstance.py2
-rw-r--r--ipaserver/install/installutils.py5
-rw-r--r--ipaserver/install/ipa_ldap_updater.py2
-rw-r--r--ipaserver/install/krbinstance.py23
-rw-r--r--ipaserver/install/ldapupdate.py688
-rw-r--r--ipaserver/install/plugins/adtrust.py16
-rw-r--r--ipaserver/install/plugins/dns.py41
-rw-r--r--ipaserver/install/plugins/fix_replica_memberof.py4
-rw-r--r--ipaserver/install/plugins/rename_managed.py159
-rw-r--r--ipaserver/install/plugins/updateclient.py23
-rw-r--r--ipaserver/install/replication.py204
-rw-r--r--ipaserver/install/service.py26
-rw-r--r--ipaserver/ipaldap.py115
-rw-r--r--ipaserver/plugins/dogtag.py14
-rw-r--r--ipaserver/plugins/ldap2.py1123
-rw-r--r--ipaserver/plugins/selfsign.py11
-rw-r--r--ipaserver/rpcserver.py34
-rwxr-xr-xmake-lint4
-rwxr-xr-xmake-testcert5
-rw-r--r--tests/test_cmdline/test_ipagetkeytab.py2
-rw-r--r--tests/test_install/0_reset.update2
-rw-r--r--tests/test_install/test_updates.py238
-rw-r--r--tests/test_ipalib/test_dn.py1085
-rw-r--r--tests/test_ipalib/test_encoder.py149
-rw-r--r--tests/test_ipalib/test_x509.py2
-rw-r--r--tests/test_ipapython/test_dn.py1937
-rw-r--r--tests/test_ipaserver/test_changepw.py6
-rw-r--r--tests/test_ipaserver/test_ldap.py11
-rw-r--r--tests/test_xmlrpc/test_attr.py104
-rw-r--r--tests/test_xmlrpc/test_automember_plugin.py129
-rw-r--r--tests/test_xmlrpc/test_automount_plugin.py36
-rw-r--r--tests/test_xmlrpc/test_batch_plugin.py20
-rw-r--r--tests/test_xmlrpc/test_cert.py2
-rw-r--r--tests/test_xmlrpc/test_delegation_plugin.py11
-rw-r--r--tests/test_xmlrpc/test_dns_plugin.py59
-rw-r--r--tests/test_xmlrpc/test_group_plugin.py72
-rw-r--r--tests/test_xmlrpc/test_hbacsvcgroup_plugin.py16
-rw-r--r--tests/test_xmlrpc/test_host_plugin.py44
-rw-r--r--tests/test_xmlrpc/test_hostgroup_plugin.py29
-rw-r--r--tests/test_xmlrpc/test_krbtpolicy.py21
-rw-r--r--tests/test_xmlrpc/test_nesting.py166
-rw-r--r--tests/test_xmlrpc/test_netgroup_plugin.py53
-rw-r--r--tests/test_xmlrpc/test_permission_plugin.py97
-rw-r--r--tests/test_xmlrpc/test_privilege_plugin.py30
-rw-r--r--tests/test_xmlrpc/test_range_plugin.py12
-rw-r--r--tests/test_xmlrpc/test_replace.py17
-rw-r--r--tests/test_xmlrpc/test_role_plugin.py44
-rw-r--r--tests/test_xmlrpc/test_selinuxusermap_plugin.py36
-rw-r--r--tests/test_xmlrpc/test_service_plugin.py38
-rw-r--r--tests/test_xmlrpc/test_sudocmd_plugin.py22
-rw-r--r--tests/test_xmlrpc/test_sudocmdgroup_plugin.py102
-rw-r--r--tests/test_xmlrpc/test_user_plugin.py231
-rw-r--r--tests/test_xmlrpc/xmlrpc_test.py4
-rw-r--r--tests/util.py4
123 files changed, 5498 insertions, 4157 deletions
diff --git a/API.txt b/API.txt
index 6f14fccc3..d32d6393b 100644
--- a/API.txt
+++ b/API.txt
@@ -491,7 +491,7 @@ output: Output('value', <type 'unicode'>, None)
command: cosentry_add
args: 1,7,3
arg: Str('cn', attribute=True, cli_name='cn', multivalue=False, primary_key=True, required=True)
-option: Str('krbpwdpolicyreference', attribute=True, cli_name='krbpwdpolicyreference', multivalue=False, required=True)
+option: DNParam('krbpwdpolicyreference', attribute=True, cli_name='krbpwdpolicyreference', multivalue=False, required=True)
option: Int('cospriority', attribute=True, cli_name='cospriority', minvalue=0, multivalue=False, required=True)
option: Str('setattr*', cli_name='setattr', exclude='webui')
option: Str('addattr*', cli_name='addattr', exclude='webui')
@@ -512,7 +512,7 @@ command: cosentry_find
args: 1,9,4
arg: Str('criteria?', noextrawhitespace=False)
option: Str('cn', attribute=True, autofill=False, cli_name='cn', multivalue=False, primary_key=True, query=True, required=False)
-option: Str('krbpwdpolicyreference', attribute=True, autofill=False, cli_name='krbpwdpolicyreference', multivalue=False, query=True, required=False)
+option: DNParam('krbpwdpolicyreference', attribute=True, autofill=False, cli_name='krbpwdpolicyreference', multivalue=False, query=True, required=False)
option: Int('cospriority', attribute=True, autofill=False, cli_name='cospriority', minvalue=0, multivalue=False, query=True, required=False)
option: Int('timelimit?', autofill=False, minvalue=0)
option: Int('sizelimit?', autofill=False, minvalue=0)
@@ -527,7 +527,7 @@ output: Output('truncated', <type 'bool'>, None)
command: cosentry_mod
args: 1,9,3
arg: Str('cn', attribute=True, cli_name='cn', multivalue=False, primary_key=True, query=True, required=True)
-option: Str('krbpwdpolicyreference', attribute=True, autofill=False, cli_name='krbpwdpolicyreference', multivalue=False, required=False)
+option: DNParam('krbpwdpolicyreference', attribute=True, autofill=False, cli_name='krbpwdpolicyreference', multivalue=False, required=False)
option: Int('cospriority', attribute=True, autofill=False, cli_name='cospriority', minvalue=0, multivalue=False, required=False)
option: Str('setattr*', cli_name='setattr', exclude='webui')
option: Str('addattr*', cli_name='addattr', exclude='webui')
@@ -1931,9 +1931,9 @@ command: migrate_ds
args: 2,16,4
arg: Str('ldapuri', cli_name='ldap_uri')
arg: Password('bindpw', cli_name='password', confirm=False)
-option: Str('binddn?', autofill=True, cli_name='bind_dn', default=u'cn=directory manager')
-option: Str('usercontainer', autofill=True, cli_name='user_container', default=u'ou=people')
-option: Str('groupcontainer', autofill=True, cli_name='group_container', default=u'ou=groups')
+option: DNParam('binddn?', autofill=True, cli_name='bind_dn', default=ipapython.dn.DN('cn=directory manager'))
+option: DNParam('usercontainer', autofill=True, cli_name='user_container', default=ipapython.dn.DN('ou=people'))
+option: DNParam('groupcontainer', autofill=True, cli_name='group_container', default=ipapython.dn.DN('ou=groups'))
option: Str('userobjectclass+', autofill=True, cli_name='user_objectclass', csv=True, default=(u'person',))
option: Str('groupobjectclass+', autofill=True, cli_name='group_objectclass', csv=True, default=(u'groupOfUniqueNames', u'groupOfNames'))
option: Str('userignoreobjectclass*', autofill=True, cli_name='user_ignore_objectclass', csv=True, default=())
@@ -1943,7 +1943,7 @@ option: Str('groupignoreattribute*', autofill=True, cli_name='group_ignore_attri
option: Flag('groupoverwritegid', autofill=True, cli_name='group_overwrite_gid', default=False)
option: StrEnum('schema?', autofill=True, cli_name='schema', default=u'RFC2307bis', values=(u'RFC2307bis', u'RFC2307'))
option: Flag('continue?', autofill=True, default=False)
-option: Str('basedn?', cli_name='base_dn')
+option: DNParam('basedn?', cli_name='base_dn')
option: Flag('compat?', autofill=True, cli_name='with_compat', default=False)
option: Str('exclude_groups*', autofill=True, cli_name='exclude_groups', csv=True, default=())
option: Str('exclude_users*', autofill=True, cli_name='exclude_users', csv=True, default=())
diff --git a/contrib/RHEL4/ipa-client-setup b/contrib/RHEL4/ipa-client-setup
index bba60c2ab..1a8761036 100644
--- a/contrib/RHEL4/ipa-client-setup
+++ b/contrib/RHEL4/ipa-client-setup
@@ -31,6 +31,7 @@ from optparse import OptionParser
import ipachangeconf
import ldap
from ldap import LDAPError
+from ipapython.dn import DN
class ipaserver:
@@ -90,7 +91,8 @@ class ipaserver:
#search and return known realms
root_logger.debug("Search for (objectClass=krbRealmContainer) in "+self.basedn+"(sub)")
- lret = lh.search_s("cn=kerberos,"+self.basedn, ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)")
+ lret = lh.search_s(str(DN(('cn', 'kerberos'), self.basedn)),
+ ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)")
if not lret:
#something very wrong
return False
@@ -272,8 +274,8 @@ def main():
{'name':'ldap_version', 'type':'option', 'value':'3'},
{'name':'base', 'type':'option', 'value':ipasrv.getBaseDN()},
{'name':'empty', 'type':'empty'},
- {'name':'nss_base_passwd', 'type':'option', 'value':'cn=users,cn=accounts,'+ipasrv.getBaseDN()+'?sub'},
- {'name':'nss_base_group', 'type':'option', 'value':'cn=users,cn=accounts,'+ipasrv.getBaseDN()+'?sub'},
+ {'name':'nss_base_passwd', 'type':'option', 'value':str(DN(('cn', 'users'), ('cn', 'accounts'), ipasrv.getBaseDN()))+'?sub'},
+ {'name':'nss_base_group', 'type':'option', 'value':str(DN(('cn', 'users'), ('cn', 'accounts'), ipasrv.getBaseDN()))+'?sub'},
{'name':'nss_schema', 'type':'option', 'value':'rfc2307bis'},
{'name':'nss_map_attribute', 'type':'option', 'value':'uniqueMember member'},
{'name':'nss_initgroups_ignoreusers', 'type':'option', 'value':'root,dirsrv'},
diff --git a/install/certmonger/dogtag-ipa-retrieve-agent-submit b/install/certmonger/dogtag-ipa-retrieve-agent-submit
index 24e1844a5..6d54000d6 100644
--- a/install/certmonger/dogtag-ipa-retrieve-agent-submit
+++ b/install/certmonger/dogtag-ipa-retrieve-agent-submit
@@ -29,7 +29,7 @@ import tempfile
import krbV
import syslog
from ipalib import api
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipalib import errors
from ipalib import x509
from ipapython import services as ipaservices
@@ -52,7 +52,7 @@ api.finalize()
# Update or add it
tmpdir = tempfile.mkdtemp(prefix = "tmp-")
try:
- dn = str(DN(('cn',nickname),('cn=ca_renewal,cn=ipa,cn=etc'),(api.env.basedn)))
+ dn = DN(('cn', nickname), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
diff --git a/install/migration/migration.py b/install/migration/migration.py
index 449d35c66..e0ada1310 100644
--- a/install/migration/migration.py
+++ b/install/migration/migration.py
@@ -27,6 +27,7 @@ import ldap
import wsgiref
from ipapython.ipa_log_manager import *
from ipapython.ipautil import get_ipa_basedn
+from ipapython.dn import DN
BASE_DN = ''
LDAP_URI = 'ldaps://localhost:636'
@@ -80,10 +81,10 @@ def bind(username, password):
if not base_dn:
root_logger.error('migration unable to get base dn')
raise IOError(errno.EIO, 'Cannot get Base DN')
- bind_dn = 'uid=%s,cn=users,cn=accounts,%s' % (username, base_dn)
+ bind_dn = DN(('uid', username), ('cn', 'users'), ('cn', 'accounts'), base_dn)
try:
conn = ldap.initialize(LDAP_URI)
- conn.simple_bind_s(bind_dn, password)
+ conn.simple_bind_s(str(bind_dn), password)
except (ldap.INVALID_CREDENTIALS, ldap.UNWILLING_TO_PERFORM,
ldap.NO_SUCH_OBJECT), e:
root_logger.error('migration invalid credentials for %s: %s' % (bind_dn, convert_exception(e)))
diff --git a/install/restart_scripts/renew_ca_cert b/install/restart_scripts/renew_ca_cert
index d3b756042..e4374eca5 100644
--- a/install/restart_scripts/renew_ca_cert
+++ b/install/restart_scripts/renew_ca_cert
@@ -26,7 +26,7 @@ import tempfile
import krbV
import syslog
from ipalib import api
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipalib import errors
from ipapython import services as ipaservices
from ipapython import ipautil
@@ -50,7 +50,7 @@ if not cert:
# Update or add it
tmpdir = tempfile.mkdtemp(prefix = "tmp-")
try:
- dn = str(DN(('cn',nickname),('cn=ca_renewal,cn=ipa,cn=etc'),(api.env.basedn)))
+ dn = DN(('cn',nickname), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
diff --git a/install/restart_scripts/renew_ra_cert b/install/restart_scripts/renew_ra_cert
index 2fcf1a79b..14cbc114c 100644
--- a/install/restart_scripts/renew_ra_cert
+++ b/install/restart_scripts/renew_ra_cert
@@ -29,7 +29,7 @@ from ipapython import ipautil
from ipaserver.install import certs
from ipaserver.install.cainstance import DEFAULT_DSPORT
from ipalib import api
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipalib import x509
from ipalib import errors
from ipaserver.plugins.ldap2 import ldap2
@@ -45,7 +45,7 @@ subject = x509.get_subject(cert, datatype=x509.DER)
issuer = x509.get_issuer(cert, datatype=x509.DER)
# Load it into dogtag
-dn = str(DN(('uid','ipara'),('ou','People'),('o','ipaca')))
+dn = DN(('uid','ipara'),('ou','People'),('o','ipaca'))
try:
dm_password = get_pin('internaldb')
@@ -55,7 +55,7 @@ except IOError, e:
try:
conn = ldap2(shared_instance=False, ldap_uri='ldap://localhost:%d' % DEFAULT_DSPORT)
- conn.connect(bind_dn='cn=directory manager', bind_pw=dm_password)
+ conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password)
(entry_dn, entry_attrs) = conn.get_entry(dn, ['usercertificate'], normalize=False)
entry_attrs['usercertificate'].append(cert)
entry_attrs['description'] = '2;%d;%s;%s' % (serial_number, issuer, subject)
@@ -68,7 +68,7 @@ except Exception, e:
# Store it in the IPA LDAP server
tmpdir = tempfile.mkdtemp(prefix = "tmp-")
try:
- dn = str(DN(('cn','ipaCert'),('cn=ca_renewal,cn=ipa,cn=etc'),(api.env.basedn)))
+ dn = DN(('cn','ipaCert'), ('cn', 'ca_renewal'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
principal = str('host/%s@%s' % (api.env.host, api.env.realm))
ccache = ipautil.kinit_hostprincipal('/etc/krb5.keytab', tmpdir, principal)
conn = ldap2(shared_instance=False, ldap_uri=api.env.ldap_uri)
diff --git a/install/tools/ipa-adtrust-install b/install/tools/ipa-adtrust-install
index 02a309306..8cea077cc 100755
--- a/install/tools/ipa-adtrust-install
+++ b/install/tools/ipa-adtrust-install
@@ -32,6 +32,7 @@ from ipapython.config import IPAOptionParser
import krbV
import ldap
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
log_file_name = "/var/log/ipaserver-install.log"
diff --git a/install/tools/ipa-compat-manage b/install/tools/ipa-compat-manage
index f7564e0c5..e88d92286 100755
--- a/install/tools/ipa-compat-manage
+++ b/install/tools/ipa-compat-manage
@@ -28,6 +28,7 @@ try:
from ipaserver.plugins.ldap2 import ldap2
from ipalib import api, errors
from ipapython.ipa_log_manager import *
+ from ipapython.dn import DN
except ImportError:
print >> sys.stderr, """\
There was a problem importing one of the required Python modules. The
@@ -37,8 +38,8 @@ error was:
""" % sys.exc_value
sys.exit(1)
-compat_dn = "cn=Schema Compatibility,cn=plugins,cn=config"
-nis_config_dn = "cn=NIS Server,cn=plugins,cn=config"
+compat_dn = DN(('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config'))
+nis_config_dn = DN(('cn', 'NIS Server'), ('cn', 'plugins'), ('cn', 'config'))
def parse_options():
usage = "%prog [options] <enable|disable>\n"
@@ -107,7 +108,7 @@ def main():
try:
conn = ldap2(shared_instance=False, base_dn='')
conn.connect(
- bind_dn='cn=directory manager', bind_pw=dirman_password
+ bind_dn=DN(('cn', 'directory manager')), bind_pw=dirman_password
)
except errors.ExecutionError, lde:
sys.exit("An error occurred while connecting to the server.\n%s\n" % str(lde))
diff --git a/install/tools/ipa-compliance b/install/tools/ipa-compliance
index 8ae91b777..c82e4151f 100644
--- a/install/tools/ipa-compliance
+++ b/install/tools/ipa-compliance
@@ -36,6 +36,7 @@ try:
from ipaserver.plugins.ldap2 import ldap2
from ipalib import api, errors, backend
from ipaserver.install import installutils
+ from ipapython.dn import DN
except ImportError, e:
# If python-rhsm isn't installed exit gracefully and quietly.
if e.args[0] == 'No module named rhsm.certificate':
@@ -116,7 +117,7 @@ def check_compliance(tmpdir, debug=False):
# Get the hosts first
try:
(entries, truncated) = conn.find_entries('(krblastpwdchange=*)', ['dn'],
- '%s,%s' % (api.env.container_host, api.env.basedn),
+ DN(api.env.container_host, api.env.basedn),
conn.SCOPE_ONELEVEL,
size_limit = -1)
except errors.NotFound:
@@ -136,7 +137,7 @@ def check_compliance(tmpdir, debug=False):
try:
(entries, truncated) = conn.find_entries('(objectclass=ipaentitlement)',
['dn', 'userCertificate'],
- '%s,%s' % (api.env.container_entitlements, api.env.basedn),
+ DN(api.env.container_entitlements, api.env.basedn),
conn.SCOPE_ONELEVEL,
size_limit = -1)
diff --git a/install/tools/ipa-csreplica-manage b/install/tools/ipa-csreplica-manage
index 938201fed..6eefe8d6d 100755
--- a/install/tools/ipa-csreplica-manage
+++ b/install/tools/ipa-csreplica-manage
@@ -30,7 +30,7 @@ from ipaserver.install import replication, installutils
from ipaserver import ipaldap
from ipapython import version
from ipalib import api, errors, util
-from ipalib.dn import DN
+from ipapython.dn import DN
CACERT = "/etc/ipa/ca.crt"
PORT = 7389
@@ -63,7 +63,7 @@ class CSReplicationManager(replication.ReplicationManager):
def __init__(self, realm, hostname, dirman_passwd, port=PORT, starttls=True):
super(CSReplicationManager, self).__init__(realm, hostname, dirman_passwd, port, starttls)
- self.suffix = 'o=ipaca'
+ self.suffix = DN(('o', 'ipaca'))
self.hostnames = [] # set before calling or agreement_dn() will fail
def agreement_dn(self, hostname, master=None):
@@ -89,14 +89,14 @@ class CSReplicationManager(replication.ReplicationManager):
else:
name = "clone"
cn="%sAgreement1-%s-%s" % (name, hostname, instance_name)
- dn = str(DN("cn=%s, %s" % (cn, self.replica_dn())))
+ dn = DN(('cn', cn), self.replica_dn())
return (cn, dn)
for host in self.hostnames:
for master in ["master", "clone"]:
try:
cn="%sAgreement1-%s-%s" % (master, host, instance_name)
- dn = "cn=%s, %s" % (cn, self.replica_dn())
+ dn = DN(('cn', cn), self.replica_dn())
self.conn.getEntry(dn, ldap.SCOPE_BASE)
return (cn, dn)
except errors.NotFound:
@@ -106,12 +106,10 @@ class CSReplicationManager(replication.ReplicationManager):
raise errors.NotFound(reason='No agreement found for %s' % hostname)
def delete_referral(self, hostname):
- esc1_suffix = self.suffix.replace('=', '\\3D').replace(',', '\\2C')
- esc2_suffix = self.suffix.replace('=', '%3D').replace(',', '%2C')
- dn = 'cn=%s,cn=mapping tree,cn=config' % esc1_suffix
+ dn = DN(('cn', self.suffix), ('cn', 'mapping tree'), ('cn', 'config'))
# TODO: should we detect proto/port somehow ?
mod = [(ldap.MOD_DELETE, 'nsslapd-referral',
- 'ldap://%s/%s' % (ipautil.format_netloc(hostname, PORT), esc2_suffix))]
+ 'ldap://%s/%s' % (ipautil.format_netloc(hostname, PORT), self.suffix))]
try:
self.conn.modify_s(dn, mod)
@@ -165,16 +163,16 @@ def list_replicas(realm, host, replica, dirman_passwd, verbose):
conn = ipaldap.IPAdmin(host, 636, cacert=CACERT)
conn.do_simple_bind(bindpw=dirman_passwd)
- dn = str(DN('cn=masters,cn=ipa,cn=etc,%s' % ipautil.realm_to_suffix(realm)))
- entries = conn.search_s(dn, ldap.SCOPE_ONELEVEL)
+ dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm))
+ entries = conn.getList(dn, ldap.SCOPE_ONELEVEL)
for ent in entries:
try:
cadn = DN(('cn', 'CA'), DN(ent.dn))
- entry = conn.getEntry(str(cadn), ldap.SCOPE_BASE)
- peers[ent.cn] = ['master', '']
+ entry = conn.getEntry(cadn, ldap.SCOPE_BASE)
+ peers[ent.getValue('cn')] = ['master', '']
except errors.NotFound:
- peers[ent.cn] = ['CA not configured', '']
+ peers[ent.getValue('cn')] = ['CA not configured', '']
except Exception, e:
sys.exit("Failed to get data from '%s': %s" % (host, convert_error(e)))
@@ -190,13 +188,13 @@ def list_replicas(realm, host, replica, dirman_passwd, verbose):
entries = repl.find_replication_agreements()
for entry in entries:
- print '%s' % entry.nsds5replicahost
+ print '%s' % entry.getValue('nsds5replicahost')
if verbose:
- print " last init status: %s" % entry.nsds5replicalastinitstatus
- print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastinitend))
- print " last update status: %s" % entry.nsds5replicalastupdatestatus
- print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastupdateend))
+ print " last init status: %s" % entry.getValue('nsds5replicalastinitstatus')
+ print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.getValue('nsds5replicalastinitend')))
+ print " last update status: %s" % entry.getValue('nsds5replicalastupdatestatus')
+ print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.getValue('nsds5replicalastupdateend')))
def del_link(realm, replica1, replica2, dirman_passwd, force=False):
@@ -316,7 +314,8 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
conn = ipaldap.IPAdmin(replica2, 636, cacert=CACERT)
conn.do_simple_bind(bindpw=dirman_passwd)
- dn = str(DN('cn=CA,cn=%s,cn=masters,cn=ipa,cn=etc,%s' % (replica2, ipautil.realm_to_suffix(realm))))
+ dn = DN(('cn', 'CA'), ('cn', replica2), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'),
+ ipautil.realm_to_suffix(realm))
conn.search_s(dn, ldap.SCOPE_ONELEVEL)
conn.unbind_s()
except ldap.NO_SUCH_OBJECT:
@@ -341,7 +340,7 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
except Exception, e:
sys.exit("Failed to get data from '%s': %s" % (replica1, convert_error(e)))
- repl1.setup_replication(replica2, PORT, 0, "cn=Directory Manager", dirman_passwd, True, True)
+ repl1.setup_replication(replica2, PORT, 0, DN(('cn', 'Directory Manager')), dirman_passwd, True, True)
print "Connected '%s' to '%s'" % (replica1, replica2)
def re_initialize(realm, options):
@@ -355,7 +354,7 @@ def re_initialize(realm, options):
thishost = installutils.get_fqdn()
filter = "(&(nsDS5ReplicaHost=%s)(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement)))" % thishost
- entry = repl.conn.search_s("cn=config", ldap.SCOPE_SUBTREE, filter)
+ entry = repl.conn.search_s(DN(('cn', 'config')), ldap.SCOPE_SUBTREE, filter)
if len(entry) == 0:
root_logger.error("Unable to find %s -> %s replication agreement" % (options.fromhost, thishost))
sys.exit(1)
diff --git a/install/tools/ipa-dns-install b/install/tools/ipa-dns-install
index 47bffdf83..d4795f72e 100755
--- a/install/tools/ipa-dns-install
+++ b/install/tools/ipa-dns-install
@@ -202,7 +202,7 @@ def main():
root_logger.debug("will use dns_forwarders: %s\n", str(dns_forwarders))
if bind.dm_password:
- api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=bind.dm_password)
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=bind.dm_password)
else:
# See if our LDAP server is up and we can talk to it over GSSAPI
ccache = krbV.default_context().default_ccache().name
diff --git a/install/tools/ipa-managed-entries b/install/tools/ipa-managed-entries
index b9a492e48..e68d4d360 100755
--- a/install/tools/ipa-managed-entries
+++ b/install/tools/ipa-managed-entries
@@ -28,8 +28,8 @@ try:
from ipaserver import ipaldap
from ipaserver.plugins.ldap2 import ldap2
from ipalib import api, errors
- from ipalib.dn import *
from ipapython.ipa_log_manager import *
+ from ipapython.dn import DN
except ImportError:
print >> sys.stderr, """\
@@ -92,9 +92,8 @@ def main():
('cn', 'Definitions'),
('cn', 'Managed Entries'),
('cn', 'etc'),
- DN(api.env.basedn)
+ api.env.basedn
)
- managed_entry_definitions_dn = str(managed_entry_definitions_dn)
conn = None
try:
@@ -125,13 +124,13 @@ def main():
# List available Managed Entry Plugins
managed_entries = None
try:
- entries = conn.search_s(
+ entries = conn.getList(
managed_entry_definitions_dn, ldap.SCOPE_SUBTREE, filter
)
except Exception, e:
root_logger.debug("Search for managed entries failed: %s" % str(e))
sys.exit("Unable to find managed entries at %s" % managed_entry_definitions_dn)
- managed_entries = [entry.cn for entry in entries]
+ managed_entries = [entry.getValue('cn') for entry in entries]
if managed_entries:
print "Available Managed Entry Definitions:"
for managed_entry in managed_entries:
@@ -142,22 +141,18 @@ def main():
if not options.managed_entry:
sys.exit("\nYou must specify a managed entry definition")
else:
- rdn = DN(
- ('cn', options.managed_entry),
- DN(managed_entry_definitions_dn)
- )
- def_dn = str(rdn)
+ def_dn = DN(('cn', options.managed_entry), managed_entry_definitions_dn)
disabled = True
try:
- entries = conn.search_s(def_dn,
+ entry = conn.getEntry(def_dn,
ldap.SCOPE_BASE,
filter,
['originfilter'],
)
disable_attr = '(objectclass=disable)'
try:
- org_filter = entries[0].originfilter
+ org_filter = entry.getValue('originfilter')
disabled = re.search(r'%s' % disable_attr, org_filter)
except KeyError:
sys.exit("%s is not a valid Managed Entry" % def_dn)
diff --git a/install/tools/ipa-nis-manage b/install/tools/ipa-nis-manage
index 1c6de7b57..5ef3ce0e6 100755
--- a/install/tools/ipa-nis-manage
+++ b/install/tools/ipa-nis-manage
@@ -30,6 +30,7 @@ try:
from ipaserver.plugins.ldap2 import ldap2
from ipalib import api, errors
from ipapython.ipa_log_manager import *
+ from ipapython.dn import DN
except ImportError:
print >> sys.stderr, """\
There was a problem importing one of the required Python modules. The
@@ -39,8 +40,8 @@ error was:
""" % sys.exc_value
sys.exit(1)
-nis_config_dn = "cn=NIS Server,cn=plugins,cn=config"
-compat_dn = "cn=Schema Compatibility,cn=plugins,cn=config"
+nis_config_dn = DN(('cn', 'NIS Server'), ('cn', 'plugins'), ('cn', 'config'))
+compat_dn = DN(('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config'))
def parse_options():
usage = "%prog [options] <enable|disable>\n"
@@ -120,7 +121,7 @@ def main():
try:
conn = ldap2(shared_instance=False, base_dn='')
conn.connect(
- bind_dn='cn=directory manager', bind_pw=dirman_password
+ bind_dn=DN(('cn', 'directory manager')), bind_pw=dirman_password
)
except errors.ExecutionError, lde:
sys.exit("An error occurred while connecting to the server: %s" % str(lde))
diff --git a/install/tools/ipa-replica-install b/install/tools/ipa-replica-install
index c322cb62e..d7baf9c05 100755
--- a/install/tools/ipa-replica-install
+++ b/install/tools/ipa-replica-install
@@ -36,12 +36,13 @@ from ipaserver.install.installutils import ReplicaConfig, expand_replica_info, r
from ipaserver.install.installutils import get_host_name, BadHostError
from ipaserver.plugins.ldap2 import ldap2
from ipaserver.install import cainstance
-from ipapython import version
from ipalib import api, errors, util
+from ipapython import version
from ipapython.config import IPAOptionParser
from ipapython import sysrestore
from ipapython import services as ipaservices
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
log_file_name = "/var/log/ipareplica-install.log"
CACERT = "/etc/ipa/ca.crt"
@@ -204,7 +205,7 @@ def install_http(config, auto_redirect):
return http
def install_bind(config, options):
- api.Backend.ldap2.connect(bind_dn="cn=Directory Manager",
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
bind_pw=config.dirman_password)
if options.forwarders:
forwarders = options.forwarders
@@ -246,7 +247,7 @@ def install_dns_records(config, options):
cur_uri = api.Backend.ldap2.ldap_uri
object.__setattr__(api.Backend.ldap2, 'ldap_uri',
'ldaps://%s' % ipautil.format_netloc(config.master_host_name))
- api.Backend.ldap2.connect(bind_dn="cn=Directory Manager",
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
bind_pw=config.dirman_password,
tls_cacertfile=CACERT)
bind = bindinstance.BindInstance(dm_password=config.dirman_password)
@@ -360,10 +361,10 @@ def main():
try:
fd = open("/etc/ipa/default.conf", "w")
fd.write("[global]\n")
- fd.write("host=" + config.host_name + "\n")
- fd.write("basedn=" + ipautil.realm_to_suffix(config.realm_name) + "\n")
- fd.write("realm=" + config.realm_name + "\n")
- fd.write("domain=" + config.domain_name + "\n")
+ fd.write("host=%s\n" % config.host_name)
+ fd.write("basedn=%s\n" % str(ipautil.realm_to_suffix(config.realm_name)))
+ fd.write("realm=%s\n" % config.realm_name)
+ fd.write("domain=%s\n" % config.domain_name)
fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % ipautil.format_netloc(config.host_name))
fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(config.realm_name))
if ipautil.file_exists(config.dir + "/cacert.p12"):
@@ -404,14 +405,14 @@ def main():
ldapuri = 'ldaps://%s' % ipautil.format_netloc(config.master_host_name)
try:
conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='')
- conn.connect(bind_dn='cn=directory manager',
+ conn.connect(bind_dn=DN(('cn', 'directory manager')),
bind_pw=config.dirman_password,
tls_cacertfile=CACERT)
replman = ReplicationManager(config.realm_name, config.master_host_name,
config.dirman_password)
found = False
try:
- entry = conn.find_entries(u'fqdn=%s' % host, ['dn', 'fqdn'], u'%s,%s' % (api.env.container_host, api.env.basedn))
+ entry = conn.find_entries(u'fqdn=%s' % host, ['dn', 'fqdn'], DN(api.env.container_host, api.env.basedn))
print "The host %s already exists on the master server.\nYou should remove it before proceeding:" % host
print " %% ipa host-del %s" % host
found = True
diff --git a/install/tools/ipa-replica-manage b/install/tools/ipa-replica-manage
index b095daf03..b2e819d1e 100755
--- a/install/tools/ipa-replica-manage
+++ b/install/tools/ipa-replica-manage
@@ -29,8 +29,8 @@ from ipaserver.install import bindinstance
from ipaserver import ipaldap
from ipapython import version
from ipalib import api, errors, util
-from ipalib.dn import DN
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
CACERT = "/etc/ipa/ca.crt"
@@ -125,23 +125,28 @@ def list_replicas(realm, host, replica, dirman_passwd, verbose):
conn.do_simple_bind(bindpw=dirman_passwd)
else:
conn.do_sasl_gssapi_bind()
+ except Exception, e:
+ print "Failed to connect to host '%s': %s" % (host, str(e))
+ return
- dn = 'cn=masters,cn=ipa,cn=etc,%s' % ipautil.realm_to_suffix(realm)
- entries = conn.search_s(dn, ldap.SCOPE_ONELEVEL)
-
+ dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm))
+ try:
+ entries = conn.getList(dn, ldap.SCOPE_ONELEVEL)
+ except:
+ print "Failed read master data from '%s': %s" % (host, str(e))
+ return
+ else:
for ent in entries:
- peers[ent.cn] = ['master', '']
-
- dn = 'cn=replicas,cn=ipa,cn=etc,%s' % ipautil.realm_to_suffix(realm)
- entries = conn.search_s(dn, ldap.SCOPE_ONELEVEL)
+ peers[ent.getValue('cn')] = ['master', '']
+ dn = DN(('cn', 'replicas'), ('cn', 'ipa'), ('cn', 'etc'), ipautil.realm_to_suffix(realm))
+ try:
+ entries = conn.getList(dn, ldap.SCOPE_ONELEVEL)
+ except:
+ pass
+ else:
for ent in entries:
- peers[ent.cn] = ent.ipaconfigstring.split(':')
-
- except Exception, e:
- print "Failed to get data from '%s': %s" % (host, str(e))
- return
-
+ peers[ent.getValue('cn')] = ent.getValue('ipaConfigString').split(':')
if not replica:
for k, p in peers.iteritems():
@@ -164,8 +169,8 @@ def list_replicas(realm, host, replica, dirman_passwd, verbose):
repl = replication.ReplicationManager(realm, winsync_peer,
dirman_passwd)
cn, dn = repl.agreement_dn(replica)
- entries = repl.conn.search_s(dn, ldap.SCOPE_BASE,
- "(objectclass=nsDSWindowsReplicationAgreement)")
+ entries = repl.conn.getList(dn, ldap.SCOPE_BASE,
+ "(objectclass=nsDSWindowsReplicationAgreement)")
ent_type = 'winsync'
else:
repl = replication.ReplicationManager(realm, replica,
@@ -177,13 +182,13 @@ def list_replicas(realm, host, replica, dirman_passwd, verbose):
return
for entry in entries:
- print '%s: %s' % (entry.nsds5replicahost, ent_type)
+ print '%s: %s' % (entry.getValue('nsds5replicahost'), ent_type)
if verbose:
- print " last init status: %s" % entry.nsds5replicalastinitstatus
- print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastinitend))
- print " last update status: %s" % entry.nsds5replicalastupdatestatus
- print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.nsds5replicalastupdateend))
+ print " last init status: %s" % entry.getValue('nsds5replicalastinitstatus')
+ print " last init ended: %s" % str(ipautil.parse_generalized_time(entry.getValue('nsds5replicalastinitend')))
+ print " last update status: %s" % entry.getValue('nsds5replicalastupdatestatus')
+ print " last update ended: %s" % str(ipautil.parse_generalized_time(entry.getValue('nsds5replicalastupdateend')))
def del_link(realm, replica1, replica2, dirman_passwd, force=False):
@@ -254,9 +259,9 @@ def del_link(realm, replica1, replica2, dirman_passwd, force=False):
if type1 == replication.WINSYNC:
try:
- dn = 'cn=%s,cn=replicas,cn=ipa,cn=etc,%s' % (replica2,
- ipautil.realm_to_suffix(realm))
- entries = repl1.conn.search_s(dn, ldap.SCOPE_SUBTREE)
+ dn = DN(('cn', replica2), ('cn', 'replicas'), ('cn', 'ipa'), ('cn', 'etc'),
+ ipautil.realm_to_suffix(realm))
+ entries = repl1.conn.getList(dn, ldap.SCOPE_SUBTREE)
if len(entries) != 0:
dnset = repl1.conn.get_dns_sorted_by_length(entries,
reverse=True)
@@ -300,11 +305,11 @@ def del_master(realm, hostname, options):
force_del = True
if force_del:
- dn = 'cn=masters,cn=ipa,cn=etc,%s' % thisrepl.suffix
- res = thisrepl.conn.search_s(dn, ldap.SCOPE_ONELEVEL)
+ dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), thisrepl.suffix)
+ entries = thisrepl.conn.getList(dn, ldap.SCOPE_ONELEVEL)
replica_names = []
- for entry in res:
- replica_names.append(entry.cn)
+ for entry in entries:
+ replica_names.append(entry.getValue('cn'))
else:
# Get list of agreements.
replica_names = delrepl.find_ipa_replication_agreements()
@@ -340,7 +345,7 @@ def del_master(realm, hostname, options):
if bindinstance.dns_container_exists(options.host, thisrepl.suffix,
dm_password=options.dirman_passwd):
if options.dirman_passwd:
- api.Backend.ldap2.connect(bind_dn='cn=Directory Manager',
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')),
bind_pw=options.dirman_passwd)
else:
ccache = krbV.default_context().default_ccache().name
@@ -366,7 +371,7 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
repl = replication.ReplicationManager(realm, replica1, dirman_passwd)
if repl.get_agreement_type(replica2) == replication.WINSYNC:
agreement = repl.get_replication_agreement(replica2)
- sys.exit("winsync agreement already exists on subtree %s" %
+ sys.exit("winsync agreement already exists on subtree %s" %
agreement.getValue('nsds7WindowsReplicaSubtree'))
else:
sys.exit("A replication agreement to %s already exists" % replica2)
@@ -407,8 +412,8 @@ def add_link(realm, replica1, replica2, dirman_passwd, options):
# from scratch
try:
masters_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), (api.env.basedn))
- master1_dn = str(DN(('cn', replica1), masters_dn))
- master2_dn = str(DN(('cn', replica2), masters_dn))
+ master1_dn = DN(('cn', replica1), masters_dn)
+ master2_dn = DN(('cn', replica2), masters_dn)
repl1.conn.getEntry(master1_dn, ldap.SCOPE_BASE)
repl1.conn.getEntry(master2_dn, ldap.SCOPE_BASE)
diff --git a/install/tools/ipa-replica-prepare b/install/tools/ipa-replica-prepare
index 19360fdf2..210a9de11 100755
--- a/install/tools/ipa-replica-prepare
+++ b/install/tools/ipa-replica-prepare
@@ -35,6 +35,7 @@ from ipaserver.plugins.ldap2 import ldap2
from ipapython import version
from ipapython.config import IPAOptionParser
from ipalib import api, errors, util
+from ipapython.dn import DN
def parse_options():
usage = "%prog [options] FQDN (e.g. replica.example.com)"
@@ -99,13 +100,16 @@ def parse_options():
def get_subject_base(host_name, dm_password, suffix):
try:
conn = ldap2(shared_instance=False, base_dn=suffix)
- conn.connect(bind_dn='cn=directory manager', bind_pw=dm_password)
+ conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password)
except errors.ExecutionError, e:
root_logger.critical("Could not connect to the Directory Server on %s" % host_name)
raise e
(dn, entry_attrs) = conn.get_ipa_config()
conn.disconnect()
- return entry_attrs.get('ipacertificatesubjectbase', [None])[0]
+ subject_base = entry_attrs.get('ipacertificatesubjectbase', [None])[0]
+ if subject_base is not None:
+ subject_base = DN(subject_base)
+ return subject_base
def check_ipa_configuration(realm_name):
config_dir = dsinstance.config_dirname(dsinstance.realm_to_serverid(realm_name))
@@ -200,7 +204,7 @@ def save_config(dir, realm_name, host_name,
config.set("realm", "master_host_name", host_name)
config.set("realm", "domain_name", domain_name)
config.set("realm", "destination_host", dest_host)
- config.set("realm", "subject_base", subject_base)
+ config.set("realm", "subject_base", str(subject_base))
fd = open(dir + "/realm_info", "w")
config.write(fd)
@@ -260,7 +264,7 @@ def main():
# Try out the password
try:
conn = ldap2(shared_instance=False)
- conn.connect(bind_dn='cn=directory manager', bind_pw=dirman_password)
+ conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dirman_password)
conn.disconnect()
except errors.ACIError:
sys.exit("\nThe password provided is incorrect for LDAP server %s" % api.env.host)
@@ -431,7 +435,7 @@ def main():
if options.ip_address:
print "Adding DNS records for %s" % replica_fqdn
- api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=dirman_password)
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dirman_password)
domain = replica_fqdn.split(".")
name = domain.pop(0)
diff --git a/install/tools/ipa-server-certinstall b/install/tools/ipa-server-certinstall
index 3b19f0452..bc4dde272 100755
--- a/install/tools/ipa-server-certinstall
+++ b/install/tools/ipa-server-certinstall
@@ -32,6 +32,7 @@ from ipapython.ipautil import user_input
from ipaserver.install import certs, dsinstance, httpinstance, installutils
from ipalib import api
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
from ipaserver.plugins.ldap2 import ldap2
def get_realm_name():
@@ -66,9 +67,9 @@ def parse_options():
def set_ds_cert_name(cert_name, dm_password):
conn = ldap2(shared_instance=False, base_dn='')
- conn.connect(bind_dn='cn=directory manager', bind_pw=dm_password)
+ conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password)
mod = {'nssslpersonalityssl': cert_name}
- conn.update_entry('cn=RSA,cn=encryption,cn=config', mod)
+ conn.update_entry(DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')), mod)
conn.disconnect()
def choose_server_cert(server_certs):
diff --git a/install/tools/ipa-server-install b/install/tools/ipa-server-install
index d7de70631..d9682bbb3 100755
--- a/install/tools/ipa-server-install
+++ b/install/tools/ipa-server-install
@@ -60,11 +60,11 @@ from ipapython.ipautil import *
from ipapython import ipautil
from ipalib import api, errors, util
from ipapython.config import IPAOptionParser
-from ipalib.dn import DN
from ipalib.x509 import load_certificate_from_file, load_certificate_chain_from_file
from ipalib.util import validate_domain_name
from ipapython import services as ipaservices
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
pw_name = None
uninstalling = False
@@ -530,13 +530,13 @@ def set_subject_in_config(realm_name, dm_password, suffix, subject_base):
)
try:
conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn=suffix)
- conn.connect(bind_dn='cn=directory manager', bind_pw=dm_password)
+ conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password)
except errors.ExecutionError, e:
root_logger.critical("Could not connect to the Directory Server on %s" % realm_name)
raise e
(dn, entry_attrs) = conn.get_ipa_config()
if 'ipacertificatesubjectbase' not in entry_attrs:
- mod = {'ipacertificatesubjectbase': subject_base}
+ mod = {'ipacertificatesubjectbase': str(subject_base)}
conn.update_entry(dn, mod)
conn.disconnect()
@@ -770,7 +770,7 @@ def main():
realm_name = options.realm_name.upper()
if not options.subject:
- options.subject = "O=%s" % realm_name
+ options.subject = DN(('O', realm_name))
if not options.dm_password:
dm_password = read_dm_password()
@@ -840,10 +840,10 @@ def main():
target_fname = '/etc/ipa/default.conf'
fd = open(target_fname, "w")
fd.write("[global]\n")
- fd.write("host=" + host_name + "\n")
- fd.write("basedn=" + ipautil.realm_to_suffix(realm_name) + "\n")
- fd.write("realm=" + realm_name + "\n")
- fd.write("domain=" + domain_name + "\n")
+ fd.write("host=%s\n" % host_name)
+ fd.write("basedn=%s\n" % ipautil.realm_to_suffix(realm_name))
+ fd.write("realm=%s\n" % realm_name)
+ fd.write("domain=%s\n" % domain_name)
fd.write("xmlrpc_uri=https://%s/ipa/xml\n" % format_netloc(host_name))
fd.write("ldap_uri=ldapi://%%2fvar%%2frun%%2fslapd-%s.socket\n" % dsinstance.realm_to_serverid(realm_name))
fd.write("enable_ra=True\n")
@@ -1046,7 +1046,7 @@ def main():
persistent_search=options.persistent_search,
serial_autoincrement=options.serial_autoincrement)
if options.setup_dns:
- api.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=dm_password)
+ api.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password)
bind.create_instance()
print ""
diff --git a/install/tools/ipa-upgradeconfig b/install/tools/ipa-upgradeconfig
index 951bd4854..3041cb60b 100644
--- a/install/tools/ipa-upgradeconfig
+++ b/install/tools/ipa-upgradeconfig
@@ -253,7 +253,7 @@ def update_dbmodules(realm, filename="/etc/krb5.conf"):
newfile.append('#%s' % line)
prefix = ''
continue
-
+
newfile.append('%s%s' % (prefix, line))
# Append updated dbmodules information
diff --git a/install/tools/ipactl b/install/tools/ipactl
index 22a4f6e03..e173d10c1 100755
--- a/install/tools/ipactl
+++ b/install/tools/ipactl
@@ -26,10 +26,10 @@ try:
from ipaserver.install.dsinstance import config_dirname, realm_to_serverid
from ipaserver.install.installutils import is_ipa_configured, ScriptError
from ipapython.ipautil import wait_for_open_ports, wait_for_open_socket
+ from ipalib import api, errors
from ipapython import sysrestore
from ipapython import config
- from ipalib import api, errors
- from ipalib.dn import DN
+ from ipapython.dn import DN
import ldap
import ldap.sasl
import ldapurl
@@ -107,8 +107,7 @@ def emit_err(err):
sys.stderr.write(err + '\n')
def get_config(dirsrv):
- base = "cn=%s,cn=masters,cn=ipa,cn=etc,%s" % (api.env.host,
- api.env.basedn)
+ base = DN(('cn', api.env.host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
srcfilter = '(ipaConfigString=enabledService)'
attrs = ['cn', 'ipaConfigString']
if not dirsrv.is_running():
@@ -127,7 +126,7 @@ def get_config(dirsrv):
wait_for_open_ports(host, [int(port)], timeout=api.env.startup_timeout)
con = ldap.initialize(api.env.ldap_uri)
con.sasl_interactive_bind_s('', SASL_EXTERNAL)
- res = con.search_st(base,
+ res = con.search_st(str(base),
ldap.SCOPE_SUBTREE,
filterstr=srcfilter,
attrlist=attrs,
@@ -138,12 +137,10 @@ def get_config(dirsrv):
"Directory Server is stopped", 3)
except ldap.NO_SUCH_OBJECT:
masters_list = []
- dn = str(DN('cn=masters,cn=ipa,cn=etc,%s' % api.env.basedn))
+ dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
attrs = ['cn']
try:
- entries = con.search_s(dn,
- ldap.SCOPE_ONELEVEL,
- attrlist=attrs,)
+ entries = con.search_s(str(dn), ldap.SCOPE_ONELEVEL, attrlist=attrs)
except Exception, e:
masters_list.append("No master found because of error: %s" % str(e))
else:
diff --git a/ipa-client/ipa-install/ipa-client-automount b/ipa-client/ipa-install/ipa-client-automount
index 713a0e425..d04350ed8 100755
--- a/ipa-client/ipa-install/ipa-client-automount
+++ b/ipa-client/ipa-install/ipa-client-automount
@@ -31,12 +31,12 @@ import SSSDConfig
from optparse import OptionParser
from ipalib import api, errors
-from ipalib.dn import DN
from ipapython import sysrestore
from ipapython import ipautil
from ipaclient import ipadiscovery
from ipaclient import ipachangeconf
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
from ipapython import services as ipaservices
AUTOFS_CONF = '/etc/sysconfig/autofs'
diff --git a/ipa-client/ipa-install/ipa-client-install b/ipa-client/ipa-install/ipa-client-install
index 081ae7f28..3b4d14d48 100755
--- a/ipa-client/ipa-install/ipa-client-install
+++ b/ipa-client/ipa-install/ipa-client-install
@@ -41,6 +41,7 @@ try:
from ipapython import certmonger
from ipapython.config import IPAOptionParser
from ipalib import api, errors
+ from ipapython.dn import DN
import SSSDConfig
from ConfigParser import RawConfigParser
from optparse import SUPPRESS_HELP, OptionGroup
@@ -510,8 +511,8 @@ def configure_ldap_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server, d
{'name':'ldap_version', 'type':'option', 'value':'3'},
{'name':'base', 'type':'option', 'value':cli_basedn},
{'name':'empty', 'type':'empty'},
- {'name':'nss_base_passwd', 'type':'option', 'value':'cn=users,cn=accounts,'+cli_basedn+'?sub'},
- {'name':'nss_base_group', 'type':'option', 'value':'cn=groups,cn=accounts,'+cli_basedn+'?sub'},
+ {'name':'nss_base_passwd', 'type':'option', 'value':str(DN(('cn', 'users'), ('cn', 'accounts'), cli_basedn))+'?sub'},
+ {'name':'nss_base_group', 'type':'option', 'value':str(DN(('cn', 'groups'), ('cn', 'accounts'), cli_basedn))+'?sub'},
{'name':'nss_schema', 'type':'option', 'value':'rfc2307bis'},
{'name':'nss_map_attribute', 'type':'option', 'value':'uniqueMember member'},
{'name':'nss_initgroups_ignoreusers', 'type':'option', 'value':'root,dirsrv'},
@@ -555,8 +556,8 @@ def configure_nslcd_conf(fstore, cli_basedn, cli_realm, cli_domain, cli_server,
{'name':'ldap_version', 'type':'option', 'value':'3'},
{'name':'base', 'type':'option', 'value':cli_basedn},
{'name':'empty', 'type':'empty'},
- {'name':'base passwd', 'type':'option', 'value':'cn=users,cn=accounts,'+cli_basedn},
- {'name':'base group', 'type':'option', 'value':'cn=groups,cn=accounts,'+cli_basedn},
+ {'name':'base passwd', 'type':'option', 'value':str(DN(('cn', 'users'), ('cn', 'accounts'), cli_basedn))},
+ {'name':'base group', 'type':'option', 'value':str(DN(('cn', 'groups'), ('cn', 'accounts'), cli_basedn))},
{'name':'map group', 'type':'option', 'value':'uniqueMember member'},
{'name':'timelimit', 'type':'option', 'value':'15'},
{'name':'empty', 'type':'empty'}]
@@ -743,9 +744,9 @@ def configure_certmonger(fstore, subject_base, cli_realm, hostname, options):
# Request our host cert
if started:
client_nss_nickname = client_nss_nickname_format % hostname
- subject = 'CN=%s,%s' % (hostname, subject_base)
+ subject = DN(('CN', hostname), subject_base)
try:
- run(["ipa-getcert", "request", "-d", "/etc/pki/nssdb", "-n", client_nss_nickname, "-N", subject, "-K", principal])
+ run(["ipa-getcert", "request", "-d", "/etc/pki/nssdb", "-n", client_nss_nickname, "-N", str(subject), "-K", principal])
except:
root_logger.error(
"%s request for host certificate failed", cmonger.service_name)
@@ -1337,7 +1338,7 @@ def install(options, env, fstore, statestore):
cli_basedn = ds.basedn
cli_basedn_source = ds.basedn_source
root_logger.debug("will use discovered basedn: %s", cli_basedn)
- subject_base = "O=%s" % cli_realm
+ subject_base = DN(('O', cli_realm))
# Now do a sanity check on the other servers
if options.server and len(options.server) > 1:
@@ -1431,7 +1432,7 @@ def install(options, env, fstore, statestore):
root_logger.error("Test kerberos configuration failed")
return CLIENT_INSTALL_ERROR
env['KRB5_CONFIG'] = krb_name
- join_args = ["/usr/sbin/ipa-join", "-s", cli_server[0], "-b", realm_to_suffix(cli_realm)]
+ join_args = ["/usr/sbin/ipa-join", "-s", cli_server[0], "-b", str(realm_to_suffix(cli_realm))]
if options.debug:
join_args.append("-d")
env['XMLRPC_TRACE_CURL'] = 'yes'
@@ -1508,6 +1509,7 @@ def install(options, env, fstore, statestore):
start = start + 29
subject_base = stderr[start:]
subject_base = subject_base.strip()
+ subject_base = DN(subject_base)
finally:
if options.principal is not None:
diff --git a/ipa-client/ipaclient/ipadiscovery.py b/ipa-client/ipaclient/ipadiscovery.py
index ca13d9c19..f91d4075a 100644
--- a/ipa-client/ipaclient/ipadiscovery.py
+++ b/ipa-client/ipaclient/ipadiscovery.py
@@ -28,7 +28,7 @@ from dns.exception import DNSException
from ipapython.ipautil import run, CalledProcessError, valid_ip, get_ipa_basedn, \
realm_to_suffix, format_netloc
-
+from ipapython.dn import DN
NOT_FQDN = -1
NO_LDAP_SERVER = -2
@@ -320,7 +320,7 @@ class IPADiscovery(object):
root_logger.debug(
"Search for (objectClass=krbRealmContainer) in %s (sub)",
self.basedn)
- lret = lh.search_s("cn=kerberos,"+self.basedn, ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)")
+ lret = lh.search_s(str(DN(('cn', 'kerberos'), self.basedn)), ldap.SCOPE_SUBTREE, "(objectClass=krbRealmContainer)")
if not lret:
#something very wrong
return [REALM_NOT_FOUND]
diff --git a/ipalib/__init__.py b/ipalib/__init__.py
index dd861a826..8bf37f048 100644
--- a/ipalib/__init__.py
+++ b/ipalib/__init__.py
@@ -878,7 +878,7 @@ from backend import Backend
from frontend import Command, LocalOrRemote, Updater
from frontend import Object, Method, Property
from crud import Create, Retrieve, Update, Delete, Search
-from parameters import DefaultFrom, Bool, Flag, Int, Decimal, Bytes, Str, IA5Str, Password
+from parameters import DefaultFrom, Bool, Flag, Int, Decimal, Bytes, Str, IA5Str, Password, DNParam
from parameters import BytesEnum, StrEnum, AccessTime, File
from errors import SkipPluginModule
from text import _, ngettext, GettextFactory, NGettextFactory
diff --git a/ipalib/aci.py b/ipalib/aci.py
index 1b607a393..53c0053c6 100755
--- a/ipalib/aci.py
+++ b/ipalib/aci.py
@@ -254,32 +254,6 @@ class ACI:
# We got this far so lets declare them the same
return True
-def extract_group_cns(aci_list, client):
- """
- Extracts all the cn's from a list of aci's and returns them as a hash
- from group_dn to group_cn.
-
- It first tries to cheat by looking at the first rdn for the
- group dn. If that's not cn for some reason, it looks up the group.
- """
- group_dn_to_cn = {}
- for aci in aci_list:
- for dn in (aci.source_group, aci.dest_group):
- if not group_dn_to_cn.has_key(dn):
- rdn_list = ldap.explode_dn(dn, 0)
- first_rdn = rdn_list[0]
- (type,value) = first_rdn.split('=')
- if type == "cn":
- group_dn_to_cn[dn] = value
- else:
- try:
- group = client.get_entry_by_dn(dn, ['cn'])
- group_dn_to_cn[dn] = group.getValue('cn')
- except Exception:
- group_dn_to_cn[dn] = 'unknown'
-
- return group_dn_to_cn
-
if __name__ == '__main__':
# a = ACI('(targetattr="title")(targetfilter="(memberOf=cn=bar,cn=groups,cn=accounts ,dc=example,dc=com)")(version 3.0;acl "foobar";allow (write) groupdn="ldap:///cn=foo,cn=groups,cn=accounts,dc=example,dc=com";)')
# print a
diff --git a/ipalib/config.py b/ipalib/config.py
index 5e3ef8d9b..3c9aeaa28 100644
--- a/ipalib/config.py
+++ b/ipalib/config.py
@@ -35,6 +35,7 @@ import os
from os import path
import sys
from socket import getfqdn
+from ipapython.dn import DN
from base import check_name
from constants import CONFIG_SECTION
@@ -256,12 +257,14 @@ class Env(object):
value = m[value]
elif value.isdigit():
value = int(value)
+ elif key in ('basedn'):
+ value = DN(value)
else:
try:
value = float(value)
except (TypeError, ValueError):
pass
- assert type(value) in (unicode, int, float, bool, NoneType)
+ assert type(value) in (unicode, int, float, bool, NoneType, DN)
object.__setattr__(self, key, value)
self.__d[key] = value
diff --git a/ipalib/constants.py b/ipalib/constants.py
index f0f89a3b3..59649865b 100644
--- a/ipalib/constants.py
+++ b/ipalib/constants.py
@@ -22,6 +22,7 @@
All constants centralised in one file.
"""
import socket
+from ipapython.dn import DN
from ipapython.version import VERSION
try:
FQDN = socket.getfqdn()
@@ -69,44 +70,44 @@ DEFAULT_CONFIG = (
# Domain, realm, basedn:
('domain', 'example.com'),
('realm', 'EXAMPLE.COM'),
- ('basedn', 'dc=example,dc=com'),
+ ('basedn', DN(('dc', 'example'), ('dc', 'com'))),
# LDAP containers:
- ('container_accounts', 'cn=accounts'),
- ('container_user', 'cn=users,cn=accounts'),
- ('container_group', 'cn=groups,cn=accounts'),
- ('container_service', 'cn=services,cn=accounts'),
- ('container_host', 'cn=computers,cn=accounts'),
- ('container_hostgroup', 'cn=hostgroups,cn=accounts'),
- ('container_rolegroup', 'cn=roles,cn=accounts'),
- ('container_permission', 'cn=permissions,cn=pbac'),
- ('container_privilege', 'cn=privileges,cn=pbac'),
- ('container_automount', 'cn=automount'),
- ('container_policies', 'cn=policies'),
- ('container_configs', 'cn=configs,cn=policies'),
- ('container_roles', 'cn=roles,cn=policies'),
- ('container_applications', 'cn=applications,cn=configs,cn=policies'),
- ('container_policygroups', 'cn=policygroups,cn=configs,cn=policies'),
- ('container_policylinks', 'cn=policylinks,cn=configs,cn=policies'),
- ('container_netgroup', 'cn=ng,cn=alt'),
- ('container_hbac', 'cn=hbac'),
- ('container_hbacservice', 'cn=hbacservices,cn=hbac'),
- ('container_hbacservicegroup', 'cn=hbacservicegroups,cn=hbac'),
- ('container_dns', 'cn=dns'),
- ('container_virtual', 'cn=virtual operations,cn=etc'),
- ('container_sudorule', 'cn=sudorules,cn=sudo'),
- ('container_sudocmd', 'cn=sudocmds,cn=sudo'),
- ('container_sudocmdgroup', 'cn=sudocmdgroups,cn=sudo'),
- ('container_entitlements', 'cn=entitlements,cn=etc'),
- ('container_automember', 'cn=automember,cn=etc'),
- ('container_selinux', 'cn=usermap,cn=selinux'),
- ('container_s4u2proxy', 'cn=s4u2proxy,cn=etc'),
- ('container_cifsdomains', 'cn=ad,cn=etc'),
- ('container_trusts', 'cn=trusts'),
- ('container_adtrusts', 'cn=ad,cn=trusts'),
- ('container_ranges', 'cn=ranges,cn=etc'),
- ('container_dna', 'cn=dna,cn=ipa,cn=etc'),
- ('container_dna_posix_ids', 'cn=posix-ids,cn=dna,cn=ipa,cn=etc'),
+ ('container_accounts', DN(('cn', 'accounts'))),
+ ('container_user', DN(('cn', 'users'), ('cn', 'accounts'))),
+ ('container_group', DN(('cn', 'groups'), ('cn', 'accounts'))),
+ ('container_service', DN(('cn', 'services'), ('cn', 'accounts'))),
+ ('container_host', DN(('cn', 'computers'), ('cn', 'accounts'))),
+ ('container_hostgroup', DN(('cn', 'hostgroups'), ('cn', 'accounts'))),
+ ('container_rolegroup', DN(('cn', 'roles'), ('cn', 'accounts'))),
+ ('container_permission', DN(('cn', 'permissions'), ('cn', 'pbac'))),
+ ('container_privilege', DN(('cn', 'privileges'), ('cn', 'pbac'))),
+ ('container_automount', DN(('cn', 'automount'))),
+ ('container_policies', DN(('cn', 'policies'))),
+ ('container_configs', DN(('cn', 'configs'), ('cn', 'policies'))),
+ ('container_roles', DN(('cn', 'roles'), ('cn', 'policies'))),
+ ('container_applications', DN(('cn', 'applications'), ('cn', 'configs'), ('cn', 'policies'))),
+ ('container_policygroups', DN(('cn', 'policygroups'), ('cn', 'configs'), ('cn', 'policies'))),
+ ('container_policylinks', DN(('cn', 'policylinks'), ('cn', 'configs'), ('cn', 'policies'))),
+ ('container_netgroup', DN(('cn', 'ng'), ('cn', 'alt'))),
+ ('container_hbac', DN(('cn', 'hbac'))),
+ ('container_hbacservice', DN(('cn', 'hbacservices'), ('cn', 'hbac'))),
+ ('container_hbacservicegroup', DN(('cn', 'hbacservicegroups'), ('cn', 'hbac'))),
+ ('container_dns', DN(('cn', 'dns'))),
+ ('container_virtual', DN(('cn', 'virtual operations'), ('cn', 'etc'))),
+ ('container_sudorule', DN(('cn', 'sudorules'), ('cn', 'sudo'))),
+ ('container_sudocmd', DN(('cn', 'sudocmds'), ('cn', 'sudo'))),
+ ('container_sudocmdgroup', DN(('cn', 'sudocmdgroups'), ('cn', 'sudo'))),
+ ('container_entitlements', DN(('cn', 'entitlements'), ('cn', 'etc'))),
+ ('container_automember', DN(('cn', 'automember'), ('cn', 'etc'))),
+ ('container_selinux', DN(('cn', 'usermap'), ('cn', 'selinux'))),
+ ('container_s4u2proxy', DN(('cn', 's4u2proxy'), ('cn', 'etc'))),
+ ('container_cifsdomains', DN(('cn', 'ad'), ('cn', 'etc'))),
+ ('container_trusts', DN(('cn', 'trusts'))),
+ ('container_adtrusts', DN(('cn', 'ad'), ('cn', 'trusts'))),
+ ('container_ranges', DN(('cn', 'ranges'), ('cn', 'etc'))),
+ ('container_dna', DN(('cn', 'dna'), ('cn', 'ipa'), ('cn', 'etc'))),
+ ('container_dna_posix_ids', DN(('cn', 'posix-ids'), ('cn', 'dna'), ('cn', 'ipa'), ('cn', 'etc'))),
# Ports, hosts, and URIs:
# FIXME: let's renamed xmlrpc_uri to rpc_xml_uri
diff --git a/ipalib/encoder.py b/ipalib/encoder.py
deleted file mode 100644
index 691f4d8ca..000000000
--- a/ipalib/encoder.py
+++ /dev/null
@@ -1,213 +0,0 @@
-# Authors:
-# Pavel Zuna <pzuna@redhat.com>
-#
-# Copyright (C) 2009 Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-Encoding capabilities.
-"""
-
-from decimal import Decimal
-
-class EncoderSettings(object):
- """
- Container for encoder settings.
- """
- encode_to = 'utf-8'
- encode_none = False
- encode_dict_keys = False
- encode_dict_keys_postprocess = True
- encode_dict_vals = True
- encode_dict_vals_postprocess = True
- encode_postprocessor = staticmethod(lambda x: x)
-
- decode_from = 'utf-8'
- decode_none = False
- decode_dict_keys = False
- decode_dict_keys_postprocess = True
- decode_dict_vals = True
- decode_dict_vals_postprocess = True
- decode_dict_vals_table = dict()
- decode_dict_vals_table_keygen = staticmethod(lambda x, y: x)
- decode_postprocessor = staticmethod(lambda x: x)
-
-
-class Encoder(object):
- """
- Base class implementing encoding of python scalar types to strings
- and vise-versa.
- """
-
- encoder_settings = EncoderSettings()
-
- def __init__(self):
- # each instance should have its own settings
- self.encoder_settings = EncoderSettings()
-
- def _decode_dict_val(self, key, val):
- f = self.encoder_settings.decode_dict_vals_table.get(
- self.encoder_settings.decode_dict_vals_table_keygen(key, val)
- )
- if f:
- return val
- return self.decode(val)
-
- def encode(self, var):
- """
- Encode any python built-in python type variable into `self.encode_to`.
-
- Compound types have their individual members encoded.
-
- Returns an encoded copy of 'var'.
- """
- if isinstance(var, str):
- return var
- elif isinstance(var, unicode):
- return self.encoder_settings.encode_postprocessor(
- var.encode(self.encoder_settings.encode_to)
- )
- elif isinstance(var, bool):
- if var:
- var = 'TRUE'
- else:
- var = 'FALSE'
- return self.encoder_settings.encode_postprocessor(
- var.encode(self.encoder_settings.encode_to)
- )
- elif isinstance(var, (float, Decimal, int, long)):
- return self.encoder_settings.encode_postprocessor(
- str(var).encode(self.encoder_settings.encode_to)
- )
- elif isinstance(var, list):
- return [self.encode(m) for m in var]
- elif isinstance(var, tuple):
- return tuple(self.encode(m) for m in var)
- elif isinstance(var, dict):
- if self.encoder_settings.encode_dict_keys:
- dct = dict()
- if not self.encoder_settings.encode_dict_keys_postprocess:
- tmp = self.encoder_settings.encode_postprocessor
- self.encoder_settings.encode_postprocessor = lambda x: x
- for (k, v) in var.iteritems():
- dct[self.encode(k)] = v
- if not self.encoder_settings.encode_dict_keys_postprocess:
- self.encoder_settings.encode_postprocessor = tmp
- else:
- dct = dict(var)
- if self.encoder_settings.encode_dict_vals:
- if not self.encoder_settings.encode_dict_vals_postprocess:
- tmp = self.encoder_settings.encode_postprocessor
- self.encoder_settings.encode_postprocessor = lambda x: x
- for (k, v) in dct.iteritems():
- dct[k] = self.encode(v)
- if not self.encoder_settings.encode_dict_vals_postprocess:
- self.encoder_settings.encode_postprocessor = tmp
- return dct
- elif var is None:
- if self.encoder_settings.encode_none:
- return self.encoder_settings.encode_postprocessor(
- str(var).encode(self.encoder_settings.encode_to)
- )
- return None
- raise TypeError('python built-in type expected, got \'%s\'', type(var))
-
- def decode(self, var):
- """
- Decode strings in `self.decode_from` into python strings.
-
- Compound types have their individual members decoded.
-
- Dictionaries can have their values decoded into other types
- by looking up keys in `self.decode_dict_vals_table`.
-
- Returns a decoded copy of 'var'.
- """
- if isinstance(var, unicode):
- return var
- elif isinstance(var, str):
- return self.encoder_settings.decode_postprocessor(
- var.decode(self.encoder_settings.decode_from)
- )
- elif isinstance(var, (bool, float, Decimal, int, long)):
- return var
- elif isinstance(var, list):
- return [self.decode(m) for m in var]
- elif isinstance(var, tuple):
- return tuple(self.decode(m) for m in var)
- elif isinstance(var, dict):
- if self.encoder_settings.decode_dict_keys:
- dct = dict()
- if not self.encoder_settings.decode_dict_keys_postprocess:
- tmp = self.encoder_settings.decode_postprocessor
- self.encoder_settings.decode_postprocessor = lambda x: x
- for (k, v) in var.iteritems():
- dct[self.decode(k)] = v
- if not self.encoder_settings.decode_dict_keys_postprocess:
- self.encoder_settings.decode_postprocessor = tmp
- else:
- dct = dict(var)
- if self.encoder_settings.decode_dict_vals:
- if not self.encoder_settings.decode_dict_vals_postprocess:
- tmp = self.encoder_settings.decode_postprocessor
- self.encoder_settings.decode_postprocessor = lambda x: x
- for (k, v) in dct.iteritems():
- dct[k] = self._decode_dict_val(k, v)
- if not self.encoder_settings.decode_dict_vals_postprocess:
- self.encoder_settings.decode_postprocessor = tmp
- return dct
- elif var is None:
- if self.encoder_settings.decode_none:
- return self.encoder_settings.decode_postprocessor(
- str(var).decode(self.encoder_settings.decode_from)
- )
- return None
- raise TypeError('python built-in type expected, got \'%s\'', type(var))
-
-## ENCODER METHOD DECORATORS
-
-def encode_args(*outer_args):
- def decorate(f):
- def new_f(*args, **kwargs):
- assert isinstance(args[0], Encoder), \
- 'first argument not Encoder instance'
- new_args = list(args)
- for a in outer_args:
- if isinstance(a, int):
- if a < len(args):
- new_args[a] = args[0].encode(args[a])
- elif isinstance(a, basestring):
- if a in kwargs:
- kwargs[a] = args[0].encode(kwargs[a])
- else:
- raise TypeError(
- 'encode_args takes a list of ints and basestrings'
- )
- return f(*new_args, **kwargs)
- new_f.func_name = f.func_name
- return new_f
- return decorate
-
-
-def decode_retval():
- def decorate(f):
- def new_f(*args, **kwargs):
- assert isinstance(args[0], Encoder), \
- 'first argument not Encoder instance'
- return args[0].decode(f(*args, **kwargs))
- new_f.func_name = f.func_name
- return new_f
- return decorate
-
diff --git a/ipalib/parameters.py b/ipalib/parameters.py
index 98b02dd6d..dd505a179 100644
--- a/ipalib/parameters.py
+++ b/ipalib/parameters.py
@@ -112,7 +112,7 @@ from errors import ConversionError, RequirementError, ValidationError
from errors import PasswordMismatch
from constants import NULLS, TYPE_ERROR, CALLABLE_ERROR
from text import Gettext, FixMe
-
+from ipapython.dn import DN
class DefaultFrom(ReadOnly):
"""
@@ -1845,6 +1845,23 @@ class AccessTime(Str):
return None
+class DNParam(Param):
+ type = DN
+
+ def _convert_scalar(self, value, index=None):
+ """
+ Convert a single scalar value.
+ """
+ if type(value) is self.type:
+ return value
+
+ try:
+ dn = DN(value)
+ except Exception, e:
+ raise ConversionError(name=self.get_param_name(), index=index,
+ error=ugettext(e))
+ return dn
+
def create_param(spec):
"""
Create an `Str` instance from the shorthand ``spec``.
diff --git a/ipalib/plugins/aci.py b/ipalib/plugins/aci.py
index 7a27ce116..7d5bf504c 100644
--- a/ipalib/plugins/aci.py
+++ b/ipalib/plugins/aci.py
@@ -123,24 +123,22 @@ from ipalib import api, crud, errors
from ipalib import Object, Command
from ipalib import Flag, Int, Str, StrEnum
from ipalib.aci import ACI
-from ipalib.dn import DN
from ipalib import output
from ipalib import _, ngettext
from ipalib.plugins.baseldap import gen_pkey_only_option
-if api.env.in_server and api.env.context in ['lite', 'server']:
- from ldap import explode_dn
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
ACI_NAME_PREFIX_SEP = ":"
_type_map = {
- 'user': 'ldap:///uid=*,%s,%s' % (api.env.container_user, api.env.basedn),
- 'group': 'ldap:///cn=*,%s,%s' % (api.env.container_group, api.env.basedn),
- 'host': 'ldap:///fqdn=*,%s,%s' % (api.env.container_host, api.env.basedn),
- 'hostgroup': 'ldap:///cn=*,%s,%s' % (api.env.container_hostgroup, api.env.basedn),
- 'service': 'ldap:///krbprincipalname=*,%s,%s' % (api.env.container_service, api.env.basedn),
- 'netgroup': 'ldap:///ipauniqueid=*,%s,%s' % (api.env.container_netgroup, api.env.basedn),
- 'dnsrecord': 'ldap:///idnsname=*,%s,%s' % (api.env.container_dns, api.env.basedn),
+ 'user': 'ldap:///' + str(DN(('uid', '*'), api.env.container_user, api.env.basedn)),
+ 'group': 'ldap:///' + str(DN(('cn', '*'), api.env.container_group, api.env.basedn)),
+ 'host': 'ldap:///' + str(DN(('fqdn', '*'), api.env.container_host, api.env.basedn)),
+ 'hostgroup': 'ldap:///' + str(DN(('cn', '*'), api.env.container_hostgroup, api.env.basedn)),
+ 'service': 'ldap:///' + str(DN(('krbprincipalname', '*'), api.env.container_service, api.env.basedn)),
+ 'netgroup': 'ldap:///' + str(DN(('ipauniqueid', '*'), api.env.container_netgroup, api.env.basedn)),
+ 'dnsrecord': 'ldap:///' + str(DN(('idnsname', '*'), api.env.container_dns, api.env.basedn)),
}
_valid_permissions_values = [
@@ -247,7 +245,7 @@ def _make_aci(ldap, current, aciname, kw):
if 'test' in kw and not kw.get('test'):
raise e
else:
- entry_attrs = {'dn': 'cn=%s,%s' % (kw['permission'], api.env.container_permission)}
+ entry_attrs = {'dn': DN(('cn', kw['permission']), api.env.container_permission)}
elif group:
# Not so friendly with groups. This will raise
try:
@@ -343,10 +341,9 @@ def _aci_to_kw(ldap, a, test=False, pkey_only=False):
else:
# See if the target is a group. If so we set the
# targetgroup attr, otherwise we consider it a subtree
- if api.env.container_group in target:
- targetdn = unicode(target.replace('ldap:///',''))
- target = DN(targetdn)
- kw['targetgroup'] = target['cn']
+ targetdn = DN(target.replace('ldap:///',''))
+ if targetdn.endswith(DN(api.env.container_group, api.env.basedn)):
+ kw['targetgroup'] = targetdn[0]['cn']
else:
kw['subtree'] = unicode(target)
@@ -357,15 +354,16 @@ def _aci_to_kw(ldap, a, test=False, pkey_only=False):
elif groupdn == 'anyone':
pass
else:
- if groupdn.startswith('cn='):
- dn = ''
+ groupdn = DN(groupdn)
+ if len(groupdn) and groupdn[0].attr == 'cn':
+ dn = DN()
entry_attrs = {}
try:
(dn, entry_attrs) = ldap.get_entry(groupdn, ['cn'])
except errors.NotFound, e:
# FIXME, use real name here
if test:
- dn = 'cn=%s,%s' % ('test', api.env.container_permission)
+ dn = DN(('cn', 'test'), api.env.container_permission)
entry_attrs = {'cn': [u'test']}
if api.env.container_permission in dn:
kw['permission'] = entry_attrs['cn'][0]
@@ -801,11 +799,11 @@ class aci_find(crud.Search):
if kw.get('group'):
for a in acis:
groupdn = a.bindrule['expression']
- groupdn = groupdn.replace('ldap:///','')
- cn = None
- if groupdn.startswith('cn='):
- cn = explode_dn(groupdn)[0]
- cn = cn.replace('cn=','')
+ groupdn = DN(groupdn.replace('ldap:///',''))
+ try:
+ cn = groupdn[0]['cn'].value
+ except (IndexError, KeyError):
+ cn = None
if cn is None or cn != kw['group']:
try:
results.remove(a)
@@ -818,9 +816,11 @@ class aci_find(crud.Search):
if 'target' in a.target:
target = a.target['target']['expression']
if api.env.container_group in target:
- targetdn = unicode(target.replace('ldap:///',''))
- cn = explode_dn(targetdn)[0]
- cn = cn.replace('cn=','')
+ targetdn = DN(target.replace('ldap:///',''))
+ try:
+ cn = targetdn[0]['cn']
+ except (IndexError, KeyError):
+ cn = None
if cn == kw['targetgroup']:
found = True
if not found:
diff --git a/ipalib/plugins/automember.py b/ipalib/plugins/automember.py
index 7ccb0bb2f..40359604b 100644
--- a/ipalib/plugins/automember.py
+++ b/ipalib/plugins/automember.py
@@ -22,8 +22,8 @@ from ipalib import Str, StrEnum
from ipalib.plugins.baseldap import *
from ipalib import _, ngettext
from ipalib.request import context
-from ipalib.dn import *
import ldap as _ldap
+from ipapython.dn import DN
__doc__ = _("""
Auto Membership Rule.
@@ -200,19 +200,16 @@ class automember(LDAPObject):
parent_dn = self.container_dn
grouptype = options['type']
try:
- ndn = DN(('cn', keys[-1]), ('cn', grouptype), DN(parent_dn))
+ ndn = DN(('cn', keys[-1]), ('cn', grouptype), parent_dn)
except IndexError:
- ndn = DN(('cn', grouptype), DN(parent_dn))
- parent_dn = str(ndn)
- return parent_dn
+ ndn = DN(('cn', grouptype), parent_dn)
+ return ndn
def check_attr(self, attr):
"""
Verify that the user supplied key is a valid attribute in the schema
"""
ldap = self.api.Backend.ldap2
- if not ldap.schema:
- ldap.get_schema()
obj = ldap.schema.get_obj(_ldap.schema.AttributeType, attr)
if obj is not None:
return obj
@@ -238,6 +235,7 @@ class automember_add(LDAPCreate):
msg_summary = _('Added automember rule "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
entry_attrs['cn'] = keys[-1]
if not automember_container_exists(self.api.Backend.ldap2):
@@ -284,6 +282,7 @@ class automember_add_condition(LDAPUpdate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# Check to see if the automember rule exists
try:
(tdn, test_attrs) = ldap.get_entry(dn, [])
@@ -370,6 +369,7 @@ class automember_remove_condition(LDAPUpdate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# Check to see if the automember rule exists
try:
(tdn, test_attrs) = ldap.get_entry(dn, [])
@@ -479,10 +479,10 @@ class automember_find(LDAPSearch):
)
def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
scope = ldap.SCOPE_SUBTREE
- ndn = DN(('cn', options['type']), DN(base_dn))
- base_dn = str(ndn)
- return (filters, base_dn, scope)
+ ndn = DN(('cn', options['type']), base_dn)
+ return (filters, ndn, scope)
api.register(automember_find)
@@ -520,7 +520,6 @@ class automember_default_group_set(LDAPUpdate):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
dn = DN(('cn', options['type']), api.env.container_automember)
- dn = str(dn)
entry_attrs['automemberdefaultgroup'] = self.obj.dn_exists(options['type'], options['automemberdefaultgroup'])
return dn
@@ -542,7 +541,6 @@ class automember_default_group_remove(LDAPUpdate):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
dn = DN(('cn', options['type']), api.env.container_automember)
- dn = str(dn)
attr = 'automemberdefaultgroup'
(dn, entry_attrs_) = ldap.get_entry(
@@ -556,6 +554,7 @@ class automember_default_group_remove(LDAPUpdate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if 'automemberdefaultgroup' not in entry_attrs:
entry_attrs['automemberdefaultgroup'] = unicode(_('No default (fallback) group set'))
return dn
@@ -576,10 +575,10 @@ class automember_default_group_show(LDAPRetrieve):
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
dn = DN(('cn', options['type']), api.env.container_automember)
- dn = str(dn)
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if 'automemberdefaultgroup' not in entry_attrs:
entry_attrs['automemberdefaultgroup'] = unicode(_('No default (fallback) group set'))
return dn
diff --git a/ipalib/plugins/automount.py b/ipalib/plugins/automount.py
index 5c9f42b4c..8e9eb5745 100644
--- a/ipalib/plugins/automount.py
+++ b/ipalib/plugins/automount.py
@@ -227,6 +227,7 @@ class automountlocation_add(LDAPCreate):
msg_summary = _('Added automount location "%(value)s"')
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
# create auto.master for the new location
self.api.Command['automountmap_add'](keys[-1], u'auto.master')
@@ -595,6 +596,7 @@ class automountmap_del(LDAPDelete):
msg_summary = _('Deleted automount map "%(value)s"')
def post_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
# delete optional parental connection (direct maps may not have this)
try:
(dn_, entry_attrs) = ldap.find_entry_by_attr(
@@ -718,7 +720,7 @@ class automountkey(LDAPObject):
(kwargs['automountkey'], kwargs['automountinformation'])
else:
sfilter = '(automountkey=%s)' % kwargs['automountkey']
- basedn = 'automountmapname=%s,cn=%s,%s' % (parent_keys[1], parent_keys[0], self.container_dn)
+ basedn = DN(('automountmapname', parent_keys[1]), ('cn', parent_keys[0]), self.container_dn)
attrs_list = ['*']
(entries, truncated) = ldap.find_entries(sfilter, attrs_list,
basedn, _ldap.SCOPE_ONELEVEL)
@@ -790,6 +792,7 @@ class automountkey_add(LDAPCreate):
internal_options = ['description', 'add_operation']
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
options.pop('add_operation', None)
options.pop('description', None)
self.obj.check_key_uniqueness(keys[-2], keys[-1], **options)
@@ -926,6 +929,7 @@ class automountkey_mod(LDAPUpdate):
yield key
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if 'newautomountkey' in options:
entry_attrs['automountkey'] = options['newautomountkey']
if 'newautomountinformation' in options:
diff --git a/ipalib/plugins/baseldap.py b/ipalib/plugins/baseldap.py
index 32dae5160..e05f59ff4 100644
--- a/ipalib/plugins/baseldap.py
+++ b/ipalib/plugins/baseldap.py
@@ -34,7 +34,7 @@ from ipalib.cli import to_cli, from_cli
from ipalib import output
from ipalib.text import _
from ipalib.util import json_serialize, validate_hostname
-from ipalib.dn import *
+from ipapython.dn import DN, RDN
global_output_params = (
Flag('has_password',
@@ -200,6 +200,7 @@ def validate_attribute(ugettext, name, attr):
raise errors.ValidationError(name=name, error='Invalid format. Should be name=value')
def get_effective_rights(ldap, dn, attrs=None):
+ assert isinstance(dn, DN)
if attrs is None:
attrs = ['*', 'nsaccountlock', 'cospriority']
rights = ldap.get_effective_rights(dn, attrs)
@@ -332,6 +333,7 @@ def add_external_pre_callback(membertype, ldap, dn, keys, options):
membertype is the type of member
"""
+ assert isinstance(dn, DN)
# validate hostname with allowed underscore characters, non-fqdn
# hostnames are allowed
def validate_host(hostname):
@@ -361,12 +363,14 @@ def add_external_post_callback(memberattr, membertype, externalattr, ldap, compl
membertype is the type of member: user,
externalattr is one of externaluser,
"""
+ assert isinstance(dn, DN)
completed_external = 0
normalize = options.get('external_callback_normalize', True)
# Sift through the failures. We assume that these are all
# entries that aren't stored in IPA, aka external entries.
if memberattr in failed and membertype in failed[memberattr]:
(dn, entry_attrs_) = ldap.get_entry(dn, [externalattr])
+ assert isinstance(dn, DN)
members = entry_attrs.get(memberattr, [])
external_entries = entry_attrs_.get(externalattr, [])
lc_external_entries = set(e.lower() for e in external_entries)
@@ -374,6 +378,7 @@ def add_external_post_callback(memberattr, membertype, externalattr, ldap, compl
for entry in failed[memberattr][membertype]:
membername = entry[0].lower()
member_dn = api.Object[membertype].get_dn(membername)
+ assert isinstance(member_dn, DN)
if (membername not in lc_external_entries and
member_dn not in members):
# Not an IPA entry, assume external
@@ -406,6 +411,7 @@ def add_external_post_callback(memberattr, membertype, externalattr, ldap, compl
return (completed + completed_external, dn)
def remove_external_post_callback(memberattr, membertype, externalattr, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
# Run through the failures and gracefully remove any member defined
# as an external member.
if memberattr in failed and membertype in failed[memberattr]:
@@ -440,7 +446,7 @@ def host_is_master(ldap, fqdn):
Raises an exception if a master, otherwise returns nothing.
"""
- master_dn = str(DN('cn=%s' % fqdn, 'cn=masters,cn=ipa,cn=etc', api.env.basedn))
+ master_dn = DN(('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
try:
(dn, entry_attrs) = ldap.get_entry(master_dn, ['objectclass'])
raise errors.ValidationError(name='hostname', error=_('An IPA master host cannot be deleted or disabled'))
@@ -518,9 +524,11 @@ class LDAPObject(Object):
return self.backend.make_dn_from_attr(
self.primary_key.name, keys[-1], parent_dn
)
+ assert isinstance(parent_dn, DN)
return parent_dn
def get_primary_key_from_dn(self, dn):
+ assert isinstance(dn, DN)
try:
if self.rdn_attribute:
(dn, entry_attrs) = self.backend.get_entry(
@@ -532,8 +540,6 @@ class LDAPObject(Object):
return ''
except errors.NotFound:
pass
- # DN object assures we're returning a decoded (unescaped) value
- dn = DN(dn)
try:
return dn[self.primary_key.name]
except KeyError:
@@ -567,7 +573,7 @@ class LDAPObject(Object):
for member in entry_attrs.setdefault(attr, []):
for ldap_obj_name in self.attribute_members[attr]:
ldap_obj = self.api.Object[ldap_obj_name]
- if member.find(ldap_obj.container_dn) > 0:
+ if ldap_obj.container_dn in member:
new_attr = '%s_%s' % (attr, ldap_obj.name)
entry_attrs.setdefault(new_attr, []).append(
ldap_obj.get_primary_key_from_dn(member)
@@ -623,7 +629,6 @@ class LDAPObject(Object):
def __json__(self):
ldap = self.backend
- ldap.get_schema()
json_dict = dict(
(a, getattr(self, a)) for a in self.json_friendly_attributes
)
@@ -777,52 +782,47 @@ last, after all sets and adds."""),
_callback_registry = dict(pre={}, post={}, exc={}, interactive_prompt={})
- def _convert_2_dict(self, attrs):
+ def _convert_2_dict(self, ldap, attrs):
"""
Convert a string in the form of name/value pairs into a dictionary.
:param attrs: A list of name/value pair strings, in the "name=value"
format. May also be a single string, or None.
"""
- if attrs is None:
- return {}
-
- if not isinstance(attrs, (tuple, list)):
- attrs = [attrs]
newdict = {}
+ if attrs is None:
+ attrs = []
+ elif not type(attrs) in (list, tuple):
+ attrs = [attrs]
for a in attrs:
- m = re.match("^\s*(?P<attr>.*?)\s*=\s*(?P<value>.*?)\s*$", a)
- attr = str(m.group('attr').lower())
- value = m.group('value')
-
+ m = re.match("\s*(.*?)\s*=\s*(.*?)\s*$", a)
+ attr = str(m.group(1)).lower()
+ value = m.group(2)
if attr in self.obj.params and attr not in self.params:
# The attribute is managed by IPA, but it didn't get cloned
# to the command. This happens with no_update/no_create attrs.
raise errors.ValidationError(
name=attr, error=_('attribute is not configurable'))
+ if len(value) == 0:
+ # None means "delete this attribute"
+ value = None
- newdict.setdefault(attr, []).append(value)
+ if ldap.has_dn_syntax(attr):
+ value = DN(value)
+ if attr in newdict:
+ if type(value) in (tuple,):
+ newdict[attr] += list(value)
+ else:
+ newdict[attr].append(value)
+ else:
+ if type(value) in (tuple,):
+ newdict[attr] = list(value)
+ else:
+ newdict[attr] = [value]
return newdict
- def _convert_entry(self, entry_attrs):
- result = {}
- for attr, val in entry_attrs.iteritems():
- if val is None:
- val = []
- elif not isinstance(val, (tuple, list)):
- val = [val]
-
- result[attr] = []
- for v in val:
- if isinstance(v, str):
- # This is a Binary value, base64 encode it
- v = base64.b64encode(v)
- result[attr].append(unicode(v))
-
- return result
-
def process_attr_options(self, entry_attrs, dn, keys, options):
"""
Process all --setattr, --addattr, and --delattr options and add the
@@ -847,14 +847,15 @@ last, after all sets and adds."""),
:param keys: List of command arguments
:param options: List of options
"""
+
if all(k not in options for k in ("setattr", "addattr", "delattr")):
return
ldap = self.obj.backend
- adddict = self._convert_2_dict(options.get('addattr', []))
- setdict = self._convert_2_dict(options.get('setattr', []))
- deldict = self._convert_2_dict(options.get('delattr', []))
+ adddict = self._convert_2_dict(ldap, options.get('addattr', []))
+ setdict = self._convert_2_dict(ldap, options.get('setattr', []))
+ deldict = self._convert_2_dict(ldap, options.get('delattr', []))
setattrs = set(setdict.keys())
addattrs = set(adddict.keys())
@@ -865,24 +866,24 @@ last, after all sets and adds."""),
direct_del = delattrs
needldapattrs = []
else:
+ assert isinstance(dn, DN)
direct_add = setattrs & addattrs
direct_del = setattrs & delattrs
needldapattrs = list((addattrs | delattrs) - setattrs)
- mod_attrs = self._convert_entry(entry_attrs)
-
for attr, val in setdict.iteritems():
- mod_attrs[attr] = val
+ entry_attrs[attr] = val
for attr in direct_add:
- mod_attrs.setdefault(attr, []).extend(adddict[attr])
+ entry_attrs.setdefault(attr, []).extend(adddict[attr])
for attr in direct_del:
for delval in deldict[attr]:
try:
- mod_attrs[attr].remove(delval)
+ entry_attrs[attr].remove(delval)
except ValueError:
- raise errors.AttrValueNotFound(attr=attr, value=delval)
+ raise errors.AttrValueNotFound(attr=attr,
+ value=delval)
if needldapattrs:
try:
@@ -901,27 +902,28 @@ last, after all sets and adds."""),
raise errors.ValidationError(name=del_nonexisting.pop(),
error=_('No such attribute on this entry'))
- old_entry = self._convert_entry(old_entry)
-
for attr in needldapattrs:
- mod_attrs[attr] = old_entry.get(attr, [])
+ entry_attrs[attr] = old_entry.get(attr, [])
if attr in addattrs:
- mod_attrs[attr].extend(adddict.get(attr, []))
+ entry_attrs[attr].extend(adddict.get(attr, []))
for delval in deldict.get(attr, []):
try:
- mod_attrs[attr].remove(delval)
+ entry_attrs[attr].remove(delval)
except ValueError:
+ if isinstance(delval, str):
+ # This is a Binary value, base64 encode it
+ delval = unicode(base64.b64encode(delval))
raise errors.AttrValueNotFound(attr=attr, value=delval)
# normalize all values
changedattrs = setattrs | addattrs | delattrs
for attr in changedattrs:
- value = mod_attrs[attr]
if attr in self.params and self.params[attr].attribute:
- param = self.params[attr]
# convert single-value params to scalars
+ param = self.params[attr]
+ value = entry_attrs[attr]
if not param.multivalue:
if len(value) == 1:
value = value[0]
@@ -931,19 +933,19 @@ last, after all sets and adds."""),
raise errors.OnlyOneValueAllowed(attr=attr)
# validate, convert and encode params
try:
- value = param(value)
+ value = param(value)
except errors.ValidationError, err:
raise errors.ValidationError(name=attr, error=err.error)
except errors.ConversionError, err:
raise errors.ConversionError(name=attr, error=err.error)
+ entry_attrs[attr] = value
else:
# unknown attribute: remove duplicite and invalid values
- value = list(set([val for val in value if val]))
- if not value:
- value = None
- elif isinstance(value, (tuple, list)) and len(value) == 1:
- value = value[0]
- entry_attrs[attr] = value
+ entry_attrs[attr] = list(set([val for val in entry_attrs[attr] if val]))
+ if not entry_attrs[attr]:
+ entry_attrs[attr] = None
+ elif isinstance(entry_attrs[attr], (tuple, list)) and len(entry_attrs[attr]) == 1:
+ entry_attrs[attr] = entry_attrs[attr][0]
@classmethod
def register_pre_callback(cls, callback, first=False):
@@ -1021,8 +1023,13 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
entry_attrs[self.obj.uuid_attribute] = 'autogenerate'
dn = self.obj.get_dn(*keys, **options)
+ assert isinstance(dn, DN)
if self.obj.rdn_attribute:
- if not dn.startswith('%s=' % self.obj.primary_key.name):
+ try:
+ dn_attr = dn[0].attr
+ except (IndexError, KeyError):
+ dn_attr = None
+ if dn_attr != self.obj.primary_key.name:
self.obj.handle_duplicate_entry(*keys)
dn = ldap.make_dn(
entry_attrs, self.obj.rdn_attribute, self.obj.container_dn
@@ -1038,9 +1045,9 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
for callback in self.get_callbacks('pre'):
dn = callback(
self, ldap, dn, entry_attrs, attrs_list, *keys, **options)
+ assert isinstance(dn, DN)
_check_single_value_attrs(self.params, entry_attrs)
- ldap.get_schema()
_check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.limit_object_classes), entry_attrs.keys(), allow_only=True)
_check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), entry_attrs.keys(), allow_only=False)
@@ -1074,16 +1081,19 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
self.obj.primary_key.name, keys[-1], object_class, attrs_list,
self.obj.container_dn
)
+ assert isinstance(dn, DN)
else:
(dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)(
dn, attrs_list, normalize=self.obj.normalize_dn
)
+ assert isinstance(dn, DN)
except errors.NotFound:
self.obj.handle_not_found(*keys)
for callback in self.get_callbacks('post'):
dn = callback(self, ldap, dn, entry_attrs, *keys, **options)
+ assert isinstance(dn, DN)
entry_attrs['dn'] = dn
self.obj.convert_attribute_members(entry_attrs, *keys, **options)
@@ -1092,9 +1102,11 @@ class LDAPCreate(BaseLDAPCommand, crud.Create):
return dict(result=entry_attrs, value=u'')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -1181,6 +1193,7 @@ class LDAPRetrieve(LDAPQuery):
ldap = self.obj.backend
dn = self.obj.get_dn(*keys, **options)
+ assert isinstance(dn, DN)
if options.get('all', False):
attrs_list = ['*'] + self.obj.default_attributes
@@ -1189,11 +1202,13 @@ class LDAPRetrieve(LDAPQuery):
for callback in self.get_callbacks('pre'):
dn = callback(self, ldap, dn, attrs_list, *keys, **options)
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = self._exc_wrapper(keys, options, ldap.get_entry)(
dn, attrs_list, normalize=self.obj.normalize_dn
)
+ assert isinstance(dn, DN)
except errors.NotFound:
self.obj.handle_not_found(*keys)
@@ -1202,17 +1217,21 @@ class LDAPRetrieve(LDAPQuery):
for callback in self.get_callbacks('post'):
dn = callback(self, ldap, dn, entry_attrs, *keys, **options)
+ assert isinstance(dn, DN)
self.obj.convert_attribute_members(entry_attrs, *keys, **options)
+ assert isinstance(dn, DN)
entry_attrs['dn'] = dn
if self.obj.primary_key and keys[-1] is not None:
return dict(result=entry_attrs, value=keys[-1])
return dict(result=entry_attrs, value=u'')
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -1261,6 +1280,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
raise errors.EmptyModlist()
dn = self.obj.get_dn(*keys, **options)
+ assert isinstance(dn, DN)
entry_attrs = self.args_options_2_entry(**options)
@@ -1279,8 +1299,8 @@ class LDAPUpdate(LDAPQuery, crud.Update):
for callback in self.get_callbacks('pre'):
dn = callback(
self, ldap, dn, entry_attrs, attrs_list, *keys, **options)
+ assert isinstance(dn, DN)
- ldap.get_schema()
_check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.limit_object_classes), entry_attrs.keys(), allow_only=True)
_check_limit_object_class(self.api.Backend.ldap2.schema.attribute_types(self.obj.disallow_object_classes), entry_attrs.keys(), allow_only=False)
@@ -1294,10 +1314,10 @@ class LDAPUpdate(LDAPQuery, crud.Update):
if self.obj.rdn_is_primary_key and self.obj.primary_key.name in entry_attrs:
# RDN change
self._exc_wrapper(keys, options, ldap.update_entry_rdn)(dn,
- unicode('%s=%s' % (self.obj.primary_key.name,
- entry_attrs[self.obj.primary_key.name])))
+ RDN((self.obj.primary_key.name, entry_attrs[self.obj.primary_key.name])))
rdnkeys = keys[:-1] + (entry_attrs[self.obj.primary_key.name], )
dn = self.obj.get_dn(*rdnkeys)
+ assert isinstance(dn, DN)
del entry_attrs[self.obj.primary_key.name]
options['rdnupdate'] = True
rdnupdate = True
@@ -1306,6 +1326,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
# to decide what to do. An EmptyModlist in this context doesn't
# mean an error occurred, just that there were no other updates to
# perform.
+ assert isinstance(dn, DN)
self._exc_wrapper(keys, options, ldap.update_entry)(dn, entry_attrs, normalize=self.obj.normalize_dn)
except errors.EmptyModlist, e:
if not rdnupdate:
@@ -1327,6 +1348,7 @@ class LDAPUpdate(LDAPQuery, crud.Update):
for callback in self.get_callbacks('post'):
dn = callback(self, ldap, dn, entry_attrs, *keys, **options)
+ assert isinstance(dn, DN)
self.obj.convert_attribute_members(entry_attrs, *keys, **options)
if self.obj.primary_key and keys[-1] is not None:
@@ -1334,9 +1356,11 @@ class LDAPUpdate(LDAPQuery, crud.Update):
return dict(result=entry_attrs, value=u'')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -1360,11 +1384,14 @@ class LDAPDelete(LDAPMultiQuery):
def delete_entry(pkey):
nkeys = keys[:-1] + (pkey, )
dn = self.obj.get_dn(*nkeys, **options)
+ assert isinstance(dn, DN)
for callback in self.get_callbacks('pre'):
dn = callback(self, ldap, dn, *nkeys, **options)
+ assert isinstance(dn, DN)
def delete_subtree(base_dn):
+ assert isinstance(base_dn, DN)
truncated = True
while truncated:
try:
@@ -1412,9 +1439,11 @@ class LDAPDelete(LDAPMultiQuery):
return dict(result=dict(failed=u''), value=u'')
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
return True
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -1495,14 +1524,17 @@ class LDAPAddMember(LDAPModMember):
(member_dns, failed) = self.get_member_dns(**options)
dn = self.obj.get_dn(*keys, **options)
+ assert isinstance(dn, DN)
for callback in self.get_callbacks('pre'):
dn = callback(self, ldap, dn, member_dns, failed, *keys, **options)
+ assert isinstance(dn, DN)
completed = 0
for (attr, objs) in member_dns.iteritems():
for ldap_obj_name in objs:
for m_dn in member_dns[attr][ldap_obj_name]:
+ assert isinstance(m_dn, DN)
if not m_dn:
continue
try:
@@ -1534,7 +1566,9 @@ class LDAPAddMember(LDAPModMember):
(completed, dn) = callback(
self, ldap, completed, failed, dn, entry_attrs, *keys,
**options)
+ assert isinstance(dn, DN)
+ assert isinstance(dn, DN)
entry_attrs['dn'] = dn
self.obj.convert_attribute_members(entry_attrs, *keys, **options)
return dict(
@@ -1544,9 +1578,11 @@ class LDAPAddMember(LDAPModMember):
)
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return (completed, dn)
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -1583,14 +1619,17 @@ class LDAPRemoveMember(LDAPModMember):
(member_dns, failed) = self.get_member_dns(**options)
dn = self.obj.get_dn(*keys, **options)
+ assert isinstance(dn, DN)
for callback in self.get_callbacks('pre'):
dn = callback(self, ldap, dn, member_dns, failed, *keys, **options)
+ assert isinstance(dn, DN)
completed = 0
for (attr, objs) in member_dns.iteritems():
for ldap_obj_name, m_dns in objs.iteritems():
for m_dn in m_dns:
+ assert isinstance(m_dn, DN)
if not m_dn:
continue
try:
@@ -1625,7 +1664,9 @@ class LDAPRemoveMember(LDAPModMember):
(completed, dn) = callback(
self, ldap, completed, failed, dn, entry_attrs, *keys,
**options)
+ assert isinstance(dn, DN)
+ assert isinstance(dn, DN)
entry_attrs['dn'] = dn
self.obj.convert_attribute_members(entry_attrs, *keys, **options)
@@ -1636,9 +1677,11 @@ class LDAPRemoveMember(LDAPModMember):
)
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return (completed, dn)
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -1765,6 +1808,7 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
base_dn = self.api.Object[self.obj.parent_object].get_dn(*args[:-1])
else:
base_dn = self.obj.container_dn
+ assert isinstance(base_dn, DN)
search_kw = self.args_options_2_entry(**options)
@@ -1812,6 +1856,7 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
for callback in self.get_callbacks('pre'):
(filter, base_dn, scope) = callback(
self, ldap, filter, attrs_list, base_dn, scope, *args, **options)
+ assert isinstance(base_dn, DN)
try:
(entries, truncated) = self._exc_wrapper(args, options, ldap.find_entries)(
@@ -1827,14 +1872,16 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
if self.sort_result_entries:
if self.obj.primary_key:
- sortfn=lambda x,y: cmp(x[1][self.obj.primary_key.name][0].lower(), y[1][self.obj.primary_key.name][0].lower())
- entries.sort(sortfn)
+ def sort_key(x):
+ return x[1][self.obj.primary_key.name][0].lower()
+ entries.sort(key=sort_key)
if not options.get('raw', False):
for e in entries:
self.obj.convert_attribute_members(e[1], *args, **options)
for e in entries:
+ assert isinstance(e[0], DN)
e[1]['dn'] = e[0]
entries = [e for (dn, e) in entries]
@@ -1845,6 +1892,7 @@ class LDAPSearch(BaseLDAPCommand, crud.Search):
)
def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
return (filters, base_dn, scope)
def post_callback(self, ldap, entries, truncated, *args, **options):
@@ -1926,9 +1974,11 @@ class LDAPAddReverseMember(LDAPModReverseMember):
# Ensure our target exists
result = self.api.Command[self.show_command](keys[-1])['result']
dn = result['dn']
+ assert isinstance(dn, DN)
for callback in self.get_callbacks('pre'):
dn = callback(self, ldap, dn, *keys, **options)
+ assert isinstance(dn, DN)
if options.get('all', False):
attrs_list = ['*'] + self.obj.default_attributes
@@ -1967,7 +2017,9 @@ class LDAPAddReverseMember(LDAPModReverseMember):
(completed, dn) = callback(
self, ldap, completed, failed, dn, entry_attrs, *keys,
**options)
+ assert isinstance(dn, DN)
+ assert isinstance(dn, DN)
entry_attrs['dn'] = dn
return dict(
completed=completed,
@@ -1976,9 +2028,11 @@ class LDAPAddReverseMember(LDAPModReverseMember):
)
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return (completed, dn)
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
@@ -2022,9 +2076,11 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
# Ensure our target exists
result = self.api.Command[self.show_command](keys[-1])['result']
dn = result['dn']
+ assert isinstance(dn, DN)
for callback in self.get_callbacks('pre'):
dn = callback(self, ldap, dn, *keys, **options)
+ assert isinstance(dn, DN)
if options.get('all', False):
attrs_list = ['*'] + self.obj.default_attributes
@@ -2063,7 +2119,9 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
(completed, dn) = callback(
self, ldap, completed, failed, dn, entry_attrs, *keys,
**options)
+ assert isinstance(dn, DN)
+ assert isinstance(dn, DN)
entry_attrs['dn'] = dn
return dict(
completed=completed,
@@ -2072,9 +2130,11 @@ class LDAPRemoveReverseMember(LDAPModReverseMember):
)
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return (completed, dn)
def exc_callback(self, keys, options, exc, call_func, *call_args, **call_kwargs):
diff --git a/ipalib/plugins/config.py b/ipalib/plugins/config.py
index 9573bbb65..ef0fd79fa 100644
--- a/ipalib/plugins/config.py
+++ b/ipalib/plugins/config.py
@@ -19,7 +19,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ipalib import api
-from ipalib import Bool, Int, Str, IA5Str, StrEnum
+from ipalib import Bool, Int, Str, IA5Str, StrEnum, DNParam
from ipalib.plugins.baseldap import *
from ipalib import _
from ipalib.errors import ValidationError
@@ -149,7 +149,7 @@ class config(LDAPObject):
label=_('Enable migration mode'),
doc=_('Enable migration mode'),
),
- Str('ipacertificatesubjectbase',
+ DNParam('ipacertificatesubjectbase',
cli_name='subject',
label=_('Certificate Subject base'),
doc=_('Base for certificate subjects (OU=Test,O=Example)'),
@@ -199,7 +199,7 @@ class config(LDAPObject):
)
def get_dn(self, *keys, **kwargs):
- return 'cn=ipaconfig,cn=etc'
+ return DN(('cn', 'ipaconfig'), ('cn', 'etc'))
api.register(config)
@@ -208,6 +208,7 @@ class config_mod(LDAPUpdate):
__doc__ = _('Modify configuration options.')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if 'ipadefaultprimarygroup' in entry_attrs:
group=entry_attrs['ipadefaultprimarygroup']
try:
diff --git a/ipalib/plugins/dns.py b/ipalib/plugins/dns.py
index 6727d052f..991eb0164 100644
--- a/ipalib/plugins/dns.py
+++ b/ipalib/plugins/dns.py
@@ -35,7 +35,6 @@ from ipalib.util import (validate_zonemgr, normalize_zonemgr,
validate_hostname, validate_dns_label, validate_domain_name,
get_dns_forward_zone_update_policy, get_dns_reverse_zone_update_policy)
from ipapython.ipautil import valid_ip, CheckedIPAddress, is_host_resolvable
-from ldap import explode_dn
__doc__ = _("""
Domain Name System (DNS)
@@ -802,10 +801,10 @@ class DNSRecord(Str):
# callbacks for per-type special record behavior
def dnsrecord_add_pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
- pass
+ assert isinstance(dn, DN)
def dnsrecord_add_post_callback(self, ldap, dn, entry_attrs, *keys, **options):
- pass
+ assert isinstance(dn, DN)
class ForwardRecord(DNSRecord):
extra = (
@@ -817,6 +816,7 @@ class ForwardRecord(DNSRecord):
)
def dnsrecord_add_pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
reverse_option = self._convert_dnsrecord_extra(self.extra[0])
if options.get(reverse_option.name):
records = entry_attrs.get(self.name, [])
@@ -832,6 +832,7 @@ class ForwardRecord(DNSRecord):
setattr(context, '%s_reverse' % self.name, entry_attrs.get(self.name))
def dnsrecord_add_post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
rev_records = getattr(context, '%s_reverse' % self.name, [])
if rev_records:
@@ -1727,6 +1728,7 @@ class dnszone_add(LDAPCreate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if not dns_container_exists(self.api.Backend.ldap2):
raise errors.NotFound(reason=_('DNS is not configured'))
@@ -1751,6 +1753,7 @@ class dnszone_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if 'ip_address' in options:
nameserver = entry_attrs['idnssoamname'][0][:-1] # ends with a dot
nsparts = nameserver.split('.')
@@ -1813,6 +1816,7 @@ class dnszone_find(LDAPSearch):
)
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
if options.get('forward_only', False):
search_kw = {}
search_kw['idnsname'] = _valid_reverse_zones.keys()
@@ -1980,6 +1984,7 @@ class dnsrecord(LDAPObject):
)
def _nsrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
nsrecords = entry_attrs.get('nsrecord')
if options.get('force', False) or nsrecords is None:
return
@@ -1987,6 +1992,7 @@ class dnsrecord(LDAPObject):
check_ns_rec_resolvable(keys[0], nsrecord)
def _ptrrecord_pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
ptrrecords = entry_attrs.get('ptrrecord')
if ptrrecords is None:
return
@@ -2015,6 +2021,7 @@ class dnsrecord(LDAPObject):
% dict(name=zone_name, count=zone_len, user_count=ip_addr_comp_count)))
def run_precallback_validators(self, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
ldap = self.api.Backend.ldap2
for rtype in entry_attrs:
@@ -2049,7 +2056,7 @@ class dnsrecord(LDAPObject):
def get_dns_masters(self):
ldap = self.api.Backend.ldap2
- base_dn = 'cn=masters,cn=ipa,cn=etc,%s' % self.api.env.basedn
+ base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.api.env.basedn)
ldap_filter = '(&(objectClass=ipaConfigObject)(cn=DNS))'
dns_masters = []
@@ -2058,9 +2065,12 @@ class dnsrecord(LDAPObject):
for entry in entries:
master_dn = entry[0]
- if master_dn.startswith('cn='):
- master = explode_dn(master_dn)[1].replace('cn=','')
+ assert isinstance(master_dn, DN)
+ try:
+ master = master_dn[1]['cn']
dns_masters.append(master)
+ except (IndexError, KeyError):
+ pass
except errors.NotFound:
return []
@@ -2254,6 +2264,7 @@ class dnsrecord_add(LDAPCreate):
kw.update(user_options)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
precallback_attrs = []
processed_attrs = []
for option in options:
@@ -2354,6 +2365,7 @@ class dnsrecord_add(LDAPCreate):
raise exc
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
for attr in getattr(context, 'dnsrecord_precallback_attrs', []):
param = self.params[attr]
param.dnsrecord_add_post_callback(ldap, dn, entry_attrs, *keys, **options)
@@ -2382,6 +2394,7 @@ class dnsrecord_mod(LDAPUpdate):
return super(dnsrecord_mod, self).args_options_2_entry(*keys, **options)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if options.get('rename') and self.obj.is_pkey_zone_record(*keys):
# zone rename is not allowed
raise errors.ValidationError(name='rename',
@@ -2466,10 +2479,12 @@ class dnsrecord_mod(LDAPUpdate):
return result
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if self.obj.is_pkey_zone_record(*keys):
entry_attrs[self.obj.primary_key.name] = [_dns_zone_record]
self.obj.postprocess_record(entry_attrs, **options)
+ return dn
def interactive_prompt_callback(self, kw):
try:
@@ -2564,6 +2579,7 @@ class dnsrecord_del(LDAPUpdate):
yield option
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn_, old_entry) = ldap.get_entry(
dn, _record_attributes,
@@ -2626,9 +2642,11 @@ class dnsrecord_del(LDAPUpdate):
return result
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if self.obj.is_pkey_zone_record(*keys):
entry_attrs[self.obj.primary_key.name] = [_dns_zone_record]
self.obj.postprocess_record(entry_attrs, **options)
+ return dn
def args_options_2_entry(self, *keys, **options):
self.obj.has_cli_options(options, self.no_option_msg)
@@ -2697,6 +2715,7 @@ class dnsrecord_show(LDAPRetrieve):
)
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if self.obj.is_pkey_zone_record(*keys):
entry_attrs[self.obj.primary_key.name] = [_dns_zone_record]
self.obj.postprocess_record(entry_attrs, **options)
@@ -2723,6 +2742,7 @@ class dnsrecord_find(LDAPSearch):
yield option
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
# include zone record (root entry) in the search
return (filter, base_dn, ldap.SCOPE_SUBTREE)
@@ -2774,7 +2794,7 @@ class dns_is_enabled(Command):
NO_CLI = True
has_output = output.standard_value
- base_dn = 'cn=masters,cn=ipa,cn=etc,%s' % api.env.basedn
+ base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
filter = '(&(objectClass=ipaConfigObject)(cn=DNS))'
def execute(self, *args, **options):
diff --git a/ipalib/plugins/entitle.py b/ipalib/plugins/entitle.py
index 5ccdb6510..67e7f959e 100644
--- a/ipalib/plugins/entitle.py
+++ b/ipalib/plugins/entitle.py
@@ -318,6 +318,7 @@ class entitle_consume(LDAPUpdate):
return result
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
quantity = keys[-1]
os.environ['LANG'] = 'en_US'
@@ -361,6 +362,7 @@ class entitle_consume(LDAPUpdate):
Returning the certificates isn't very interesting. Return the
status of entitlements instead.
"""
+ assert isinstance(dn, DN)
if 'usercertificate' in entry_attrs:
del entry_attrs['usercertificate']
if 'userpkcs12' in entry_attrs:
@@ -504,7 +506,7 @@ class entitle_register(LDAPCreate):
"""
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
- dn = '%s,%s' % (self.obj.container_dn, self.api.env.basedn)
+ dn = DN(self.obj.container_dn, self.api.env.basedn)
if not ldap.can_add(dn):
raise errors.ACIError(info='No permission to register')
os.environ['LANG'] = 'en_US'
@@ -604,6 +606,7 @@ class entitle_import(LDAPUpdate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
try:
(db, uuid, certfile, keyfile) = get_uuid(ldap)
if db is not None:
@@ -622,7 +625,7 @@ class entitle_import(LDAPUpdate):
raise errors.CertificateFormatError(error=_('Not an entitlement certificate'))
except M2Crypto.X509.X509Error:
raise errors.CertificateFormatError(error=_('Not an entitlement certificate'))
- dn = 'ipaentitlementid=%s,%s' % (entry_attrs['ipaentitlementid'], dn)
+ dn = DN(('ipaentitlementid', entry_attrs['ipaentitlementid']), dn)
(dn, current_attrs) = ldap.get_entry(
dn, ['*'], normalize=self.obj.normalize_dn
)
@@ -689,6 +692,7 @@ class entitle_sync(LDAPUpdate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
os.environ['LANG'] = 'en_US'
locale.setlocale(locale.LC_ALL, '')
@@ -719,6 +723,7 @@ class entitle_sync(LDAPUpdate):
Returning the certificates isn't very interesting. Return the
status of entitlements instead.
"""
+ assert isinstance(dn, DN)
if 'usercertificate' in entry_attrs:
del entry_attrs['usercertificate']
if 'userpkcs12' in entry_attrs:
diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py
index 74bea1700..011587206 100644
--- a/ipalib/plugins/group.py
+++ b/ipalib/plugins/group.py
@@ -156,6 +156,7 @@ class group_add(LDAPCreate):
# As both 'external' and 'nonposix' options have default= set for
# them, they will always be present in options dict, thus we can
# safely reference the values
+ assert isinstance(dn, DN)
if options['external']:
entry_attrs['objectclass'].append('ipaexternalgroup')
if 'gidnumber' in options:
@@ -176,6 +177,7 @@ class group_del(LDAPDelete):
msg_summary = _('Deleted group "%(value)s"')
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
config = ldap.get_ipa_config()[1]
def_primary_group = config.get('ipadefaultprimarygroup', '')
def_primary_group_dn = group_dn = self.obj.get_dn(def_primary_group)
@@ -192,6 +194,7 @@ class group_del(LDAPDelete):
return dn
def post_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
try:
api.Command['pwpolicy_del'](keys[-1])
except errors.NotFound:
@@ -220,6 +223,7 @@ class group_mod(LDAPUpdate):
)
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if ('posix' in options and options['posix']) or 'gidnumber' in options:
(dn, old_entry_attrs) = ldap.get_entry(dn, ['objectclass'])
if 'ipaexternalgroup' in old_entry_attrs['objectclass']:
@@ -275,6 +279,7 @@ class group_find(LDAPSearch):
)
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
# if looking for private groups, we need to create a new search filter,
# because private groups have different object classes
if options['private']:
@@ -319,6 +324,7 @@ class group_add_member(LDAPAddMember):
)
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
result = (completed, dn)
if 'ipaexternalmember' in options:
if not _dcerpc_bindings_installed:
@@ -367,6 +373,7 @@ class group_remove_member(LDAPRemoveMember):
)
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
if keys[0] == protected_group_name:
result = api.Command.group_show(protected_group_name)
users_left = set(result['result'].get('member_user', []))
@@ -377,6 +384,7 @@ class group_remove_member(LDAPRemoveMember):
return dn
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
result = (completed, dn)
if 'ipaexternalmember' in options:
sids = options['ipaexternalmember']
diff --git a/ipalib/plugins/hbacrule.py b/ipalib/plugins/hbacrule.py
index 460083622..94f0d0e20 100644
--- a/ipalib/plugins/hbacrule.py
+++ b/ipalib/plugins/hbacrule.py
@@ -231,6 +231,7 @@ class hbacrule_add(LDAPCreate):
msg_summary = _('Added HBAC rule "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# HBAC rules are enabled by default
entry_attrs['ipaenabledflag'] = 'TRUE'
return dn
@@ -244,6 +245,7 @@ class hbacrule_del(LDAPDelete):
msg_summary = _('Deleted HBAC rule "%(value)s"')
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
kw = dict(seealso=keys[0])
_entries = api.Command.selinuxusermap_find(None, **kw)
if _entries['count']:
@@ -260,6 +262,7 @@ class hbacrule_mod(LDAPUpdate):
msg_summary = _('Modified HBAC rule "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
except errors.NotFound:
@@ -436,6 +439,7 @@ class hbacrule_add_user(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -464,6 +468,7 @@ class hbacrule_add_host(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -492,6 +497,7 @@ class hbacrule_add_sourcehost(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -502,6 +508,7 @@ class hbacrule_add_sourcehost(LDAPAddMember):
return add_external_pre_callback('host', ldap, dn, keys, options)
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return add_external_post_callback('sourcehost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(hbacrule_add_sourcehost)
@@ -514,6 +521,7 @@ class hbacrule_remove_sourcehost(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return remove_external_post_callback('sourcehost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(hbacrule_remove_sourcehost)
@@ -526,6 +534,7 @@ class hbacrule_add_service(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
diff --git a/ipalib/plugins/host.py b/ipalib/plugins/host.py
index e8967b8c0..a417ba0f7 100644
--- a/ipalib/plugins/host.py
+++ b/ipalib/plugins/host.py
@@ -38,10 +38,10 @@ from ipalib.plugins.dns import (dns_container_exists, _record_types,
from ipalib.plugins.dns import get_reverse_zone
from ipalib import _, ngettext
from ipalib import x509
-from ipalib.dn import *
from ipalib.request import context
from ipalib.util import validate_sshpubkey, output_sshpubkey
from ipapython.ipautil import ipa_generate_password, CheckedIPAddress, make_sshfp
+from ipapython.dn import DN
__doc__ = _("""
Hosts/Machines
@@ -379,6 +379,7 @@ class host_add(LDAPCreate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if options.get('ip_address') and dns_container_exists(ldap):
parts = keys[-1].split('.')
host = parts[0]
@@ -423,6 +424,7 @@ class host_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
exc = None
if dns_container_exists(ldap):
try:
@@ -483,6 +485,7 @@ class host_del(LDAPDelete):
)
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
# If we aren't given a fqdn, find it
if _hostname_validator(None, keys[-1]) is not None:
hostentry = api.Command['host_show'](keys[-1])['result']
@@ -599,6 +602,7 @@ class host_mod(LDAPUpdate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# Allow an existing OTP to be reset but don't allow a OTP to be
# added to an enrolled host.
if options.get('userpassword') or options.get('random'):
@@ -690,6 +694,7 @@ class host_mod(LDAPUpdate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if options.get('random', False):
entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
set_certificate_attrs(entry_attrs)
@@ -728,6 +733,7 @@ class host_find(LDAPSearch):
yield option
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
if 'locality' in attrs_list:
attrs_list.remove('locality')
attrs_list.append('l')
@@ -808,6 +814,7 @@ class host_show(LDAPRetrieve):
member_attributes = ['managedby']
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.get_password_attributes(ldap, dn, entry_attrs)
if entry_attrs['has_password']:
# If an OTP is set there is no keytab, at least not one
@@ -891,8 +898,7 @@ class host_disable(LDAPQuery):
try:
serial = unicode(x509.get_serial_number(cert, x509.DER))
try:
- result = api.Command['cert_show'](unicode(serial))['result'
-]
+ result = api.Command['cert_show'](unicode(serial))['result']
if 'revocation_reason' not in result:
try:
api.Command['cert_revoke'](unicode(serial), revocation_reason=4)
@@ -928,6 +934,7 @@ class host_disable(LDAPQuery):
)
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.suppress_netgroup_memberof(entry_attrs)
return dn
@@ -941,6 +948,7 @@ class host_add_managedby(LDAPAddMember):
allow_same = True
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.suppress_netgroup_memberof(entry_attrs)
return (completed, dn)
@@ -954,6 +962,7 @@ class host_remove_managedby(LDAPRemoveMember):
has_output_params = LDAPRemoveMember.has_output_params + host_output_params
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.suppress_netgroup_memberof(entry_attrs)
return (completed, dn)
diff --git a/ipalib/plugins/hostgroup.py b/ipalib/plugins/hostgroup.py
index b68c45842..7e6fe6d65 100644
--- a/ipalib/plugins/hostgroup.py
+++ b/ipalib/plugins/hostgroup.py
@@ -21,7 +21,7 @@
from ipalib.plugins.baseldap import *
from ipalib import api, Int, _, ngettext, errors
from ipalib.plugins.netgroup import NETGROUP_PATTERN, NETGROUP_PATTERN_ERRMSG
-from ipalib.dn import DN
+from ipapython.dn import DN
__doc__ = _("""
Groups of hosts.
@@ -119,6 +119,7 @@ class hostgroup_add(LDAPCreate):
msg_summary = _('Added hostgroup "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
try:
# check duplicity with hostgroups first to provide proper error
netgroup = api.Command['hostgroup_show'](keys[-1])
@@ -140,6 +141,7 @@ class hostgroup_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
# Always wait for the associated netgroup to be created so we can
# be sure to ignore it in memberOf
newentry = wait_for_value(ldap, dn, 'objectclass', 'mepOriginEntry')
@@ -166,6 +168,7 @@ class hostgroup_mod(LDAPUpdate):
msg_summary = _('Modified hostgroup "%(value)s"')
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.suppress_netgroup_memberof(dn, entry_attrs)
return dn
@@ -195,6 +198,7 @@ class hostgroup_show(LDAPRetrieve):
__doc__ = _('Display information about a hostgroup.')
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.suppress_netgroup_memberof( dn, entry_attrs)
return dn
@@ -205,6 +209,7 @@ class hostgroup_add_member(LDAPAddMember):
__doc__ = _('Add members to a hostgroup.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.suppress_netgroup_memberof(dn, entry_attrs)
return (completed, dn)
@@ -215,6 +220,7 @@ class hostgroup_remove_member(LDAPRemoveMember):
__doc__ = _('Remove members from a hostgroup.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.suppress_netgroup_memberof(dn, entry_attrs)
return (completed, dn)
diff --git a/ipalib/plugins/krbtpolicy.py b/ipalib/plugins/krbtpolicy.py
index 0f80c770c..60674cc06 100644
--- a/ipalib/plugins/krbtpolicy.py
+++ b/ipalib/plugins/krbtpolicy.py
@@ -71,7 +71,7 @@ class krbtpolicy(LDAPObject):
"""
Kerberos Ticket Policy object
"""
- container_dn = 'cn=%s,cn=kerberos' % api.env.realm
+ container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos'))
object_name = _('kerberos ticket policy settings')
default_attributes = ['krbmaxticketlife', 'krbmaxrenewableage']
limit_object_classes = ['krbticketpolicyaux']
@@ -112,6 +112,7 @@ class krbtpolicy_mod(LDAPUpdate):
__doc__ = _('Modify Kerberos ticket policy.')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# disable all flag
# ticket policies are attached to objects with unrelated attributes
if options.get('all'):
@@ -125,6 +126,7 @@ class krbtpolicy_show(LDAPRetrieve):
__doc__ = _('Display the current Kerberos ticket policy.')
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# disable all flag
# ticket policies are attached to objects with unrelated attributes
if options.get('all'):
@@ -132,6 +134,7 @@ class krbtpolicy_show(LDAPRetrieve):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if keys[-1] is not None:
# if policy for a specific user isn't set, display global values
if 'krbmaxticketlife' not in entry_attrs or \
diff --git a/ipalib/plugins/migration.py b/ipalib/plugins/migration.py
index a8c1c6d82..157ab4447 100644
--- a/ipalib/plugins/migration.py
+++ b/ipalib/plugins/migration.py
@@ -21,10 +21,8 @@ import re
import ldap as _ldap
from ipalib import api, errors, output
-from ipalib import Command, Password, Str, Flag, StrEnum
+from ipalib import Command, Password, Str, Flag, StrEnum, DNParam
from ipalib.cli import to_cli
-from ipalib.util import validate_dn_param
-from ipalib.dn import *
from ipalib.plugins.user import NO_UPG_MAGIC
if api.env.in_server and api.env.context in ['lite', 'server']:
try:
@@ -32,6 +30,7 @@ if api.env.in_server and api.env.context in ['lite', 'server']:
except StandardError, e:
raise e
from ipalib import _
+from ipapython.dn import DN
__doc__ = _("""
Migration to IPA
@@ -114,18 +113,10 @@ _dn_err_msg = _('Malformed DN')
_supported_schemas = (u'RFC2307bis', u'RFC2307')
-_compat_dn = "cn=Schema Compatibility,cn=plugins,cn=config"
-
-def is_DN_syntax(ldap, attr):
- """
- Check the schema to see if the attribute uses DN syntax.
-
- Returns True/False
- """
- obj = ldap.schema.get_obj(_ldap.schema.AttributeType, attr)
- return obj is not None and obj.syntax == '1.3.6.1.4.1.1466.115.121.1.12'
+_compat_dn = DN(('cn', 'Schema Compatibility'), ('cn', 'plugins'), ('cn', 'config'))
def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs):
+ assert isinstance(dn, DN)
attr_blacklist = ['krbprincipalkey','memberofindirect','memberindirect']
attr_blacklist.extend(kwargs.get('attr_blacklist', []))
ds_ldap = ctx['ds_ldap']
@@ -198,17 +189,18 @@ def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs
# tree
for attr in entry_attrs.keys():
- if is_DN_syntax(ldap, attr):
+ if ldap.has_dn_syntax(attr):
for ind, value in enumerate(entry_attrs[attr]):
+ assert isinstance(value, DN)
try:
(remote_dn, remote_entry) = ds_ldap.get_entry(value, [api.Object.user.primary_key.name, api.Object.group.primary_key.name])
except errors.NotFound:
api.log.warn('%s: attribute %s refers to non-existent entry %s' % (pkey, attr, value))
continue
- if value.lower().endswith(search_bases['user']):
+ if value.endswith(search_bases['user']):
primary_key = api.Object.user.primary_key.name
container = api.env.container_user
- elif value.lower().endswith(search_bases['group']):
+ elif value.endswith(search_bases['group']):
primary_key = api.Object.group.primary_key.name
container = api.env.container_group
else:
@@ -221,15 +213,13 @@ def _pre_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs
api.log.debug('converting DN value %s for %s in %s' % (value, attr, dn))
rdnval = remote_entry[primary_key][0].lower()
- entry_attrs[attr][ind] = \
- str(DN((primary_key, rdnval),
- container,
- api.env.basedn))
+ entry_attrs[attr][ind] = DN((primary_key, rdnval), container, api.env.basedn)
return dn
def _post_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx):
+ assert isinstance(dn, DN)
# add user to the default group
try:
ldap.add_entry_to_group(dn, ctx['def_group_dn'])
@@ -246,6 +236,7 @@ def _post_migrate_user(ldap, pkey, dn, entry_attrs, failed, config, ctx):
# GROUP MIGRATION CALLBACKS AND VARS
def _pre_migrate_group(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwargs):
+
def convert_members_rfc2307bis(member_attr, search_bases, overwrite=False):
"""
Convert DNs in member attributes to work in IPA.
@@ -253,24 +244,19 @@ def _pre_migrate_group(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwarg
new_members = []
entry_attrs.setdefault(member_attr, [])
for m in entry_attrs[member_attr]:
+ assert isinstance(m, DN)
try:
- # what str2dn returns looks like [[('cn', 'foo', 4)], [('dc', 'example', 1)], [('dc', 'com', 1)]]
- rdn = _ldap.dn.str2dn(m ,flags=_ldap.DN_FORMAT_LDAPV3)[0]
- rdnval = rdn[0][1]
+ rdnval = m[0].value
except IndexError:
api.log.error('Malformed DN %s has no RDN?' % m)
continue
- if m.lower().endswith(search_bases['user']):
+ if m.endswith(search_bases['user']):
api.log.info('migrating user %s' % m)
- m = '%s=%s,%s' % (api.Object.user.primary_key.name,
- rdnval,
- api.env.container_user)
- elif m.lower().endswith(search_bases['group']):
+ m = DN((api.Object.user.primary_key.name, rdnval), api.env.container_user)
+ elif m.endswith(search_bases['group']):
api.log.info('migrating group %s' % m)
- m = '%s=%s,%s' % (api.Object.group.primary_key.name,
- rdnval,
- api.env.container_group)
+ m = DN((api.Object.group.primary_key.name, rdnval), api.env.container_group)
else:
api.log.error('entry %s does not belong into any known container' % m)
continue
@@ -290,12 +276,11 @@ def _pre_migrate_group(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwarg
new_members = []
entry_attrs.setdefault(member_attr, [])
for m in entry_attrs[member_attr]:
- memberdn = '%s=%s,%s' % (api.Object.user.primary_key.name,
- m,
- api.env.container_user)
+ memberdn = DN((api.Object.user.primary_key.name, m), api.env.container_user)
new_members.append(ldap.normalize_dn(memberdn))
entry_attrs['member'] = new_members
+ assert isinstance(dn, DN)
attr_blacklist = ['memberofindirect','memberindirect']
attr_blacklist.extend(kwargs.get('attr_blacklist', []))
@@ -330,6 +315,7 @@ def _pre_migrate_group(ldap, pkey, dn, entry_attrs, failed, config, ctx, **kwarg
def _group_exc_callback(ldap, dn, entry_attrs, exc, options):
+ assert isinstance(dn, DN)
if isinstance(exc, errors.DuplicateEntry):
if options.get('groupoverwritegid', False) and \
entry_attrs.get('gidnumber') is not None:
@@ -424,24 +410,24 @@ class migrate_ds(Command):
)
takes_options = (
- Str('binddn?', validate_dn_param,
+ DNParam('binddn?',
cli_name='bind_dn',
label=_('Bind DN'),
- default=u'cn=directory manager',
+ default=DN(('cn', 'directory manager')),
autofill=True,
),
- Str('usercontainer', validate_dn_param,
+ DNParam('usercontainer',
cli_name='user_container',
label=_('User container'),
doc=_('DN of container for users in DS relative to base DN'),
- default=u'ou=people',
+ default=DN(('ou', 'people')),
autofill=True,
),
- Str('groupcontainer', validate_dn_param,
+ DNParam('groupcontainer',
cli_name='group_container',
label=_('Group container'),
doc=_('DN of container for groups in DS relative to base DN'),
- default=u'ou=groups',
+ default=DN(('ou', 'groups')),
autofill=True,
),
Str('userobjectclass+',
@@ -511,7 +497,7 @@ class migrate_ds(Command):
doc=_('Continuous operation mode. Errors are reported but the process continues'),
default=False,
),
- Str('basedn?',
+ DNParam('basedn?',
cli_name='base_dn',
label=_('Base DN'),
doc=_('Base DN on remote LDAP server'),
@@ -594,11 +580,9 @@ can use their Kerberos accounts.''')
def _get_search_bases(self, options, ds_base_dn, migrate_order):
search_bases = dict()
- ds_base_dn = DN(ds_base_dn)
for ldap_obj_name in migrate_order:
container = options.get('%scontainer' % to_cli(ldap_obj_name))
if container:
- container = DN(container)
# Don't append base dn if user already appended it in the container dn
if container.endswith(ds_base_dn):
search_base = container
@@ -606,13 +590,14 @@ can use their Kerberos accounts.''')
search_base = DN(container, ds_base_dn)
else:
search_base = ds_base_dn
- search_bases[ldap_obj_name] = str(search_base)
+ search_bases[ldap_obj_name] = search_base
return search_bases
def migrate(self, ldap, config, ds_ldap, ds_base_dn, options):
"""
Migrate objects from DS to LDAP.
"""
+ assert isinstance(ds_base_dn, DN)
migrated = {} # {'OBJ': ['PKEY1', 'PKEY2', ...], ...}
failed = {} # {'OBJ': {'PKEY1': 'Failed 'cos blabla', ...}, ...}
search_bases = self._get_search_bases(options, ds_base_dn, self.migrate_order)
@@ -703,6 +688,7 @@ can use their Kerberos accounts.''')
continue
dn = ldap_obj.get_dn(pkey)
+ assert isinstance(dn, DN)
entry_attrs['objectclass'] = list(
set(
config.get(
@@ -722,6 +708,7 @@ can use their Kerberos accounts.''')
valid_gids = valid_gids,
**blacklists
)
+ assert isinstance(dn, DN)
if not dn:
continue
except errors.NotFound, e:
@@ -760,6 +747,8 @@ can use their Kerberos accounts.''')
config = ldap.get_ipa_config()[1]
ds_base_dn = options.get('basedn')
+ if ds_base_dn is not None:
+ assert isinstance(ds_base_dn, DN)
# check if migration mode is enabled
if config.get('ipamigrationenabled', ('FALSE', ))[0] == 'FALSE':
@@ -773,6 +762,7 @@ can use their Kerberos accounts.''')
if not options.get('compat'):
try:
(dn,check_compat) = ldap.get_entry(_compat_dn, normalize=False)
+ assert isinstance(dn, DN)
if check_compat is not None and \
check_compat.get('nsslapd-pluginenabled', [''])[0].lower() == 'on':
return dict(result={}, failed={}, enabled=True, compat=False)
@@ -782,14 +772,16 @@ can use their Kerberos accounts.''')
if not ds_base_dn:
# retrieve base DN from remote LDAP server
(entries, truncated) = ds_ldap.find_entries(
- '', ['namingcontexts', 'defaultnamingcontext'], '',
+ '', ['namingcontexts', 'defaultnamingcontext'], DN(''),
_ldap.SCOPE_BASE, size_limit=-1, time_limit=0,
)
if 'defaultnamingcontext' in entries[0][1]:
- ds_base_dn = entries[0][1]['defaultnamingcontext'][0]
+ ds_base_dn = DN(entries[0][1]['defaultnamingcontext'][0])
+ assert isinstance(ds_base_dn, DN)
else:
try:
- ds_base_dn = entries[0][1]['namingcontexts'][0]
+ ds_base_dn = DN(entries[0][1]['namingcontexts'][0])
+ assert isinstance(ds_base_dn, DN)
except (IndexError, KeyError), e:
raise StandardError(str(e))
diff --git a/ipalib/plugins/netgroup.py b/ipalib/plugins/netgroup.py
index 4236feeb7..263d66b55 100644
--- a/ipalib/plugins/netgroup.py
+++ b/ipalib/plugins/netgroup.py
@@ -162,6 +162,7 @@ class netgroup_add(LDAPCreate):
u'Hostgroups and netgroups share a common namespace')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
entry_attrs.setdefault('nisdomainname', self.api.env.domain)
try:
@@ -203,6 +204,7 @@ class netgroup_mod(LDAPUpdate):
msg_summary = _('Modified netgroup "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, attrs_list)
except errors.NotFound:
@@ -238,6 +240,7 @@ class netgroup_find(LDAPSearch):
)
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
# Do not display private mepManagedEntry netgroups by default
# If looking for managed groups, we need to omit the negation search filter
@@ -267,8 +270,11 @@ class netgroup_add_member(LDAPAddMember):
member_attributes = ['memberuser', 'memberhost', 'member']
has_output_params = LDAPAddMember.has_output_params + output_params
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
return add_external_pre_callback('host', ldap, dn, keys, options)
+
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return add_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(netgroup_add_member)
@@ -280,6 +286,7 @@ class netgroup_remove_member(LDAPRemoveMember):
member_attributes = ['memberuser', 'memberhost', 'member']
has_output_params = LDAPRemoveMember.has_output_params + output_params
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return remove_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(netgroup_remove_member)
diff --git a/ipalib/plugins/passwd.py b/ipalib/plugins/passwd.py
index 9bee314ec..2c83560b1 100644
--- a/ipalib/plugins/passwd.py
+++ b/ipalib/plugins/passwd.py
@@ -24,6 +24,7 @@ from ipalib import _
from ipalib import output
from ipalib.plugins.user import split_principal, validate_principal, normalize_principal
from ipalib.request import context
+from ipapython.dn import DN
__doc__ = _("""
Set a user's password
@@ -104,7 +105,7 @@ class passwd(Command):
(dn, entry_attrs) = ldap.find_entry_by_attr(
'krbprincipalname', principal, 'posixaccount', [''],
- ",".join([api.env.container_user, api.env.basedn])
+ DN(api.env.container_user, api.env.basedn)
)
if principal == getattr(context, 'principal') and \
diff --git a/ipalib/plugins/permission.py b/ipalib/plugins/permission.py
index 89f9eaa62..befa74df8 100644
--- a/ipalib/plugins/permission.py
+++ b/ipalib/plugins/permission.py
@@ -22,6 +22,7 @@ from ipalib import api, _, ngettext
from ipalib import Flag, Str, StrEnum
from ipalib.request import context
from ipalib import errors
+from ipapython.dn import DN, EditableDN
__doc__ = _("""
Permissions
@@ -202,6 +203,7 @@ class permission_add(LDAPCreate):
has_output_params = LDAPCreate.has_output_params + output_params
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# Test the ACI before going any further
opts = self.obj.filter_aci_attributes(options)
opts['test'] = True
@@ -219,6 +221,7 @@ class permission_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
# Now actually add the aci.
opts = self.obj.filter_aci_attributes(options)
opts['test'] = False
@@ -275,6 +278,7 @@ class permission_add_noaci(LDAPCreate):
yield option
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
permission_type = options.get('permissiontype')
if permission_type:
entry_attrs['ipapermissiontype'] = [ permission_type ]
@@ -297,6 +301,7 @@ class permission_del(LDAPDelete):
)
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
if not options.get('force') and not self.obj.check_system(ldap, dn, *keys):
raise errors.ACIError(info='A SYSTEM permission may not be removed')
# remove permission even when the underlying ACI is missing
@@ -316,6 +321,7 @@ class permission_mod(LDAPUpdate):
has_output_params = LDAPUpdate.has_output_params + output_params
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if not self.obj.check_system(ldap, dn, *keys):
raise errors.ACIError(info='A SYSTEM permission may not be modified')
@@ -332,10 +338,13 @@ class permission_mod(LDAPUpdate):
if 'rename' in options:
if options['rename']:
try:
- new_dn = dn.replace(keys[-1].lower(), options['rename'], 1)
- (new_dn, attrs) = ldap.get_entry(
- new_dn, attrs_list, normalize=self.obj.normalize_dn
- )
+ try:
+ new_dn = EditableDN(dn)
+ new_dn[0]['cn'] # assure the first RDN has cn as it's type
+ except (IndexError, KeyError), e:
+ raise ValueError("expected dn starting with 'cn=' but got '%s'" % dn)
+ new_dn[0].value = options['rename']
+ (new_dn, attrs) = ldap.get_entry(new_dn, attrs_list, normalize=self.obj.normalize_dn)
raise errors.DuplicateEntry()
except errors.NotFound:
pass # permission may be renamed, continue
@@ -371,6 +380,7 @@ class permission_mod(LDAPUpdate):
raise exc
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
# rename the underlying ACI after the change to permission
cn = keys[-1]
@@ -480,6 +490,7 @@ class permission_show(LDAPRetrieve):
has_output_params = LDAPRetrieve.has_output_params + output_params
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
try:
common_options = filter_options(options, ['all', 'raw'])
aci = self.api.Command.aci_show(keys[-1], aciprefix=ACI_PREFIX,
diff --git a/ipalib/plugins/pkinit.py b/ipalib/plugins/pkinit.py
index cb3b9c2fc..2d11f0244 100644
--- a/ipalib/plugins/pkinit.py
+++ b/ipalib/plugins/pkinit.py
@@ -21,6 +21,7 @@ from ipalib import api, errors
from ipalib import Int, Str
from ipalib import Object, Command
from ipalib import _
+from ipapython.dn import DN
__doc__ = _("""
Kerberos pkinit options
@@ -67,9 +68,7 @@ class pkinit_anonymous(Command):
__doc__ = _('Enable or Disable Anonymous PKINIT.')
princ_name = 'WELLKNOWN/ANONYMOUS@%s' % api.env.realm
- default_dn = 'krbprincipalname=%s,cn=%s,cn=kerberos,%s' % (
- princ_name, api.env.realm, api.env.basedn
- )
+ default_dn = DN(('krbprincipalname', princ_name), ('cn', api.env.realm), ('cn', 'kerberos'), api.env.basedn)
takes_args = (
Str('action', valid_arg),
diff --git a/ipalib/plugins/pwpolicy.py b/ipalib/plugins/pwpolicy.py
index 77e6f2c79..33c8329f7 100644
--- a/ipalib/plugins/pwpolicy.py
+++ b/ipalib/plugins/pwpolicy.py
@@ -19,11 +19,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from ipalib import api
-from ipalib import Int, Str
+from ipalib import Int, Str, DNParam
from ipalib.plugins.baseldap import *
from ipalib import _
from ipalib.request import context
from ipapython.ipautil import run
+from ipapython.dn import DN
from distutils import version
__doc__ = _("""
@@ -75,13 +76,13 @@ class cosentry(LDAPObject):
"""
NO_CLI = True
- container_dn = 'cn=costemplates,%s' % api.env.container_accounts
+ container_dn = DN(('cn', 'costemplates'), api.env.container_accounts)
object_class = ['top', 'costemplate', 'extensibleobject', 'krbcontainer']
default_attributes = ['cn', 'cospriority', 'krbpwdpolicyreference']
takes_params = (
Str('cn', primary_key=True),
- Str('krbpwdpolicyreference'),
+ DNParam('krbpwdpolicyreference'),
Int('cospriority', minvalue=0),
)
@@ -102,8 +103,7 @@ class cosentry(LDAPObject):
)['result']
if len(entries) > 0:
group_name = self.api.Object.group.get_primary_key_from_dn(
- entries[0]['cn'][0]
- )
+ DN(entries[0]['cn'][0]))
raise errors.ValidationError(
name='priority',
error=self.priority_not_unique_msg % {
@@ -119,6 +119,7 @@ class cosentry_add(LDAPCreate):
NO_CLI = True
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# check for existence of the group
result = self.api.Command.group_show(keys[-1], all=True)['result']
oc = map(lambda x:x.lower(),result['objectclass'])
@@ -141,6 +142,7 @@ class cosentry_mod(LDAPUpdate):
NO_CLI = True
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
new_cospriority = options.get('cospriority')
if new_cospriority is not None:
cos_entry = self.api.Command.cosentry_show(keys[-1])['result']
@@ -167,13 +169,13 @@ api.register(cosentry_find)
global_policy_name = 'global_policy'
-global_policy_dn = 'cn=%s,cn=%s,cn=kerberos,%s' % (global_policy_name, api.env.realm, api.env.basedn)
+global_policy_dn = DN(('cn', global_policy_name), ('cn', api.env.realm), ('cn', 'kerberos'), api.env.basedn)
class pwpolicy(LDAPObject):
"""
Password Policy object
"""
- container_dn = 'cn=%s,cn=kerberos' % api.env.realm
+ container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos'))
object_name = _('password policy')
object_name_plural = _('password policies')
object_class = ['top', 'nscontainer', 'krbpwdpolicy']
@@ -339,6 +341,7 @@ class pwpolicy_add(LDAPCreate):
yield self.obj.primary_key.clone(attribute=True, required=True)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.convert_time_on_input(entry_attrs)
self.obj.validate_lifetime(entry_attrs, True)
self.api.Command.cosentry_add(
@@ -348,6 +351,7 @@ class pwpolicy_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.log.info('%r' % entry_attrs)
# attribute rights are not allowed for pwpolicy_add
self.obj.add_cospriority(entry_attrs, keys[-1], rights=False)
@@ -366,7 +370,8 @@ class pwpolicy_del(LDAPDelete):
)
def pre_callback(self, ldap, dn, *keys, **options):
- if dn.lower() == global_policy_dn.lower():
+ assert isinstance(dn, DN)
+ if dn == global_policy_dn:
raise errors.ValidationError(
name='group',
error=_('cannot delete global password policy')
@@ -374,6 +379,7 @@ class pwpolicy_del(LDAPDelete):
return dn
def post_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
try:
self.api.Command.cosentry_del(keys[-1])
except errors.NotFound:
@@ -387,6 +393,7 @@ class pwpolicy_mod(LDAPUpdate):
__doc__ = _('Modify a group password policy.')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.convert_time_on_input(entry_attrs)
self.obj.validate_lifetime(entry_attrs, False, *keys)
setattr(context, 'cosupdate', False)
@@ -408,6 +415,7 @@ class pwpolicy_mod(LDAPUpdate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
rights = options.get('all', False) and options.get('rights', False)
self.obj.add_cospriority(entry_attrs, keys[-1], rights)
self.obj.convert_time_for_output(entry_attrs, **options)
@@ -436,6 +444,7 @@ class pwpolicy_show(LDAPRetrieve):
)
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if options.get('user') is not None:
user_entry = self.api.Command.user_show(
options['user'], all=True
@@ -445,6 +454,7 @@ class pwpolicy_show(LDAPRetrieve):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
rights = options.get('all', False) and options.get('rights', False)
self.obj.add_cospriority(entry_attrs, keys[-1], rights)
self.obj.convert_time_for_output(entry_attrs, **options)
diff --git a/ipalib/plugins/range.py b/ipalib/plugins/range.py
index 39849b661..c1d918679 100644
--- a/ipalib/plugins/range.py
+++ b/ipalib/plugins/range.py
@@ -96,6 +96,7 @@ class range_add(LDAPCreate):
msg_summary = _('Added ID range "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if ('ipanttrusteddomainsid' not in options and
'ipasecondarybaserid' not in options):
raise errors.ValidationError(name=_('Range setup'),
@@ -110,6 +111,7 @@ class range_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.handle_iparangetype(entry_attrs, options, keep_objectclass=True)
return dn
@@ -128,6 +130,7 @@ class range_find(LDAPSearch):
# Since all range types are stored within separate containers under
# 'cn=ranges,cn=etc' search can be done on a one-level scope
def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
attrs_list.append('objectclass')
return (filters, base_dn, ldap.SCOPE_ONELEVEL)
@@ -140,10 +143,12 @@ class range_show(LDAPRetrieve):
__doc__ = _('Display information about a range.')
def pre_callback(self, ldap, dn, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
attrs_list.append('objectclass')
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.handle_iparangetype(entry_attrs, options)
return dn
@@ -153,10 +158,12 @@ class range_mod(LDAPUpdate):
msg_summary = _('Modified ID range "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
attrs_list.append('objectclass')
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.handle_iparangetype(entry_attrs, options)
return dn
@@ -166,4 +173,3 @@ api.register(range_mod)
api.register(range_del)
api.register(range_find)
api.register(range_show)
-
diff --git a/ipalib/plugins/selinuxusermap.py b/ipalib/plugins/selinuxusermap.py
index 160e68c96..988cb4f0b 100644
--- a/ipalib/plugins/selinuxusermap.py
+++ b/ipalib/plugins/selinuxusermap.py
@@ -234,6 +234,7 @@ class selinuxusermap_add(LDAPCreate):
msg_summary = _('Added SELinux User Map "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
# rules are enabled by default
entry_attrs['ipaenabledflag'] = 'TRUE'
validate_selinuxuser_inlist(ldap, entry_attrs['ipaselinuxuser'])
@@ -243,6 +244,7 @@ class selinuxusermap_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj._convert_seealso(ldap, entry_attrs, **options)
return dn
@@ -264,6 +266,7 @@ class selinuxusermap_mod(LDAPUpdate):
msg_summary = _('Modified SELinux User Map "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
try:
(_dn, _entry_attrs) = ldap.get_entry(dn, attrs_list)
except errors.NotFound:
@@ -288,6 +291,7 @@ class selinuxusermap_mod(LDAPUpdate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj._convert_seealso(ldap, entry_attrs, **options)
return dn
@@ -331,6 +335,7 @@ class selinuxusermap_show(LDAPRetrieve):
__doc__ = _('Display the properties of a SELinux User Map rule.')
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj._convert_seealso(ldap, entry_attrs, **options)
return dn
@@ -398,6 +403,7 @@ class selinuxusermap_add_user(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -428,6 +434,7 @@ class selinuxusermap_add_host(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(dn, entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
diff --git a/ipalib/plugins/service.py b/ipalib/plugins/service.py
index 7cb7b8030..213711ab3 100644
--- a/ipalib/plugins/service.py
+++ b/ipalib/plugins/service.py
@@ -278,6 +278,7 @@ class service_add(LDAPCreate):
),
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
(service, hostname, realm) = split_principal(keys[-1])
if service.lower() == 'host' and not options['force']:
raise errors.HostService()
@@ -322,6 +323,7 @@ class service_del(LDAPDelete):
msg_summary = _('Deleted service "%(value)s"')
member_attributes = ['managedby']
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
# In the case of services we don't want IPA master services to be
# deleted. This is a limited few though. If the user has their own
# custom services allow them to manage them.
@@ -367,6 +369,7 @@ class service_mod(LDAPUpdate):
member_attributes = ['managedby']
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if 'usercertificate' in options:
(service, hostname, realm) = split_principal(keys[-1])
cert = options.get('usercertificate')
@@ -386,7 +389,9 @@ class service_mod(LDAPUpdate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
set_certificate_attrs(entry_attrs)
+ return dn
api.register(service_mod)
@@ -402,6 +407,7 @@ class service_find(LDAPSearch):
has_output_params = LDAPSearch.has_output_params + output_params
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
# lisp style!
custom_filter = '(&(objectclass=ipaService)' \
'(!(objectClass=posixAccount))' \
@@ -439,6 +445,7 @@ class service_show(LDAPRetrieve):
has_output_params = LDAPRetrieve.has_output_params + output_params
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.get_password_attributes(ldap, dn, entry_attrs)
set_certificate_attrs(entry_attrs)
diff --git a/ipalib/plugins/sudorule.py b/ipalib/plugins/sudorule.py
index 723cce2e4..e2937949b 100644
--- a/ipalib/plugins/sudorule.py
+++ b/ipalib/plugins/sudorule.py
@@ -246,6 +246,7 @@ class sudorule_add(LDAPCreate):
__doc__ = _('Create new Sudo Rule.')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
self.obj.check_order_uniqueness(*keys, **options)
# Sudo Rules are enabled by default
entry_attrs['ipaenabledflag'] = 'TRUE'
@@ -269,6 +270,7 @@ class sudorule_mod(LDAPUpdate):
msg_summary = _('Modified Sudo Rule "%(value)s"')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if 'sudoorder' in options:
new_order = options.get('sudoorder')
old_entry = self.api.Command.sudorule_show(keys[-1])['result']
@@ -371,6 +373,7 @@ class sudorule_add_allow_command(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -399,6 +402,7 @@ class sudorule_add_deny_command(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -426,6 +430,7 @@ class sudorule_add_user(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -435,6 +440,7 @@ class sudorule_add_user(LDAPAddMember):
return add_external_pre_callback('user', ldap, dn, keys, options)
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return add_external_post_callback('memberuser', 'user', 'externaluser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_user)
@@ -447,6 +453,7 @@ class sudorule_remove_user(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return remove_external_post_callback('memberuser', 'user', 'externaluser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_user)
@@ -459,6 +466,7 @@ class sudorule_add_host(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, found, not_found, *keys, **options):
+ assert isinstance(dn, DN)
try:
(_dn, _entry_attrs) = ldap.get_entry(dn, self.obj.default_attributes)
except errors.NotFound:
@@ -468,6 +476,7 @@ class sudorule_add_host(LDAPAddMember):
return add_external_pre_callback('host', ldap, dn, keys, options)
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return add_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_host)
@@ -480,6 +489,7 @@ class sudorule_remove_host(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return remove_external_post_callback('memberhost', 'host', 'externalhost', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_host)
@@ -491,6 +501,7 @@ class sudorule_add_runasuser(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
def check_validity(runas):
v = unicode(runas)
if v.upper() == u'ALL':
@@ -521,6 +532,7 @@ class sudorule_add_runasuser(LDAPAddMember):
return add_external_pre_callback('user', ldap, dn, keys, options)
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return add_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_runasuser)
@@ -533,6 +545,7 @@ class sudorule_remove_runasuser(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return remove_external_post_callback('ipasudorunas', 'user', 'ipasudorunasextuser', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_runasuser)
@@ -545,6 +558,7 @@ class sudorule_add_runasgroup(LDAPAddMember):
member_count_out = ('%i object added.', '%i objects added.')
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
def check_validity(runas):
v = unicode(runas)
if v.upper() == u'ALL':
@@ -569,6 +583,7 @@ class sudorule_add_runasgroup(LDAPAddMember):
return add_external_pre_callback('group', ldap, dn, keys, options)
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return add_external_post_callback('ipasudorunasgroup', 'group', 'ipasudorunasextgroup', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_add_runasgroup)
@@ -581,6 +596,7 @@ class sudorule_remove_runasgroup(LDAPRemoveMember):
member_count_out = ('%i object removed.', '%i objects removed.')
def post_callback(self, ldap, completed, failed, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
return remove_external_post_callback('ipasudorunasgroup', 'group', 'ipasudorunasextgroup', ldap, completed, failed, dn, entry_attrs, keys, options)
api.register(sudorule_remove_runasgroup)
diff --git a/ipalib/plugins/trust.py b/ipalib/plugins/trust.py
index acb65b388..a70293bff 100644
--- a/ipalib/plugins/trust.py
+++ b/ipalib/plugins/trust.py
@@ -107,9 +107,10 @@ class trust(LDAPObject):
)
def make_trust_dn(env, trust_type, dn):
+ assert isinstance(dn, DN)
if trust_type in trust.trust_types:
container_dn = DN(('cn', trust_type), env.container_trusts, env.basedn)
- return unicode(DN(DN(dn)[0], container_dn))
+ return DN(dn[0], container_dn)
return dn
class trust_add(LDAPCreate):
@@ -214,6 +215,7 @@ class trust_del(LDAPDelete):
msg_summary = _('Deleted trust "%(value)s"')
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
try:
result = self.api.Command.trust_show(keys[-1])
except errors.NotFound, e:
@@ -226,6 +228,7 @@ class trust_mod(LDAPUpdate):
msg_summary = _('Modified trust "%(value)s"')
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
result = None
try:
result = self.api.Command.trust_show(keys[-1])
@@ -245,6 +248,7 @@ class trust_find(LDAPSearch):
# Since all trusts types are stored within separate containers under 'cn=trusts',
# search needs to be done on a sub-tree scope
def pre_callback(self, ldap, filters, attrs_list, base_dn, scope, *args, **options):
+ assert isinstance(base_dn, DN)
return (filters, base_dn, ldap.SCOPE_SUBTREE)
class trust_show(LDAPRetrieve):
@@ -271,6 +275,7 @@ class trust_show(LDAPRetrieve):
return result
def pre_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if 'trust_show_type' in options:
return make_trust_dn(self.env, options['trust_show_type'], dn)
return dn
@@ -281,4 +286,3 @@ api.register(trust_mod)
api.register(trust_del)
api.register(trust_find)
api.register(trust_show)
-
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index c19d9a666..529699f9a 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -375,11 +375,12 @@ class user(LDAPObject):
if not manager:
return None
- if isinstance(manager, basestring):
+ if not isinstance(manager, list):
manager = [manager]
try:
+ container_dn = DN(self.container_dn, api.env.basedn)
for m in xrange(len(manager)):
- if manager[m].endswith('%s,%s' % (self.container_dn, api.env.basedn)):
+ if isinstance(manager[m], DN) and manager[m].endswith(container_dn):
continue
(dn, entry_attrs) = self.backend.find_entry_by_attr(
self.primary_key.name, manager[m], self.object_class, [''],
@@ -420,6 +421,7 @@ class user_add(LDAPCreate):
)
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if not options.get('noprivate', False):
try:
# The Managed Entries plugin will allow a user to be created
@@ -459,7 +461,9 @@ class user_add(LDAPCreate):
homes_root = config.get('ipahomesrootdir', ['/home'])[0]
# build user's home directory based on his uid
entry_attrs['homedirectory'] = posixpath.join(homes_root, keys[-1])
- entry_attrs.setdefault('krbpwdpolicyreference', 'cn=global_policy,cn=%s,cn=kerberos,%s' % (api.env.realm, api.env.basedn))
+ entry_attrs.setdefault('krbpwdpolicyreference',
+ DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'),
+ api.env.basedn))
entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm))
if entry_attrs.get('gidnumber', DNA_MAGIC) == DNA_MAGIC:
@@ -496,6 +500,7 @@ class user_add(LDAPCreate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
config = ldap.get_ipa_config()[1]
# add the user we just created into the default primary group
def_primary_group = config.get('ipadefaultprimarygroup')
@@ -544,6 +549,7 @@ class user_del(LDAPDelete):
msg_summary = _('Deleted user "%(value)s"')
def pre_callback(self, ldap, dn, *keys, **options):
+ assert isinstance(dn, DN)
protected_group_name = u'admins'
result = api.Command.group_show(protected_group_name)
if result['result'].get('member_user', []) == [keys[-1]]:
@@ -562,6 +568,7 @@ class user_mod(LDAPUpdate):
has_output_params = LDAPUpdate.has_output_params + user_output_params
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
+ assert isinstance(dn, DN)
if options.get('rename') is not None:
config = ldap.get_ipa_config()[1]
if 'ipamaxusernamelength' in config:
@@ -592,6 +599,7 @@ class user_mod(LDAPUpdate):
return dn
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
if options.get('random', False):
try:
entry_attrs['randompassword'] = unicode(getattr(context, 'randompassword'))
@@ -621,6 +629,7 @@ class user_find(LDAPSearch):
)
def pre_callback(self, ldap, filter, attrs_list, base_dn, scope, *keys, **options):
+ assert isinstance(base_dn, DN)
if options.get('whoami'):
return ("(&(objectclass=posixaccount)(krbprincipalname=%s))"%\
getattr(context, 'principal'), base_dn, scope)
@@ -651,6 +660,7 @@ class user_show(LDAPRetrieve):
has_output_params = LDAPRetrieve.has_output_params + user_output_params
def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
+ assert isinstance(dn, DN)
convert_nsaccountlock(entry_attrs)
self.obj._convert_manager(entry_attrs, **options)
self.obj.get_password_attributes(ldap, dn, entry_attrs)
@@ -763,7 +773,7 @@ class user_status(LDAPQuery):
# Get list of masters
try:
(masters, truncated) = ldap.find_entries(
- None, ['*'], 'cn=masters,cn=ipa,cn=etc,%s' % api.env.basedn,
+ None, ['*'], DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn),
ldap.SCOPE_ONELEVEL
)
except errors.NotFound:
diff --git a/ipalib/plugins/virtual.py b/ipalib/plugins/virtual.py
index c827d3d9d..8db1a9653 100644
--- a/ipalib/plugins/virtual.py
+++ b/ipalib/plugins/virtual.py
@@ -23,6 +23,7 @@ Base classes for non-LDAP backend plugins.
from ipalib import api
from ipalib import Command
from ipalib import errors
+from ipapython.dn import DN
class VirtualCommand(Command):
"""
@@ -55,7 +56,7 @@ class VirtualCommand(Command):
ldap = self.api.Backend.ldap2
self.log.debug("IPA: virtual verify %s" % operation)
- operationdn = "cn=%s,%s,%s" % (operation, self.api.env.container_virtual, self.api.env.basedn)
+ operationdn = DN(('cn', operation), self.api.env.container_virtual, self.api.env.basedn)
try:
if not ldap.can_write(operationdn, "objectclass"):
diff --git a/ipalib/rpc.py b/ipalib/rpc.py
index 8a6a51088..a22fae505 100644
--- a/ipalib/rpc.py
+++ b/ipalib/rpc.py
@@ -57,6 +57,7 @@ from nss.error import NSPRError
from urllib2 import urlparse
from ipalib.krb_utils import KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN, KRB5KRB_AP_ERR_TKT_EXPIRED, \
KRB5_FCC_PERM, KRB5_FCC_NOFILE, KRB5_CC_FORMAT, KRB5_REALM_CANT_RESOLVE
+from ipapython.dn import DN
COOKIE_NAME = 'ipa_session_cookie:%s'
@@ -83,7 +84,7 @@ def xml_wrap(value):
"""
if type(value) in (list, tuple):
return tuple(xml_wrap(v) for v in value)
- if type(value) is dict:
+ if isinstance(value, dict):
return dict(
(k, xml_wrap(v)) for (k, v) in value.iteritems()
)
@@ -92,6 +93,8 @@ def xml_wrap(value):
if type(value) is Decimal:
# transfer Decimal as a string
return unicode(value)
+ if isinstance(value, DN):
+ return str(value)
assert type(value) in (unicode, int, float, bool, NoneType)
return value
diff --git a/ipalib/session.py b/ipalib/session.py
index 4b783bbcb..87fa44825 100644
--- a/ipalib/session.py
+++ b/ipalib/session.py
@@ -628,7 +628,7 @@ mod_auth_kerb. Everything else remains the same.
default_max_session_duration = 60*60 # number of seconds
-ISO8601_DATETIME_FMT = '%Y-%m-%dT%H:%M:%S' # FIXME jrd, this should be defined elsewhere
+ISO8601_DATETIME_FMT = '%Y-%m-%dT%H:%M:%S' # FIXME, this should be defined elsewhere
def fmt_time(timestamp):
return time.strftime(ISO8601_DATETIME_FMT, time.localtime(timestamp))
diff --git a/ipalib/util.py b/ipalib/util.py
index 039ffb06d..abd50da7d 100644
--- a/ipalib/util.py
+++ b/ipalib/util.py
@@ -33,8 +33,8 @@ from dns.exception import DNSException
from ipalib import errors
from ipalib.text import _
-from ipalib.dn import DN, RDN
from ipapython.ipautil import decode_ssh_pubkey
+from ipapython.dn import DN, RDN
def json_serialize(obj):
@@ -472,10 +472,3 @@ def validate_rdn_param(ugettext, value):
except Exception, e:
return str(e)
return None
-
-def validate_dn_param(ugettext, value):
- try:
- rdn = DN(value)
- except Exception, e:
- return str(e)
- return None
diff --git a/ipalib/x509.py b/ipalib/x509.py
index 1b133adfb..84c1acfcd 100644
--- a/ipalib/x509.py
+++ b/ipalib/x509.py
@@ -42,7 +42,7 @@ from ipalib import api
from ipalib import _
from ipalib import util
from ipalib import errors
-from ipalib.dn import DN
+from ipapython.dn import DN
PEM = 0
DER = 1
diff --git a/ipalib/dn.py b/ipapython/dn.py
index 6f2f7deb5..6cce40e29 100644
--- a/ipalib/dn.py
+++ b/ipapython/dn.py
@@ -17,15 +17,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-from ldap.dn import str2dn, dn2str
-from ldap import DECODING_ERROR
-import codecs
-import sys
-
-utf8_codec = codecs.lookup('utf-8')
-
-__all__ = ['AVA', 'RDN', 'DN']
-
'''
Goal
@@ -396,7 +387,15 @@ if container_dn in dn:
# the respective components of each are pair-wise compared until one
# is discovered to be non-equal. The comparision is case insensitive.
-Concatenation and In-Place Addition:
+Cloning (Object Copy):
+
+All the class types are capable of cloning by passing an object of the
+same type (or subclass) to the constructor. The new object is a copy
+of the object passed as input to the constructor. One place this is
+useful is when you want to coerce between immutable and mutable
+versions in order to modify an object.
+
+Concatenation, In-Place Addition, Insertion:
# DN's and RDN's can be concatenated.
# Return a new DN by appending the RDN's of dn2 to dn1
@@ -409,11 +408,78 @@ dn += RDN('cn', 'Bob')
# Append a DN to an existing DN
dn1 += dn2
+# Prepend a RDN to an existing DN
+dn1.insert(0, RDN('cn', 'Bob'))
+
Finally see the unittest for a more complete set of ways you can
manipulate these objects.
+Mutability
+----------
+
+Python makes a clear distinction between mutable and immutable
+objects. Examples of immutable Python objects are strings, integers
+and floats. Examples of mutable Python objects are lists, dicts, and
+sets. Immutable objects cannot be modified, mutable objects can be
+modified. An object's mutability affects how the object behaves when
+passed to a function or method, this is because it's the object's
+reference which is always passed, thus immutable objects behave as if
+it were "call by value" and mutable objects behave as if it were "call
+by reference" (mutable objects can be modifed inside the
+function/method and that modification will be visible to the
+caller. On object's mutability also affects how an object will behave
+when used as a key in a dict or as a member of a set.
+
+The following discussion applies equally to AVA, RDN and DN object
+class variants.
+
+The AVA, RDN and DN classes have both immutable and mutable
+variants. The base classes (AVA, RDN, DN) are immutable. Each of the
+immutable base classes have a mutable subclass whose name begins with
+'Editable'. Thus the DN class is immutable, instances of that class
+cannot be modified, there is a mutable class EditableDN derived from
+DN whose instances can be modified. The primary difference between the
+immutable and mutable variants is:
+
+* Immutable variants are preferred.
+
+* Mutable variants are exactly identical in behavior to their
+ immutable parent class (except for supporting assignment, etc.)
+
+* Immutable objects that test as equal will be the same as dict keys
+ and set members even if they are different objects. Mutable variants
+ are not hashable and thus cannot be used as a dict key nor inserted
+ into a set.
+
+* Only mutable variants support modification via assignment, insert or
+ in-place addition (e.g. +=).
+
+* In-place addtion (e.g. +=) works for both immutable and mutable
+ variants. The distinction is for immutable objects the lhs is
+ replaced with a new immutable result while a mutable object will be
+ modfied in place and lhs object remains the same object.
+
+It is trival to coerce between an mutable and immutable AVA, RDN and
+DN types. These classes can clone their objects by passing an object
+of the same type to the constructor. For example:
+
+ dn1 = DN(('cn', 'Bob')) # dn1 is immutable
+ dn2 = EditableDN(dn1) # dn2 is mutable copy of dn1,
+ # equal to dn1 until it's modified
+
+ and visa-versa
+
+ dn1 = EditableDN(('cn', 'Bob')) # dn1 is mutable
+ dn2 = DN(dn1) # dn2 is immutable copy of dn1, equal to dn1
+
'''
+from ldap.dn import str2dn, dn2str
+from ldap import DECODING_ERROR
+import sys
+
+__all__ = ['AVA', 'EditableAVA', 'RDN', 'EditableRDN', 'DN', 'EditableDN']
+
def _adjust_indices(start, end, length):
'helper to fixup start/end slice values'
@@ -444,11 +510,11 @@ class AVA(object):
The arg sequence may be:
- 1) With 2 string (or unicode) arguments, the first argument will be the
- attr, the 2nd the value.
+ 1) With 2 arguments, the first argument will be the attr, the 2nd
+ the value. Each argument must be scalar convertable to unicode.
- 2) With a sigle list or tuple argument containing exactly 2 string (or unicode
- members), the first member is the attr and the second is the value.
+ 2) With a sigle list or tuple argument containing exactly 2 items.
+ Each item must be scalar convertable to unicode.
3) With a single string (or unicode) argument, in this case the string will
be interpretted using the DN syntax described in RFC 4514 to yield a AVA
@@ -485,12 +551,15 @@ class AVA(object):
The str method of an AVA returns the string representation in RFC 4514 DN
syntax with proper escaping.
'''
+ is_mutable = False
flags = 0
def __init__(self, *args, **kwds):
if len(args) == 1:
arg = args[0]
- if isinstance(arg, basestring):
+ if isinstance(arg, AVA):
+ ava = (arg.attr, arg.value)
+ elif isinstance(arg, basestring):
try:
rdns = str2dn(arg.encode('utf-8'))
except DECODING_ERROR:
@@ -517,41 +586,48 @@ class AVA(object):
else:
raise TypeError("takes 1 or 2 arguments (%d given)" % (len(args)))
- if not isinstance(attr, basestring):
- raise TypeError("attr must be basestring, got %s instead" % attr.__class__.__name__)
- if not isinstance(value, basestring):
- raise TypeError("value must be basestring, got %s instead" % value.__class__.__name__)
-
- self.attr = attr
- self.value = value
+ self._set_attr(attr)
+ self._set_value(value)
def _get_attr(self):
return self._attr_unicode
def _set_attr(self, new_attr):
- if not isinstance(new_attr, basestring):
- raise TypeError("attr must be basestring, got %s instead" % new_attr.__class__.__name__)
-
- if isinstance(new_attr, unicode):
- self._attr_unicode = new_attr
- else:
- self._attr_unicode = utf8_codec.decode(new_attr)[0]
+ # Scalars only
+ if isinstance(new_attr, (tuple, list)):
+ raise TypeError("attr must be scalar, got %s" % type(new_attr))
+
+ try:
+ if isinstance(new_attr, unicode):
+ self._attr_unicode = new_attr
+ elif isinstance(new_attr, str):
+ self._attr_unicode = new_attr.decode('utf-8')
+ else:
+ self._attr_unicode = unicode(new_attr)
+ except Exception, e:
+ raise ValueError('unable to convert attr "%s" to unicode: %s' % (new_attr, e))
- attr = property(_get_attr, _set_attr)
+ attr = property(_get_attr)
def _get_value(self):
return self._value_unicode
def _set_value(self, new_value):
- if not isinstance(new_value, basestring):
- raise TypeError("value must be basestring, got %s instead" % new_value.__class__.__name__)
-
- if isinstance(new_value, unicode):
- self._value_unicode = new_value
- else:
- self._value_unicode = utf8_codec.decode(new_value)[0]
+ # Scalars only
+ if isinstance(new_value, (tuple, list)):
+ raise TypeError("value must be scalar, got %s" % type(new_value))
+
+ try:
+ if isinstance(new_value, unicode):
+ self._value_unicode = new_value
+ elif isinstance(new_value, str):
+ self._value_unicode = new_value.decode('utf-8')
+ else:
+ self._value_unicode = unicode(new_value)
+ except Exception, e:
+ raise ValueError('unable to convert value "%s" to unicode: %s' % (new_value, e))
- value = property(_get_value, _set_value)
+ value = property(_get_value)
def _to_openldap(self):
return [[(self._attr_unicode.encode('utf-8'), self._value_unicode.encode('utf-8'), self.flags)]]
@@ -559,6 +635,9 @@ class AVA(object):
def __str__(self):
return dn2str(self._to_openldap())
+ def __repr__(self):
+ return "%s.%s('%s')" % (self.__module__, self.__class__.__name__, self.__str__())
+
def __getitem__(self, key):
if isinstance(key, basestring):
if key == self._attr_unicode:
@@ -568,6 +647,10 @@ class AVA(object):
raise TypeError("unsupported type for AVA indexing, must be basestring; not %s" % \
(key.__class__.__name__))
+ def __hash__(self):
+ # Hash is computed from AVA's string representation because it's immutable
+ return hash(str(self))
+
def __eq__(self, other):
'''
The attr comparison is case insensitive because attr is
@@ -581,16 +664,29 @@ class AVA(object):
atribute type (OID 2.5.4.41) whose EQUALITY MATCH RULE is
caseIgnoreMatch.
'''
- if not isinstance(other, self.__class__):
- raise TypeError("expected AVA but got %s" % (other.__class__.__name__))
+ # Try coercing string to AVA, if successful compare to coerced object
+ if isinstance(other, basestring):
+ try:
+ other_ava = AVA(other)
+ return self.__eq__(other_ava)
+ except Exception:
+ return False
+ # If it's not an AVA it can't be equal
+ if not isinstance(other, AVA):
+ return False
+
+ # Perform comparision between objects of same type
return self._attr_unicode.lower() == other.attr.lower() and \
self._value_unicode.lower() == other.value.lower()
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __cmp__(self, other):
'comparision is case insensitive, see __eq__ doc for explanation'
- if not isinstance(other, self.__class__):
+ if not isinstance(other, AVA):
raise TypeError("expected AVA but got %s" % (other.__class__.__name__))
result = cmp(self._attr_unicode.lower(), other.attr.lower())
@@ -599,9 +695,28 @@ class AVA(object):
result = cmp(self._value_unicode.lower(), other.value.lower())
return result
+class EditableAVA(AVA):
+ '''
+ Exactly identical to the AVA class except
+
+ * Hash value is based on object identity, not object
+ value. Objects that test as equal will be non-unique when
+ used as a dict key or member of a set.
+
+ * The attr and value properties may be modified after object creation.
+
+ '''
+ is_mutable = True
+ __hash__ = None
+
+ attr = property(AVA._get_attr, AVA._set_attr)
+ value = property(AVA._get_value, AVA._set_value)
+
+
+
class RDN(object):
'''
- RDN(arg0, ..., first_key_match=True)
+ RDN(arg0, ...)
An RDN is a LDAP Relative Distinguished Name. RDN's are members of DN's
(Distinguished Name). An RDN contains 1 or more AVA's. If the RDN contains
@@ -669,12 +784,7 @@ class RDN(object):
WARNING: When indexing by attr (e.g. rdn['cn']) there is a possibility more
than one AVA has the same attr name as the index key. The default behavior
is to return the value of the first AVA whose attr matches the index
- key. This behavior can be modified by setting the first_key_match property
- to false in the RDN object. If first_key_match is False a list of all values
- will be returned instead. The first_key_match behavior is the default and is
- useful because duplicate attr names in multi-valued RDN's are rare. We seek
- the most useful common case for programmer friendliness, but you should be
- aware of the caveat.
+ key.
RDN objects support the AVA attr and value properties as another programmer
convenience because the vast majority of RDN's are single valued. The attr
@@ -710,20 +820,21 @@ class RDN(object):
syntax with proper escaping.
'''
+ is_mutable = False
flags = 0
+ AVA_type = AVA
def __init__(self, *args, **kwds):
- self.first_key_match = kwds.get('first_key_match', True)
self.avas = self._avas_from_sequence(args)
self.avas.sort()
def _ava_from_value(self, value):
if isinstance(value, AVA):
- return AVA(value.attr, value.value)
+ return self.AVA_type(value.attr, value.value)
elif isinstance(value, RDN):
avas = []
for ava in value.avas:
- avas.append(AVA(ava.attr, ava.value))
+ avas.append(self.AVA_type(ava.attr, ava.value))
if len(avas) == 1:
return avas[0]
else:
@@ -735,18 +846,18 @@ class RDN(object):
raise ValueError("multiple RDN's specified by \"%s\"" % (value))
rdn = rdns[0]
if len(rdn) == 1:
- return AVA(rdn[0][0], rdn[0][1])
+ return self.AVA_type(rdn[0][0], rdn[0][1])
else:
avas = []
for ava_tuple in rdn:
- avas.append(AVA(ava_tuple[0], ava_tuple[1]))
+ avas.append(self.AVA_type(ava_tuple[0], ava_tuple[1]))
return avas
except DECODING_ERROR:
raise ValueError("malformed RDN string = \"%s\"" % value)
elif isinstance(value, (tuple, list)):
if len(value) != 2:
raise ValueError("tuple or list must be 2-valued, not \"%s\"" % (value))
- return AVA(value)
+ return self.AVA_type(value)
else:
raise TypeError("must be str,unicode,tuple, or AVA, got %s instead" % \
value.__class__.__name__)
@@ -769,6 +880,9 @@ class RDN(object):
def __str__(self):
return dn2str(self._to_openldap())
+ def __repr__(self):
+ return "%s.%s('%s')" % (self.__module__, self.__class__.__name__, self.__str__())
+
def _next(self):
for ava in self.avas:
yield ava
@@ -783,51 +897,13 @@ class RDN(object):
if isinstance(key, (int, long, slice)):
return self.avas[key]
elif isinstance(key, basestring):
- if self.first_key_match:
- for ava in self.avas:
- if key == ava.attr:
- return ava.value
- raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
- else:
- avas = []
- for ava in self.avas:
- if key == ava.attr:
- avas.append(ava.value)
- if len(avas) > 0:
- return avas
- raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
- else:
- raise TypeError("unsupported type for RDN indexing, must be int, basestring or slice; not %s" % \
- (key.__class__.__name__))
-
- def __setitem__(self, key, value):
- if isinstance(key, (int, long)):
- new_ava = self._ava_from_value(value)
- if isinstance(new_ava, list):
- raise TypeError("cannot assign multiple AVA's to single entry")
- self.avas[key] = new_ava
- elif isinstance(key, slice):
- avas = self._avas_from_sequence(value)
- self.avas[key] = avas
- elif isinstance(key, basestring):
- new_ava = self._ava_from_value(value)
- if isinstance(new_ava, list):
- raise TypeError("cannot assign multiple AVA's to single entry")
- found = False
- i = 0
- while i < len(self.avas):
- if key == self.avas[i].attr:
- found = True
- self.avas[i] = new_ava
- if self.first_key_match:
- break
- i += 1
- if not found:
- raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
+ for ava in self.avas:
+ if key == ava.attr:
+ return ava.value
+ raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
else:
raise TypeError("unsupported type for RDN indexing, must be int, basestring or slice; not %s" % \
(key.__class__.__name__))
- self.avas.sort()
def _get_attr(self):
if len(self.avas) == 0:
@@ -838,12 +914,9 @@ class RDN(object):
if len(self.avas) == 0:
raise IndexError("No AVA's in this RDN")
- if not isinstance(new_attr, basestring):
- raise TypeError("attr must be basestring, got %s instead" % new_attr.__class__.__name__)
-
self.avas[0].attr = new_attr
- attr = property(_get_attr, _set_attr)
+ attr = property(_get_attr)
def _get_value(self):
if len(self.avas) == 0:
@@ -854,21 +927,35 @@ class RDN(object):
if len(self.avas) == 0:
raise IndexError("No AVA's in this RDN")
- if not isinstance(new_value, basestring):
- raise TypeError("value must be basestring, got %s instead" % new_value.__class__.__name__)
-
self.avas[0].value = new_value
- value = property(_get_value, _set_value)
+ value = property(_get_value)
+
+ def __hash__(self):
+ # Hash is computed from RDN's string representation because it's immutable
+ return hash(str(self))
def __eq__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("expected RDN but got %s" % (other.__class__.__name__))
+ # Try coercing string to RDN, if successful compare to coerced object
+ if isinstance(other, basestring):
+ try:
+ other_rdn = RDN(other)
+ return self.__eq__(other_rdn)
+ except Exception:
+ return False
+
+ # If it's not an RDN it can't be equal
+ if not isinstance(other, RDN):
+ return False
+ # Perform comparision between objects of same type
return self.avas == other.avas
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __cmp__(self, other):
- if not isinstance(other, self.__class__):
+ if not isinstance(other, RDN):
raise TypeError("expected RDN but got %s" % (other.__class__.__name__))
result = cmp(len(self), len(other))
@@ -883,32 +970,85 @@ class RDN(object):
return 0
def __add__(self, other):
- result = RDN(self, first_key_match=self.first_key_match)
+ result = self.__class__(self)
if isinstance(other, RDN):
for ava in other.avas:
- result.avas.append(AVA(ava.attr, ava.value))
+ result.avas.append(self.AVA_type(ava.attr, ava.value))
elif isinstance(other, AVA):
- result.avas.append(AVA(other.attr, other.value))
+ result.avas.append(self.AVA_type(other.attr, other.value))
elif isinstance(other, basestring):
- rdn = RDN(other)
+ rdn = self.__class__(other)
for ava in rdn.avas:
- result.avas.append(AVA(ava.attr, ava.value))
+ result.avas.append(self.AVA_type(ava.attr, ava.value))
else:
raise TypeError("expected RDN, AVA or basestring but got %s" % (other.__class__.__name__))
result.avas.sort()
return result
+class EditableRDN(RDN):
+ '''
+ Exactly identical to the RDN class except
+
+ * Hash value is based on object identity, not object
+ value. Objects that test as equal will be non-unique when
+ used as a dict key or member of a set.
+
+ * AVA components may be assigned via assignment statements.
+
+ * In-place addition modifes the lhs object.
+
+ * The attr and value properties may be modified after object creation.
+ '''
+
+ is_mutable = True
+ __hash__ = None
+ AVA_type = EditableAVA
+
+ def __setitem__(self, key, value):
+ if isinstance(key, (int, long)):
+ new_ava = self._ava_from_value(value)
+ if isinstance(new_ava, list):
+ raise TypeError("cannot assign multiple AVA's to single entry")
+ self.avas[key] = new_ava
+ elif isinstance(key, slice):
+ avas = self._avas_from_sequence(value)
+ self.avas[key] = avas
+ elif isinstance(key, basestring):
+ new_ava = self._ava_from_value(value)
+ if isinstance(new_ava, list):
+ raise TypeError("cannot assign multiple AVA's to single entry")
+ found = False
+ i = 0
+ while i < len(self.avas):
+ if key == self.avas[i].attr:
+ found = True
+ self.avas[i] = new_ava
+ break
+ i += 1
+ if not found:
+ raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
+ else:
+ raise TypeError("unsupported type for RDN indexing, must be int, basestring or slice; not %s" % \
+ (key.__class__.__name__))
+ self.avas.sort()
+
+ attr = property(RDN._get_attr, RDN._set_attr)
+ value = property(RDN._get_value, RDN._set_value)
+
+
def __iadd__(self, other):
+ # If __iadd__ is not available Python will emulate += by
+ # replacing the lhs object with the result of __add__ (if available).
if isinstance(other, RDN):
for ava in other.avas:
- self.avas.append(AVA(ava.attr, ava.value))
+ self.avas.append(self.AVA_type(ava.attr, ava.value))
elif isinstance(other, AVA):
- self.avas.append(AVA(other.attr, other.value))
+ self.avas.append(self.AVA_type(other.attr, other.value))
elif isinstance(other, basestring):
- rdn = RDN(other)
+ rdn = self.__class__(other)
for ava in rdn.avas:
- self.avas.append(AVA(ava.attr, ava.value))
+ self.avas.append(self.AVA_type(ava.attr, ava.value))
else:
raise TypeError("expected RDN, AVA or basestring but got %s" % (other.__class__.__name__))
@@ -917,7 +1057,7 @@ class RDN(object):
class DN(object):
'''
- DN(arg0, ..., first_key_match=True)
+ DN(arg0, ...)
A DN is a LDAP Distinguished Name. A DN is an ordered sequence of RDN's.
@@ -988,15 +1128,21 @@ class DN(object):
for ava in rdn: # iterate over each RDN
rdn[:] # a slice, in this case a copy of each RDN
- WARNING: When indexing by attr (e.g. rdn['cn']) there is a possibility more
- than one RDN has the same attr name as the index key. The default behavior
- is to return the value of the first RDN whose attr matches the index
- key. This behavior can be modified by setting the first_key_match property
- to false in the RDN object. If first_key_match is False a list of all values
- will be returned instead. The first_key_match behavior is the default and is
- useful because typical usage is to seek the first matching RDN. We seek
- the most useful common case for programmer friendliness, but you should be
- aware of the caveat.
+ WARNING: When indexing by attr (e.g. dn['cn']) there is a
+ possibility more than one RDN has the same attr name as the index
+ key. The default behavior is to return the value of the first RDN
+ whose attr matches the index key. If it's important the attr
+ belong to a specific RDN (e.g. the first) then this is the
+ suggested construct:
+
+ try:
+ cn = dn[0]['cn']
+ except (IndexError, KeyError):
+ raise ValueError("dn '%s' missing expected cn as first attribute" % dn)
+
+ The IndexError catches a DN which does not have the expected
+ number of RDN's and the KeyError catches the case where the
+ indexed RDN does not have the expected attr.
DN object support slices.
@@ -1056,20 +1202,21 @@ class DN(object):
syntax with proper escaping.
'''
+ is_mutable = False
flags = 0
+ AVA_type = AVA
+ RDN_type = RDN
def __init__(self, *args, **kwds):
- self.first_key_match = kwds.get('first_key_match', True)
- self.first_key_match = True
self.rdns = self._rdns_from_sequence(args)
def _rdn_from_value(self, value):
if isinstance(value, RDN):
- return RDN(value, first_key_match=self.first_key_match)
+ return self.RDN_type(value)
elif isinstance(value, DN):
rdns = []
for rdn in value.rdns:
- rdns.append(RDN(rdn, first_key_match=self.first_key_match))
+ rdns.append(self.RDN_type(rdn))
if len(rdns) == 1:
return rdns[0]
else:
@@ -1081,8 +1228,8 @@ class DN(object):
for rdn_list in dn_list:
avas = []
for ava_tuple in rdn_list:
- avas.append(AVA(ava_tuple[0], ava_tuple[1]))
- rdn = RDN(*avas, first_key_match=self.first_key_match)
+ avas.append(self.AVA_type(ava_tuple[0], ava_tuple[1]))
+ rdn = self.RDN_type(*avas)
rdns.append(rdn)
except DECODING_ERROR:
raise ValueError("malformed RDN string = \"%s\"" % value)
@@ -1093,7 +1240,7 @@ class DN(object):
elif isinstance(value, (tuple, list)):
if len(value) != 2:
raise ValueError("tuple or list must be 2-valued, not \"%s\"" % (value))
- rdn = RDN(value, first_key_match=self.first_key_match)
+ rdn = self.RDN_type(value)
return rdn
else:
raise TypeError("must be str,unicode,tuple, or RDN, got %s instead" % \
@@ -1116,6 +1263,9 @@ class DN(object):
def __str__(self):
return dn2str(self._to_openldap())
+ def __repr__(self):
+ return "%s.%s('%s')" % (self.__module__, self.__class__.__name__, self.__str__())
+
def _next(self):
for rdn in self.rdns:
yield rdn
@@ -1130,58 +1280,39 @@ class DN(object):
if isinstance(key, (int, long, slice)):
return self.rdns[key]
elif isinstance(key, basestring):
- if self.first_key_match:
- for rdn in self.rdns:
- if key == rdn.attr:
- return rdn.value
- raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
- else:
- rdns = []
- for rdn in self.rdns:
- if key == rdn.attr:
- rdns.append(rdn.value)
- if len(rdns) > 0:
- return rdns
- raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
+ for rdn in self.rdns:
+ if key == rdn.attr:
+ return rdn.value
+ raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
else:
raise TypeError("unsupported type for DN indexing, must be int, basestring or slice; not %s" % \
(key.__class__.__name__))
- def __setitem__(self, key, value):
- if isinstance(key, (int, long)):
- new_rdn = self._rdn_from_value(value)
- if isinstance(new_rdn, list):
- raise TypeError("cannot assign multiple RDN's to single entry")
- self.rdns[key] = new_rdn
- elif isinstance(key, slice):
- rdns = self._rdns_from_sequence(value)
- self.rdns[key] = rdns
- elif isinstance(key, basestring):
- new_rdn = self._rdn_from_value(value)
- if isinstance(new_rdn, list):
- raise TypeError("cannot assign multiple values to single entry")
- found = False
- i = 0
- while i < len(self.rdns):
- if key == self.rdns[i].attr:
- found = True
- self.rdns[i] = new_rdn
- if self.first_key_match: break
- i += 1
- if not found:
- raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
- else:
- raise TypeError("unsupported type for DN indexing, must be int, basestring or slice; not %s" % \
- (key.__class__.__name__))
+ def __hash__(self):
+ # Hash is computed from DN's string representation because it's immutable
+ return hash(str(self))
def __eq__(self, other):
- if not isinstance(other, self.__class__):
- raise TypeError("expected DN but got %s" % (other.__class__.__name__))
+ # Try coercing string to DN, if successful compare to coerced object
+ if isinstance(other, basestring):
+ try:
+ other_dn = DN(other)
+ return self.__eq__(other_dn)
+ except Exception:
+ return False
+
+ # If it's not an DN it can't be equal
+ if not isinstance(other, DN):
+ return False
+ # Perform comparision between objects of same type
return self.rdns == other.rdns
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __cmp__(self, other):
- if not isinstance(other, self.__class__):
+ if not isinstance(other, DN):
raise TypeError("expected DN but got %s" % (other.__class__.__name__))
result = cmp(len(self), len(other))
@@ -1201,14 +1332,14 @@ class DN(object):
return 0
def __add__(self, other):
- result = DN(self, first_key_match=self.first_key_match)
- if isinstance(other, self.__class__):
+ result = self.__class__(self)
+ if isinstance(other, DN):
for rdn in other.rdns:
- result.rdns.append(RDN(rdn, first_key_match=self.first_key_match))
+ result.rdns.append(self.RDN_type(rdn))
elif isinstance(other, RDN):
- result.rdns.append(RDN(other, first_key_match=self.first_key_match))
+ result.rdns.append(self.RDN_type(other))
elif isinstance(other, basestring):
- dn = DN(other, first_key_match=self.first_key_match)
+ dn = self.__class__(other)
for rdn in dn.rdns:
result.rdns.append(rdn)
else:
@@ -1216,34 +1347,6 @@ class DN(object):
return result
- def __iadd__(self, other):
- if isinstance(other, DN):
- for rdn in other.rdns:
- self.rdns.append(RDN(rdn, first_key_match=self.first_key_match))
- elif isinstance(other, RDN):
- self.rdns.append(RDN(other, first_key_match=self.first_key_match))
- elif isinstance(other, basestring):
- dn = DN(other, first_key_match=self.first_key_match)
- self.__iadd__(dn)
- else:
- raise TypeError("expected DN, RDN or basestring but got %s" % (other.__class__.__name__))
-
- return self
-
- def insert(self, i, x):
- '''
- x must be a 2-value tuple or list promotable to an RDN object,
- or a RDN object.
-
- dn.insert(i, x) is the same as s[i:i] = [x]
-
- When a negative index is passed as the first parameter to the
- insert() method, the list length is added, as for slice
- indices. If it is still negative, it is truncated to zero, as
- for slice indices.
- '''
- self.rdns.insert(i, self._rdn_from_value(x))
-
# The implementation of startswith, endswith, tailmatch, adjust_indices
# was based on the Python's stringobject.c implementation
@@ -1332,6 +1435,209 @@ class DN(object):
raise TypeError("expected DN or RDN but got %s" % (other.__class__.__name__))
+ def find(self, pattern, start=None, end=None):
+ '''
+ Return the lowest index in the DN where pattern DN (or RDN) is found,
+ such that pattern is contained in the range [start, end]. Optional
+ arguments start and end are interpreted as in slice notation. Return
+ -1 if pattern is not found.
+ '''
+
+ if isinstance(pattern, DN):
+ pat_len = len(pattern)
+ elif isinstance(pattern, RDN):
+ pat_len = 1
+ else:
+ raise TypeError("expected DN or RDN but got %s" % (pattern.__class__.__name__))
+
+ self_len = len(self)
+
+ if start is None:
+ start = 0
+ if end is None:
+ end = self_len
+
+ start, end = _adjust_indices(start, end, self_len)
+
+ i = start
+ stop = max(start, end - pat_len)
+ if isinstance(pattern, DN):
+ while i <= stop:
+ result = self._cmp_sequence(pattern, i, pat_len)
+ if result == 0:
+ return i
+ i += 1
+ return -1
+ else:
+ while i <= stop:
+ if self.rdns[i] == pattern:
+ return i
+ i += 1
+ return -1
+
+ def index(self, pattern, start=None, end=None):
+ '''
+ Like find() but raise ValueError when the pattern is not found.
+ '''
+
+ i = self.find(pattern, start, end)
+ if i == -1:
+ raise ValueError("pattern not found")
+ return i
+
+ def rfind(self, pattern, start=None, end=None):
+ '''
+ Return the highest index in the DN where pattern DN (or RDN) is found,
+ such that pattern is contained in the range [start, end]. Optional
+ arguments start and end are interpreted as in slice notation. Return
+ -1 if pattern is not found.
+ '''
+
+ if isinstance(pattern, DN):
+ pat_len = len(pattern)
+ elif isinstance(pattern, RDN):
+ pat_len = 1
+ else:
+ raise TypeError("expected DN or RDN but got %s" % (pattern.__class__.__name__))
+
+ self_len = len(self)
+
+ if start is None:
+ start = 0
+ if end is None:
+ end = self_len
+
+ start, end = _adjust_indices(start, end, self_len)
+
+ i = max(start, min(end, self_len - pat_len))
+ stop = start
+ if isinstance(pattern, DN):
+ while i >= stop:
+ result = self._cmp_sequence(pattern, i, pat_len)
+ if result == 0:
+ return i
+ i -= 1
+ return -1
+ else:
+ while i >= stop:
+ if self.rdns[i] == pattern:
+ return i
+ i -= 1
+ return -1
+
+ def rindex(self, pattern, start=None, end=None):
+ '''
+ Like rfind() but raise ValueError when the pattern is not found.
+ '''
+
+ i = self.rfind(pattern, start, end)
+ if i == -1:
+ raise ValueError("pattern not found")
+ return i
+
+class EditableDN(DN):
+ '''
+ Exactly identical to the DN class except
+
+ * Hash value is based on object identity, not object
+ value. Objects that test as equal will be non-unique when
+ used as a dict key or member of a set.
+
+ * RDN components may be assigned via assignment statements.
+
+ * RDN components may be inserted.
+
+ * In-place addition modifes the lhs object.
+
+ '''
+
+ is_mutable = True
+ __hash__ = None
+ AVA_type = EditableAVA
+ RDN_type = EditableRDN
+
+ def __setitem__(self, key, value):
+ if isinstance(key, (int, long)):
+ new_rdn = self._rdn_from_value(value)
+ if isinstance(new_rdn, list):
+ raise TypeError("cannot assign multiple RDN's to single entry")
+ self.rdns[key] = new_rdn
+ elif isinstance(key, slice):
+ rdns = self._rdns_from_sequence(value)
+ self.rdns[key] = rdns
+ elif isinstance(key, basestring):
+ new_rdn = self._rdn_from_value(value)
+ if isinstance(new_rdn, list):
+ raise TypeError("cannot assign multiple values to single entry")
+ found = False
+ i = 0
+ while i < len(self.rdns):
+ if key == self.rdns[i].attr:
+ found = True
+ self.rdns[i] = new_rdn
+ break
+ i += 1
+ if not found:
+ raise KeyError("\"%s\" not found in %s" % (key, self.__str__()))
+ else:
+ raise TypeError("unsupported type for DN indexing, must be int, basestring or slice; not %s" % \
+ (key.__class__.__name__))
+
+ def __iadd__(self, other):
+ # If __iadd__ is not available Python will emulate += by
+ # replacing the lhs object with the result of __add__ (if available).
+ if isinstance(other, DN):
+ for rdn in other.rdns:
+ self.rdns.append(self.RDN_type(rdn))
+ elif isinstance(other, RDN):
+ self.rdns.append(self.RDN_type(other))
+ elif isinstance(other, basestring):
+ dn = self.__class__(other)
+ self.__iadd__(dn)
+ else:
+ raise TypeError("expected DN, RDN or basestring but got %s" % (other.__class__.__name__))
+
+ return self
+
+ def insert(self, i, x):
+ '''
+ x must be a 2-value tuple or list promotable to an RDN object,
+ or a RDN object.
+
+ dn.insert(i, x) is the same as s[i:i] = [x]
+
+ When a negative index is passed as the first parameter to the
+ insert() method, the list length is added, as for slice
+ indices. If it is still negative, it is truncated to zero, as
+ for slice indices.
+ '''
+
+ self.rdns.insert(i, self._rdn_from_value(x))
+
+ def replace(self, old, new, count=sys.maxsize):
+ '''
+ Replace all occurrences of old DN (or RDN) with new DN (or
+ RDN). If the optional argument count is given, only the first
+ count occurrences are replaced.
+
+ Returns the number of replacements made.
+ '''
+
+ if not isinstance(old, (DN, RDN)):
+ raise TypeError("old must be DN or RDN but got %s" % (old.__class__.__name__))
+ if not isinstance(new, (DN, RDN)):
+ raise TypeError("new must be DN or RDN but got %s" % (new.__class__.__name__))
+ start = 0
+ pat_len = len(old)
+ n_replaced = 0
+ while n_replaced < count:
+ index = self.find(old, start)
+ if index < 0:
+ return n_replaced
+ self[index : index+pat_len] = new
+ n_replaced += 1
+ start = index + pat_len
+ return n_replaced
diff --git a/ipapython/entity.py b/ipapython/entity.py
index 27d517879..cb97b9913 100644
--- a/ipapython/entity.py
+++ b/ipapython/entity.py
@@ -18,6 +18,7 @@
import copy
from ipapython import ipautil
+from ipapython.dn import DN
def copy_CIDict(x):
"""Do a deep copy of a CIDict"""
@@ -45,19 +46,25 @@ class Entity:
if isinstance(entrydata,tuple):
self.dn = entrydata[0]
self.data = ipautil.CIDict(entrydata[1])
- elif isinstance(entrydata,str) or isinstance(entrydata,unicode):
+ elif isinstance(entrydata, DN):
self.dn = entrydata
self.data = ipautil.CIDict()
+ elif isinstance(entrydata, basestring):
+ self.dn = DN(entrydata)
+ self.data = ipautil.CIDict()
elif isinstance(entrydata,dict):
self.dn = entrydata['dn']
del entrydata['dn']
self.data = ipautil.CIDict(entrydata)
else:
- self.dn = ''
+ self.dn = DN()
self.data = ipautil.CIDict()
+ assert isinstance(self.dn, DN)
self.orig_data = ipautil.CIDict(copy_CIDict(self.data))
+ dn = ipautil.dn_attribute_property('_dn')
+
def __nonzero__(self):
"""This allows us to do tests like if entry: returns false if there is no data,
true otherwise"""
@@ -67,23 +74,8 @@ class Entity:
"""Return True if this entry has an attribute named name, False otherwise"""
return self.data and self.data.has_key(name)
- def __setattr__(self,name,value):
- """One should use setValue() or setValues() to set values except for
- dn and data which are special."""
- if name != 'dn' and name != 'data' and name != 'orig_data':
- raise KeyError, 'use setValue() or setValues()'
- else:
- self.__dict__[name] = value
-
- def __getattr__(self,name):
- """If name is the name of an LDAP attribute, return the first value for that
- attribute - equivalent to getValue - this allows the use of
- entry.cn
- instead of
- entry.getValue('cn')
- This also allows us to return None if an attribute is not found rather than
- throwing an exception"""
- return self.getValue(name)
+ def __str__(self):
+ return "dn: %s data: %s" % (self.dn, self.data)
def getValues(self,name):
"""Get the list (array) of values for the attribute named name"""
@@ -150,6 +142,7 @@ class Entity:
def toDict(self):
"""Convert the attrs and values to a dict. The dict is keyed on the
attribute name. The value is either single value or a list of values."""
+ assert isinstance(self.dn, DN)
result = ipautil.CIDict(self.data)
result['dn'] = self.dn
return result
@@ -160,6 +153,7 @@ class Entity:
def origDataDict(self):
"""Returns a dict of the original values of the user. Used for updates."""
+ assert isinstance(self.dn, DN)
result = ipautil.CIDict(self.orig_data)
result['dn'] = self.dn
return result
diff --git a/ipapython/ipa_log_manager.py b/ipapython/ipa_log_manager.py
index 8af0f79a7..f2cd4d3a1 100644
--- a/ipapython/ipa_log_manager.py
+++ b/ipapython/ipa_log_manager.py
@@ -101,10 +101,10 @@ class IPALogManager(LogManager):
in the Env config must begin with "log_logger_level\_" and then be
followed by a symbolic or numeric log level, for example::
- log_logger_level_debug = ipalib\.dn\..*
+ log_logger_level_debug = ipapython\.dn\..*
log_logger_level_35 = ipalib\.plugins\.dogtag
- The first line says any logger belonging to the ipalib.dn module
+ The first line says any logger belonging to the ipapython.dn module
will have it's level configured to debug.
The second line say the ipa.plugins.dogtag logger will be
diff --git a/ipapython/ipautil.py b/ipapython/ipautil.py
index 1b0597763..a212aa6ef 100644
--- a/ipapython/ipautil.py
+++ b/ipapython/ipautil.py
@@ -49,6 +49,7 @@ from dns.exception import DNSException
from ipapython.ipa_log_manager import *
from ipapython import ipavalidate
from ipapython import config
+from ipapython.dn import DN
try:
from subprocess import CalledProcessError
@@ -200,10 +201,16 @@ def format_netloc(host, port=None):
return '%s:%s' % (host, str(port))
def realm_to_suffix(realm_name):
- """Convert a kerberos realm into the IPA suffix."""
+ 'Convert a kerberos realm to a IPA suffix.'
s = realm_name.split(".")
- terms = ["dc=" + x.lower() for x in s]
- return ",".join(terms)
+ suffix_dn = DN(*[('dc', x.lower()) for x in s])
+ return suffix_dn
+
+def suffix_to_realm(suffix_dn):
+ 'Convert a IPA suffix to a kerberos realm.'
+ assert isinstance(suffix_dn, DN)
+ realm = '.'.join([x.value for x in suffix_dn])
+ return realm
def template_str(txt, vars):
val = string.Template(txt).substitute(vars)
@@ -1111,3 +1118,33 @@ def kinit_hostprincipal(keytab, ccachedir, principal):
return ccache_file
except krbV.Krb5Error, e:
raise StandardError('Error initializing principal %s in %s: %s' % (principal, keytab, str(e)))
+
+def dn_attribute_property(private_name):
+ '''
+ Create a property for a dn attribute which assures the attribute
+ is a DN or None. If the value is not None the setter converts it to
+ a DN. The getter assures it's either None or a DN instance.
+
+ The private_name parameter is the class internal attribute the property
+ shadows.
+
+ For example if a class has an attribute called base_dn, then:
+
+ base_dn = dn_attribute_property('_base_dn')
+
+ Thus the class with have an attriubte called base_dn which can only
+ ever be None or a DN instance. The actual value is stored in _base_dn.
+ '''
+
+ def setter(self, value):
+ if value is not None:
+ value = DN(value)
+ setattr(self, private_name, value)
+
+ def getter(self):
+ value = getattr(self, private_name)
+ if value is not None:
+ assert isinstance(value, DN)
+ return value
+
+ return property(getter, setter)
diff --git a/ipaserver/conn.py b/ipaserver/conn.py
deleted file mode 100644
index 070a6adc8..000000000
--- a/ipaserver/conn.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Authors: Rob Crittenden <rcritten@redhat.com>
-#
-# Copyright (C) 2008 Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-import krbV
-import ldap
-import ldap.dn
-import ipaldap
-
-class IPAConn:
- def __init__(self, host, port, krbccache, debug=None):
- self._conn = None
-
- # Save the arguments
- self._host = host
- self._port = port
- self._krbccache = krbccache
- self._debug = debug
-
- self._ctx = krbV.default_context()
-
- ccache = krbV.CCache(name=krbccache, context=self._ctx)
- cprinc = ccache.principal()
-
- self._conn = ipaldap.IPAdmin(host,port,None,None,None,debug)
-
- # This will bind the connection
- try:
- self._conn.set_krbccache(krbccache, cprinc.name)
- except ldap.UNWILLING_TO_PERFORM, e:
- raise e
- except Exception, e:
- raise e
-
- def __del__(self):
- # take no chances on unreleased connections
- self.releaseConn()
-
- def getConn(self):
- return self._conn
-
- def releaseConn(self):
- if self._conn is None:
- return
-
- self._conn.unbind_s()
- self._conn = None
-
- return
-
-if __name__ == "__main__":
- ipaconn = IPAConn("localhost", 389, "FILE:/tmp/krb5cc_500")
- x = ipaconn.getConn().getEntry("dc=example,dc=com", ldap.SCOPE_SUBTREE, "uid=admin", ["cn"])
- print "%s" % x
diff --git a/ipaserver/dcerpc.py b/ipaserver/dcerpc.py
index 982e12b31..f7abf62e4 100644
--- a/ipaserver/dcerpc.py
+++ b/ipaserver/dcerpc.py
@@ -101,7 +101,7 @@ class DomainValidator(object):
def is_configured(self):
cn_trust_local = DN(('cn', self.api.env.domain), self.api.env.container_cifsdomains, self.api.env.basedn)
try:
- (dn, entry_attrs) = self.ldap.get_entry(unicode(cn_trust_local), [self.ATTR_FLATNAME, self.ATTR_SID])
+ (dn, entry_attrs) = self.ldap.get_entry(cn_trust_local, [self.ATTR_FLATNAME, self.ATTR_SID])
self.flatname = entry_attrs[self.ATTR_FLATNAME][0]
self.sid = entry_attrs[self.ATTR_SID][0]
self.dn = dn
@@ -115,7 +115,7 @@ class DomainValidator(object):
try:
search_kw = {'objectClass': 'ipaNTTrustedDomain'}
filter = self.ldap.make_filter(search_kw, rules=self.ldap.MATCH_ALL)
- (entries, truncated) = self.ldap.find_entries(filter=filter, base_dn=unicode(cn_trust),
+ (entries, truncated) = self.ldap.find_entries(filter=filter, base_dn=cn_trust,
attrs_list=[self.ATTR_TRUSTED_SID, 'dn'])
return entries
@@ -447,5 +447,3 @@ class TrustDomainJoins(object):
self.__populate_remote_domain(realm, realm_server, realm_passwd=None)
self.local_domain.establish_trust(self.remote_domain, trustdom_passwd)
return dict(local=self.local_domain, remote=self.remote_domain)
-
-
diff --git a/ipaserver/install/adtrustinstance.py b/ipaserver/install/adtrustinstance.py
index 9dcbec2d6..078c54dbe 100644
--- a/ipaserver/install/adtrustinstance.py
+++ b/ipaserver/install/adtrustinstance.py
@@ -29,11 +29,12 @@ from ipaserver.install.dsinstance import realm_to_serverid
from ipaserver.install.bindinstance import get_rr, add_rr, del_rr, \
dns_zone_exists
from ipalib import errors, api
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipapython import sysrestore
from ipapython import ipautil
from ipapython.ipa_log_manager import *
from ipapython import services as ipaservices
+from ipapython.dn import DN
import string
import struct
@@ -103,7 +104,7 @@ class ADTRUSTInstance(service.Service):
self.netbios_name = None
self.no_msdcs = None
self.smbd_user = None
- self.suffix = None
+ self.suffix = DN()
self.ldapi_socket = None
self.smb_conf = None
self.smb_dn = None
@@ -129,11 +130,10 @@ class ADTRUSTInstance(service.Service):
return "S-1-5-21-%d-%d-%d" % (sub_ids[0], sub_ids[1], sub_ids[2])
def __add_admin_sids(self):
- admin_dn = str(DN(('uid', 'admin'), api.env.container_user,
- self.suffix))
- admin_group_dn = str(DN(('cn', 'admins'), api.env.container_group,
- self.suffix))
-
+ admin_dn = DN(('uid', 'admin'), api.env.container_user,
+ self.suffix)
+ admin_group_dn = DN(('cn', 'admins'), api.env.container_group,
+ self.suffix)
try:
dom_entry = self.admin_conn.getEntry(self.smb_dom_dn, \
ldap.SCOPE_BASE)
@@ -186,10 +186,9 @@ class ADTRUSTInstance(service.Service):
"""
try:
- res = self.admin_conn.search_s(str(DN(api.env.container_ranges,
- self.suffix)),
- ldap.SCOPE_ONELEVEL,
- "(objectclass=ipaDomainIDRange)")
+ res = self.admin_conn.getList(DN(api.env.container_ranges, self.suffix),
+ ldap.SCOPE_ONELEVEL,
+ "(objectclass=ipaDomainIDRange)")
if len(res) != 1:
root_logger.critical("Found more than one ID range for the " \
"local domain.")
@@ -230,17 +229,18 @@ class ADTRUSTInstance(service.Service):
pass
for new_dn in (self.trust_dn, \
- str(DN(('cn', 'ad'), self.trust_dn)), \
- str(DN(api.env.container_cifsdomains, self.suffix))):
+ DN(('cn', 'ad'), self.trust_dn), \
+ DN(api.env.container_cifsdomains, self.suffix)):
try:
self.admin_conn.getEntry(new_dn, ldap.SCOPE_BASE)
except errors.NotFound:
entry = ipaldap.Entry(new_dn)
entry.setValues("objectclass", ["nsContainer"])
- name = new_dn.split('=')[1].split(',')[0]
- if not name:
- print "Cannot extract RDN attribute value from [%s]" % \
- new_dn
+ try:
+ name = new_dn[1].attr
+ except Exception, e:
+ print 'Cannot extract RDN attribute value from "%s": %s' % \
+ (new_dn, e)
return
entry.setValues("cn", name)
self.admin_conn.addEntry(entry)
@@ -474,16 +474,16 @@ class ADTRUSTInstance(service.Service):
self.smb_conf = "/etc/samba/smb.conf"
- self.smb_dn = str(DN(('cn', 'adtrust agents'), ('cn', 'sysaccounts'),
- ('cn', 'etc'), self.suffix))
+ self.smb_dn = DN(('cn', 'adtrust agents'), ('cn', 'sysaccounts'),
+ ('cn', 'etc'), self.suffix)
- self.trust_dn = str(DN(api.env.container_trusts, self.suffix))
- self.smb_dom_dn = str(DN(('cn', self.domain_name),
- api.env.container_cifsdomains, self.suffix))
+ self.trust_dn = DN(api.env.container_trusts, self.suffix)
+ self.smb_dom_dn = DN(('cn', self.domain_name),
+ api.env.container_cifsdomains, self.suffix)
self.cifs_principal = "cifs/" + self.fqdn + "@" + self.realm
- self.cifs_agent = str(DN(('krbprincipalname', self.cifs_principal.lower()),
- api.env.container_service,
- self.suffix))
+ self.cifs_agent = DN(('krbprincipalname', self.cifs_principal.lower()),
+ api.env.container_service,
+ self.suffix)
self.selinux_booleans = ["samba_portmapper"]
self.__setup_sub_dict()
@@ -491,16 +491,13 @@ class ADTRUSTInstance(service.Service):
def find_local_id_range(self):
self.ldap_connect()
- if self.admin_conn.search_s(str(DN(api.env.container_ranges,
- self.suffix)),
+ if self.admin_conn.search_s(DN(api.env.container_ranges, self.suffix),
ldap.SCOPE_ONELEVEL,
"objectclass=ipaDomainIDRange"):
return
try:
- entry = self.admin_conn.getEntry(str(DN(('cn', 'admins'),
- api.env.container_group,
- self.suffix)),
+ entry = self.admin_conn.getEntry(DN(('cn', 'admins'), api.env.container_group, self.suffix),
ldap.SCOPE_BASE)
except errors.NotFound:
raise ValueError("No local ID range and no admins group found.\n" \
@@ -523,9 +520,9 @@ class ADTRUSTInstance(service.Service):
"range.\nAdd local ID range manually and try " \
"again!")
- entry = ipaldap.Entry(str(DN(('cn', ('%s_id_range' % self.realm)),
- api.env.container_ranges,
- self.suffix)))
+ entry = ipaldap.Entry(DN(('cn', ('%s_id_range' % self.realm)),
+ api.env.container_ranges,
+ self.suffix))
entry.setValue('objectclass', 'ipaDomainIDRange')
entry.setValue('cn', ('%s_id_range' % self.realm))
entry.setValue('ipaBaseID', str(base_id))
diff --git a/ipaserver/install/bindinstance.py b/ipaserver/install/bindinstance.py
index f320202ea..2e00f70b1 100644
--- a/ipaserver/install/bindinstance.py
+++ b/ipaserver/install/bindinstance.py
@@ -38,6 +38,7 @@ from ipapython.ipa_log_manager import *
import ipalib
from ipalib import api, util, errors
+from ipapython.dn import DN
NAMED_CONF = '/etc/named.conf'
RESOLV_CONF = '/etc/resolv.conf'
@@ -166,10 +167,11 @@ def dns_container_exists(fqdn, suffix, dm_password=None, ldapi=False, realm=None
Test whether the dns container exists.
"""
- def object_exists(dn):
+ def object_exists(dn): # FIXME, this should be a IPAdmin/ldap2 method so it can be shared
"""
Test whether the given object exists in LDAP.
"""
+ assert isinstance(dn, DN)
try:
conn.search_ext_s(dn, ldap.SCOPE_BASE)
except ldap.NO_SUCH_OBJECT:
@@ -177,6 +179,7 @@ def dns_container_exists(fqdn, suffix, dm_password=None, ldapi=False, realm=None
else:
return True
+ assert isinstance(suffix, DN)
try:
# At install time we may need to use LDAPI to avoid chicken/egg
# issues with SSL certs and truting CAs
@@ -192,7 +195,7 @@ def dns_container_exists(fqdn, suffix, dm_password=None, ldapi=False, realm=None
except ldap.SERVER_DOWN:
raise RuntimeError('LDAP server on %s is not responding. Is IPA installed?' % fqdn)
- ret = object_exists("cn=dns,%s" % suffix)
+ ret = object_exists(DN(('cn', 'dns'), suffix))
conn.unbind_s()
return ret
@@ -288,11 +291,14 @@ def add_zone(name, zonemgr=None, dns_backup=None, ns_hostname=None, ns_ip_addres
ns_main = ns_hostname
ns_replicas = []
+ if ns_ip_address is not None:
+ ns_ip_address = unicode(ns_ip_address)
+
try:
api.Command.dnszone_add(unicode(name),
idnssoamname=unicode(ns_main+'.'),
idnssoarname=unicode(zonemgr),
- ip_address=unicode(ns_ip_address),
+ ip_address=ns_ip_address,
idnsallowdynupdate=True,
idnsupdatepolicy=unicode(update_policy),
idnsallowquery=u'any',
@@ -329,11 +335,14 @@ def add_reverse_zone(zone, ns_hostname=None, ns_ip_address=None,
ns_main = ns_hostname
ns_replicas = []
+ if ns_ip_address is not None:
+ ns_ip_address = unicode(ns_ip_address)
+
try:
api.Command.dnszone_add(unicode(zone),
idnssoamname=unicode(ns_main+'.'),
idnsallowdynupdate=True,
- ip_address=unicode(ns_ip_address),
+ ip_address=ns_ip_address,
idnsupdatepolicy=unicode(update_policy),
idnsallowquery=u'any',
idnsallowtransfer=u'none',)
@@ -465,6 +474,8 @@ class BindInstance(service.Service):
else:
self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
+ suffix = ipautil.dn_attribute_property('_suffix')
+
def setup(self, fqdn, ip_address, realm_name, domain_name, forwarders, ntp,
reverse_zone, named_user="named", zonemgr=None,
zone_refresh=0, persistent_search=True, serial_autoincrement=True):
@@ -574,7 +585,7 @@ class BindInstance(service.Service):
if self.ntp:
optional_ntp = "\n;ntp server\n"
- optional_ntp += "_ntp._udp\t\tIN SRV 0 100 123\t%s""" % self.host_in_rr
+ optional_ntp += "_ntp._udp\t\tIN SRV 0 100 123\t%s" % self.host_in_rr
else:
optional_ntp = ""
@@ -654,7 +665,8 @@ class BindInstance(service.Service):
p = self.move_service(dns_principal)
if p is None:
# the service has already been moved, perhaps we're doing a DNS reinstall
- dns_principal = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (dns_principal, self.suffix)
+ dns_principal = DN(('krbprincipalname', dns_principal),
+ ('cn', 'services'), ('cn', 'accounts'), self.suffix)
else:
dns_principal = p
@@ -667,9 +679,7 @@ class BindInstance(service.Service):
# it can host the memberof attribute, then also add it to the
# dnsserver role group, this way the DNS is allowed to perform
# DNS Updates
- dns_group = "cn=DNS Servers,cn=privileges,cn=pbac,%s" % self.suffix
- if isinstance(dns_principal, unicode):
- dns_principal = dns_principal.encode('utf-8')
+ dns_group = DN(('cn', 'DNS Servers'), ('cn', 'privileges'), ('cn', 'pbac'), self.suffix)
mod = [(ldap.MOD_ADD, 'member', dns_principal)]
try:
diff --git a/ipaserver/install/cainstance.py b/ipaserver/install/cainstance.py
index dc4374cce..b00ceeaed 100644
--- a/ipaserver/install/cainstance.py
+++ b/ipaserver/install/cainstance.py
@@ -39,7 +39,7 @@ from ipapython import dogtag
from ipapython.certdb import get_ca_nickname
from ipapython import certmonger
from ipalib import pkcs10, x509
-from ipalib.dn import DN
+from ipapython.dn import DN
import subprocess
from nss.error import NSPRError
@@ -243,7 +243,9 @@ class CADSInstance(service.Service):
self.suffix = ipautil.realm_to_suffix(self.realm_name)
self.__setup_sub_dict()
else:
- self.suffix = None
+ self.suffix = DN()
+
+ subject_base = ipautil.dn_attribute_property('_subject_base')
def create_instance(self, realm_name, host_name, domain_name,
dm_password, pkcs12_info=None, ds_port=DEFAULT_DSPORT,
@@ -268,7 +270,7 @@ class CADSInstance(service.Service):
def __setup_sub_dict(self):
server_root = dsinstance.find_server_root()
self.sub_dict = dict(FQDN=self.fqdn, SERVERID=self.serverid,
- PASSWORD=self.dm_password, SUFFIX=self.suffix.lower(),
+ PASSWORD=self.dm_password, SUFFIX=self.suffix,
REALM=self.realm_name, USER=PKI_DS_USER,
SERVER_ROOT=server_root, DOMAIN=self.domain,
TIME=int(time.time()), DSPORT=self.ds_port,
@@ -342,7 +344,7 @@ class CADSInstance(service.Service):
def enable_ssl(self):
conn = ipaldap.IPAdmin("127.0.0.1", port=DEFAULT_DSPORT)
- conn.simple_bind_s("cn=directory manager", self.dm_password)
+ conn.simple_bind_s(DN(('cn', 'directory manager')), self.dm_password)
mod = [(ldap.MOD_REPLACE, "nsSSLClientAuth", "allowed"),
(ldap.MOD_REPLACE, "nsSSL3Ciphers",
@@ -350,13 +352,13 @@ class CADSInstance(service.Service):
+rsa_des_sha,+rsa_fips_des_sha,+rsa_3des_sha,+rsa_fips_3des_sha,+fortezza,\
+fortezza_rc4_128_sha,+fortezza_null,+tls_rsa_export1024_with_rc4_56_sha,\
+tls_rsa_export1024_with_des_cbc_sha")]
- conn.modify_s("cn=encryption,cn=config", mod)
+ conn.modify_s(DN(('cn', 'encryption'), ('cn', 'config')), mod)
mod = [(ldap.MOD_ADD, "nsslapd-security", "on"),
(ldap.MOD_ADD, "nsslapd-secureport", str(DEFAULT_DSPORT+1))]
- conn.modify_s("cn=config", mod)
+ conn.modify_s(DN(('cn', 'config')), mod)
- entry = ipaldap.Entry("cn=RSA,cn=encryption,cn=config")
+ entry = ipaldap.Entry(DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')))
entry.setValues("objectclass", "top", "nsEncryptionModule")
entry.setValues("cn", "RSA")
@@ -460,7 +462,7 @@ class CAInstance(service.Service):
# will already have been initialized by Apache by the time
# mod_python wants to do things.
self.canickname = get_ca_nickname(realm)
- self.basedn = "o=ipaca"
+ self.basedn = DN(('o', 'ipaca'))
self.ca_agent_db = tempfile.mkdtemp(prefix = "tmp-")
self.ra_agent_db = ra_db
self.ra_agent_pwd = self.ra_agent_db + "/pwdfile.txt"
@@ -506,7 +508,7 @@ class CAInstance(service.Service):
self.clone = True
self.master_host = master_host
if subject_base is None:
- self.subject_base = "O=%s" % self.realm
+ self.subject_base = DN(('O', self.realm))
else:
self.subject_base = subject_base
@@ -615,12 +617,12 @@ class CAInstance(service.Service):
"-agent_name", "ipa-ca-agent",
"-agent_key_size", "2048",
"-agent_key_type", "rsa",
- "-agent_cert_subject", "CN=ipa-ca-agent,%s" % self.subject_base,
+ "-agent_cert_subject", str(DN(('CN', 'ipa-ca-agent'), self.subject_base)),
"-ldap_host", self.fqdn,
"-ldap_port", str(self.ds_port),
"-bind_dn", "cn=Directory Manager",
"-bind_password", self.dm_password,
- "-base_dn", self.basedn,
+ "-base_dn", str(self.basedn),
"-db_name", "ipaca",
"-key_size", "2048",
"-key_type", "rsa",
@@ -629,11 +631,12 @@ class CAInstance(service.Service):
"-backup_pwd", self.admin_password,
"-subsystem_name", self.service_name,
"-token_name", "internal",
- "-ca_subsystem_cert_subject_name", "CN=CA Subsystem,%s" % self.subject_base,
- "-ca_ocsp_cert_subject_name", "CN=OCSP Subsystem,%s" % self.subject_base,
- "-ca_server_cert_subject_name", "CN=%s,%s" % (self.fqdn, self.subject_base),
- "-ca_audit_signing_cert_subject_name", "CN=CA Audit,%s" % self.subject_base,
- "-ca_sign_cert_subject_name", "CN=Certificate Authority,%s" % self.subject_base ]
+ "-ca_subsystem_cert_subject_name", str(DN(('CN', 'CA Subsystem'), self.subject_base)),
+ "-ca_subsystem_cert_subject_name", str(DN(('CN', 'CA Subsystem'), self.subject_base)),
+ "-ca_ocsp_cert_subject_name", str(DN(('CN', 'OCSP Subsystem'), self.subject_base)),
+ "-ca_server_cert_subject_name", str(DN(('CN', self.fqdn), self.subject_base)),
+ "-ca_audit_signing_cert_subject_name", str(DN(('CN', 'CA Audit'), self.subject_base)),
+ "-ca_sign_cert_subject_name", str(DN(('CN', 'Certificate Authority'), self.subject_base)) ]
if self.external == 1:
args.append("-external")
args.append("true")
@@ -836,13 +839,12 @@ class CAInstance(service.Service):
# Create an RA user in the CA LDAP server and add that user to
# the appropriate groups so it can issue certificates without
# manual intervention.
- ld = ldap.initialize("ldap://%s" % ipautil.format_netloc(self.fqdn, self.ds_port))
- ld.protocol_version=ldap.VERSION3
- ld.simple_bind_s("cn=Directory Manager", self.dm_password)
+ conn = ipaldap.IPAdmin(self.fqdn, self.ds_port)
+ conn.simple_bind_s(DN(('cn', 'Directory Manager')), self.dm_password)
decoded = base64.b64decode(self.ra_cert)
- entry_dn = "uid=%s,ou=People,%s" % ("ipara", self.basedn)
+ entry_dn = DN(('uid', "ipara"), ('ou', 'People'), self.basedn)
entry = [
('objectClass', ['top', 'person', 'organizationalPerson', 'inetOrgPerson', 'cmsuser']),
('uid', "ipara"),
@@ -851,19 +853,23 @@ class CAInstance(service.Service):
('usertype', "agentType"),
('userstate', "1"),
('userCertificate', decoded),
- ('description', '2;%s;CN=Certificate Authority,%s;CN=IPA RA,%s' % (str(self.requestId), self.subject_base, self.subject_base)),]
+ ('description', '2;%s;%s;%s' % \
+ (str(self.requestId),
+ DN(('CN', 'Certificate Authority'), self.subject_base),
+ DN(('CN', 'IPA RA'), self.subject_base))),
+ ]
- ld.add_s(entry_dn, entry)
+ conn.add_s(entry_dn, entry)
- dn = "cn=Certificate Manager Agents,ou=groups,%s" % self.basedn
+ dn = DN(('cn', 'Certificate Manager Agents'), ('ou', 'groups'), self.basedn)
modlist = [(0, 'uniqueMember', '%s' % entry_dn)]
- ld.modify_s(dn, modlist)
+ conn.modify_s(dn, modlist)
- dn = "cn=Registration Manager Agents,ou=groups,%s" % self.basedn
+ dn = DN(('cn', 'Registration Manager Agents'), ('ou', 'groups'), self.basedn)
modlist = [(0, 'uniqueMember', '%s' % entry_dn)]
- ld.modify_s(dn, modlist)
+ conn.modify_s(dn, modlist)
- ld.unbind_s()
+ conn.unbind_s()
def __run_certutil(self, args, database=None, pwd_file=None,stdin=None):
if not database:
@@ -969,7 +975,7 @@ class CAInstance(service.Service):
# Generate our CSR. The result gets put into stdout
try:
- (stdout, stderr, returncode) = self.__run_certutil(["-R", "-k", "rsa", "-g", "2048", "-s", "CN=IPA RA,%s" % self.subject_base, "-z", noise_name, "-a"])
+ (stdout, stderr, returncode) = self.__run_certutil(["-R", "-k", "rsa", "-g", "2048", "-s", str(DN(('CN', 'IPA RA'), self.subject_base)), "-z", noise_name, "-a"])
finally:
os.remove(noise_name)
@@ -1071,7 +1077,7 @@ class CAInstance(service.Service):
def __set_subject_in_config(self):
# dogtag ships with an IPA-specific profile that forces a subject
# format. We need to update that template with our base subject
- if installutils.update_file(IPA_SERVICE_PROFILE, 'OU=pki-ipa, O=IPA', self.subject_base):
+ if installutils.update_file(IPA_SERVICE_PROFILE, 'OU=pki-ipa, O=IPA', str(self.subject_base)):
print "Updating subject_base in CA template failed"
def uninstall(self):
diff --git a/ipaserver/install/certs.py b/ipaserver/install/certs.py
index d25a471ea..eebaa48c4 100644
--- a/ipaserver/install/certs.py
+++ b/ipaserver/install/certs.py
@@ -39,7 +39,7 @@ from ipalib import pkcs10
from ConfigParser import RawConfigParser, MissingSectionHeaderError
from ipapython import services as ipaservices
from ipalib import x509
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipalib.errors import CertificateOperationError
from nss.error import NSPRError
@@ -224,8 +224,7 @@ class CertDB(object):
self.self_signed_ca = ipa_self_signed()
if not subject_base:
- self.subject_base = "O=IPA"
- self.subject_format = "CN=%%s,%s" % self.subject_base
+ self.subject_base = DN(('O', 'IPA'))
self.cacert_name = get_ca_nickname(self.realm)
self.valid_months = "120"
@@ -245,6 +244,8 @@ class CertDB(object):
else:
self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
+ subject_base = ipautil.dn_attribute_property('_subject_base')
+
def __del__(self):
if self.reqdir is not None:
shutil.rmtree(self.reqdir, ignore_errors=True)
@@ -381,11 +382,11 @@ class CertDB(object):
def create_ca_cert(self):
os.chdir(self.secdir)
- subject = "cn=%s Certificate Authority" % self.realm
+ subject = DN(('cn', '%s Certificate Authority' % self.realm))
p = subprocess.Popen(["/usr/bin/certutil",
"-d", self.secdir,
"-S", "-n", self.cacert_name,
- "-s", subject,
+ "-s", str(subject),
"-x",
"-t", "CT,,C",
"-1",
@@ -565,7 +566,7 @@ class CertDB(object):
if not cdb:
cdb = self
if subject is None:
- subject=self.subject_format % hostname
+ subject=DN(('CN', hostname), self.subject_base)
self.request_cert(subject)
cdb.issue_server_cert(self.certreq_fname, self.certder_fname)
self.add_cert(self.certder_fname, nickname)
@@ -583,7 +584,7 @@ class CertDB(object):
if not cdb:
cdb = self
if subject is None:
- subject=self.subject_format % hostname
+ subject=DN(('CN', hostname), self.subject_base)
self.request_cert(subject)
cdb.issue_signing_cert(self.certreq_fname, self.certder_fname)
self.add_cert(self.certder_fname, nickname)
@@ -591,9 +592,10 @@ class CertDB(object):
os.unlink(self.certder_fname)
def request_cert(self, subject, certtype="rsa", keysize="2048"):
+ assert isinstance(subject, DN)
self.create_noise_file()
self.setup_cert_request()
- args = ["-R", "-s", subject,
+ args = ["-R", "-s", str(subject),
"-o", self.certreq_fname,
"-k", certtype,
"-g", keysize,
@@ -1046,19 +1048,19 @@ class CertDB(object):
# Prepare a simple cert request
req_dict = dict(PASSWORD=self.gen_password(),
SUBJBASE=self.subject_base,
- CERTNAME="CN="+nickname)
+ CERTNAME=DN(('CN', nickname)))
req_template = ipautil.SHARE_DIR + reqcfg + ".template"
conf = ipautil.template_file(req_template, req_dict)
fd = open(reqcfg, "w+")
fd.write(conf)
fd.close()
- base = self.subject_base.replace(",", "/")
- esc_subject = "CN=%s/%s" % (nickname, base)
+ base = str(self.subject_base).replace(",", "/")
+ esc_subject = DN(('CN', '%s/%s' % (nickname, base)))
ipautil.run(["/usr/bin/openssl", "req", "-new",
"-config", reqcfg,
- "-subj", esc_subject,
+ "-subj", str(esc_subject),
"-key", key_fname,
"-out", "kdc.req"])
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 9f3ae7252..bf6677381 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -36,12 +36,12 @@ import service
import installutils
import certs
import ldap
-from ldap.dn import escape_dn_chars
from ipaserver import ipaldap
from ipaserver.install import ldapupdate
from ipaserver.install import httpinstance
from ipaserver.install import replication
from ipalib import util, errors
+from ipapython.dn import DN
from ipaserver.plugins.ldap2 import ldap2
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
@@ -177,7 +177,7 @@ class DsInstance(service.Service):
self.suffix = ipautil.realm_to_suffix(self.realm_name)
self.__setup_sub_dict()
else:
- self.suffix = None
+ self.suffix = DN()
if fstore:
self.fstore = fstore
@@ -185,6 +185,8 @@ class DsInstance(service.Service):
self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
+ subject_base = ipautil.dn_attribute_property('_subject_base')
+
def __common_setup(self):
self.step("creating directory server user", self.__create_ds_user)
@@ -299,7 +301,7 @@ class DsInstance(service.Service):
self.fqdn,
self.dm_password)
repl.setup_replication(self.master_fqdn,
- r_binddn="cn=Directory Manager",
+ r_binddn=DN(('cn', 'Directory Manager')),
r_bindpw=self.dm_password)
self.run_init_memberof = repl.needs_memberof_fixup()
@@ -314,12 +316,12 @@ class DsInstance(service.Service):
self.sub_dict = dict(FQDN=self.fqdn, SERVERID=self.serverid,
PASSWORD=self.dm_password,
RANDOM_PASSWORD=self.generate_random(),
- SUFFIX=self.suffix.lower(),
+ SUFFIX=self.suffix,
REALM=self.realm_name, USER=DS_USER,
SERVER_ROOT=server_root, DOMAIN=self.domain,
TIME=int(time.time()), IDSTART=self.idstart,
IDMAX=self.idmax, HOST=self.fqdn,
- ESCAPED_SUFFIX= escape_dn_chars(self.suffix.lower()),
+ ESCAPED_SUFFIX=str(self.suffix),
GROUP=DS_GROUP,
IDRANGE_SIZE=self.idmax-self.idstart+1
)
@@ -445,11 +447,12 @@ class DsInstance(service.Service):
self._ldap_mod("memberof-task.ldif", self.sub_dict)
# Note, keep dn in sync with dn in install/share/memberof-task.ldif
- dn = "cn=IPA install %s,cn=memberof task,cn=tasks,cn=config" % self.sub_dict["TIME"]
+ dn = DN(('cn', 'IPA install %s' % self.sub_dict["TIME"]), ('cn', 'memberof task'),
+ ('cn', 'tasks'), ('cn', 'config'))
root_logger.debug("Waiting for memberof task to complete.")
conn = ipaldap.IPAdmin("127.0.0.1")
if self.dm_password:
- conn.simple_bind_s("cn=directory manager", self.dm_password)
+ conn.simple_bind_s(DN(('cn', 'directory manager')), self.dm_password)
else:
conn.do_sasl_gssapi_bind()
conn.checkTask(dn, dowait=True)
@@ -543,7 +546,7 @@ class DsInstance(service.Service):
dsdb.create_pin_file()
conn = ipaldap.IPAdmin("127.0.0.1")
- conn.simple_bind_s("cn=directory manager", self.dm_password)
+ conn.simple_bind_s(DN(('cn', 'directory manager')), self.dm_password)
mod = [(ldap.MOD_REPLACE, "nsSSLClientAuth", "allowed"),
(ldap.MOD_REPLACE, "nsSSL3Ciphers",
@@ -551,12 +554,12 @@ class DsInstance(service.Service):
+rsa_des_sha,+rsa_fips_des_sha,+rsa_3des_sha,+rsa_fips_3des_sha,+fortezza,\
+fortezza_rc4_128_sha,+fortezza_null,+tls_rsa_export1024_with_rc4_56_sha,\
+tls_rsa_export1024_with_des_cbc_sha")]
- conn.modify_s("cn=encryption,cn=config", mod)
+ conn.modify_s(DN(('cn', 'encryption'), ('cn', 'config')), mod)
mod = [(ldap.MOD_ADD, "nsslapd-security", "on")]
- conn.modify_s("cn=config", mod)
+ conn.modify_s(DN(('cn', 'config')), mod)
- entry = ipaldap.Entry("cn=RSA,cn=encryption,cn=config")
+ entry = ipaldap.Entry(DN(('cn', 'RSA'), ('cn', 'encryption'), ('cn', 'config')))
entry.setValues("objectclass", "top", "nsEncryptionModule")
entry.setValues("cn", "RSA")
@@ -612,9 +615,9 @@ class DsInstance(service.Service):
os.close(admpwdfd)
args = ["/usr/bin/ldappasswd", "-h", self.fqdn,
- "-ZZ", "-x", "-D", "cn=Directory Manager",
+ "-ZZ", "-x", "-D", str(DN(('cn', 'Directory Manager'))),
"-y", dmpwdfile, "-T", admpwdfile,
- "uid=admin,cn=users,cn=accounts,"+self.suffix]
+ str(DN(('uid', 'admin'), ('cn', 'users'), ('cn', 'accounts'), self.suffix))]
try:
env = { 'LDAPTLS_CACERTDIR':os.path.dirname(CACERT),
'LDAPTLS_CACERT':CACERT }
@@ -801,22 +804,19 @@ class DsInstance(service.Service):
def replica_populate(self):
self.ldap_connect()
- dn = "cn=default,ou=profile,%s" % self.suffix
+ dn = DN(('cn', 'default'), ('ou', 'profile'), self.suffix)
try:
- ret = self.admin_conn.search_s(dn, ldap.SCOPE_BASE,
- '(objectclass=*)')[0]
- srvlist = ret.data.get('defaultServerList')
- if len(srvlist) > 0:
- srvlist = srvlist[0].split()
+ entry = self.admin_conn.getEntry(dn, ldap.SCOPE_BASE, '(objectclass=*)')
+ srvlist = entry.getValue('defaultServerList', '')
+ srvlist = srvlist.split()
if not self.fqdn in srvlist:
srvlist.append(self.fqdn)
attr = ' '.join(srvlist)
mod = [(ldap.MOD_REPLACE, 'defaultServerList', attr)]
self.admin_conn.modify_s(dn, mod)
- except ldap.NO_SUCH_OBJECT:
+ except errors.NotFound:
pass
except ldap.TYPE_OR_VALUE_EXISTS:
pass
self.ldap_disconnect()
-
diff --git a/ipaserver/install/httpinstance.py b/ipaserver/install/httpinstance.py
index 601f76bb7..e5d9f080b 100644
--- a/ipaserver/install/httpinstance.py
+++ b/ipaserver/install/httpinstance.py
@@ -57,6 +57,8 @@ class HTTPInstance(service.Service):
else:
self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
+ subject_base = ipautil.dn_attribute_property('_subject_base')
+
def create_instance(self, realm, fqdn, domain_name, dm_password=None, autoconfig=True, pkcs12_info=None, self_signed_ca=False, subject_base=None, auto_redirect=True):
self.fqdn = fqdn
self.realm = realm
diff --git a/ipaserver/install/installutils.py b/ipaserver/install/installutils.py
index 388a11e26..048706523 100644
--- a/ipaserver/install/installutils.py
+++ b/ipaserver/install/installutils.py
@@ -44,6 +44,7 @@ from ipapython.ipa_log_manager import *
from ipalib.util import validate_hostname
from ipapython import config
from ipalib import errors
+from ipapython.dn import DN
# Used to determine install status
IPA_MODULES = ['httpd', 'kadmin', 'dirsrv', 'pki-cad', 'pkids', 'install', 'krb5kdc', 'ntpd', 'named', 'ipa_memcached']
@@ -71,9 +72,11 @@ class ReplicaConfig:
self.dirman_password = ""
self.host_name = ""
self.dir = ""
- self.subject_base = ""
+ self.subject_base = None
self.setup_ca = False
+ subject_base = ipautil.dn_attribute_property('_subject_base')
+
def get_fqdn():
fqdn = ""
try:
diff --git a/ipaserver/install/ipa_ldap_updater.py b/ipaserver/install/ipa_ldap_updater.py
index 794ea28b5..d9f680927 100644
--- a/ipaserver/install/ipa_ldap_updater.py
+++ b/ipaserver/install/ipa_ldap_updater.py
@@ -150,6 +150,8 @@ class LDAPUpdater_Upgrade(LDAPUpdater):
class LDAPUpdater_NonUpgrade(LDAPUpdater):
+ log_file_name = '/var/log/ipaupgrade.log'
+
def validate_options(self):
super(LDAPUpdater_NonUpgrade, self).validate_options()
options = self.options
diff --git a/ipaserver/install/krbinstance.py b/ipaserver/install/krbinstance.py
index 8cc50fba4..9101e6fcc 100644
--- a/ipaserver/install/krbinstance.py
+++ b/ipaserver/install/krbinstance.py
@@ -33,6 +33,7 @@ from ipapython import services as ipaservices
from ipalib import util
from ipalib import errors
from ipapython.ipa_log_manager import *
+from ipapython.dn import DN
from ipaserver import ipaldap
from ipaserver.install import replication
@@ -84,6 +85,7 @@ class KrbInstance(service.Service):
self.admin_password = None
self.master_password = None
self.suffix = None
+ self.subject_base = None
self.kdc_password = None
self.sub_dict = None
self.pkcs12_info = None
@@ -94,8 +96,11 @@ class KrbInstance(service.Service):
else:
self.fstore = sysrestore.FileStore('/var/lib/ipa/sysrestore')
+ suffix = ipautil.dn_attribute_property('_suffix')
+ subject_base = ipautil.dn_attribute_property('_subject_base')
+
def get_realm_suffix(self):
- return "cn=%s,cn=kerberos,%s" % (self.realm, self.suffix)
+ return DN(('cn', self.realm), ('cn', 'kerberos'), self.suffix)
def move_service_to_host(self, principal):
"""
@@ -103,12 +108,12 @@ class KrbInstance(service.Service):
cn=kerberos to reside under the host entry.
"""
- service_dn = "krbprincipalname=%s,%s" % (principal, self.get_realm_suffix())
+ service_dn = DN(('krbprincipalname', principal), self.get_realm_suffix())
service_entry = self.admin_conn.getEntry(service_dn, ldap.SCOPE_BASE)
self.admin_conn.deleteEntry(service_dn)
# Create a host entry for this master
- host_dn = "fqdn=%s,cn=computers,cn=accounts,%s" % (self.fqdn, self.suffix)
+ host_dn = DN(('fqdn', self.fqdn), ('cn', 'computers'), ('cn', 'accounts'), self.suffix)
host_entry = ipaldap.Entry(host_dn)
host_entry.setValues('objectclass', ['top', 'ipaobject', 'nshost', 'ipahost', 'ipaservice', 'pkiuser', 'krbprincipalaux', 'krbprincipal', 'krbticketpolicyaux', 'ipasshhost'])
host_entry.setValues('krbextradata', service_entry.getValues('krbextradata'))
@@ -251,7 +256,7 @@ class KrbInstance(service.Service):
# they may conflict.
try:
- res = self.admin_conn.search_s("cn=mapping,cn=sasl,cn=config",
+ res = self.admin_conn.search_s(DN(('cn', 'mapping'), ('cn', 'sasl'), ('cn', 'config')),
ldap.SCOPE_ONELEVEL,
"(objectclass=nsSaslMapping)")
for r in res:
@@ -264,7 +269,7 @@ class KrbInstance(service.Service):
root_logger.critical("Error while enumerating SASL mappings %s" % str(e))
raise e
- entry = ipaldap.Entry("cn=Full Principal,cn=mapping,cn=sasl,cn=config")
+ entry = ipaldap.Entry(DN(('cn', 'Full Principal'), ('cn', 'mapping'), ('cn', 'sasl'), ('cn', 'config')))
entry.setValues("objectclass", "top", "nsSaslMapping")
entry.setValues("cn", "Full Principal")
entry.setValues("nsSaslMapRegexString", '\(.*\)@\(.*\)')
@@ -277,7 +282,7 @@ class KrbInstance(service.Service):
root_logger.critical("failed to add Full Principal Sasl mapping")
raise e
- entry = ipaldap.Entry("cn=Name Only,cn=mapping,cn=sasl,cn=config")
+ entry = ipaldap.Entry(DN(('cn', 'Name Only'), ('cn', 'mapping'), ('cn', 'sasl'), ('cn', 'config')))
entry.setValues("objectclass", "top", "nsSaslMapping")
entry.setValues("cn", "Name Only")
entry.setValues("nsSaslMapRegexString", '^[^:@]+$')
@@ -358,7 +363,7 @@ class KrbInstance(service.Service):
root_logger.critical("Could not find master key in DS")
raise e
- krbMKey = pyasn1.codec.ber.decoder.decode(entry.krbmkey)
+ krbMKey = pyasn1.codec.ber.decoder.decode(entry.getValue('krbmkey'))
keytype = int(krbMKey[0][1][0])
keydata = str(krbMKey[0][1][1])
@@ -431,7 +436,7 @@ class KrbInstance(service.Service):
# Create the special anonymous principal
installutils.kadmin_addprinc(princ_realm)
- dn = "krbprincipalname=%s,%s" % (princ_realm, self.get_realm_suffix())
+ dn = DN(('krbprincipalname', princ_realm), self.get_realm_suffix())
self.admin_conn.inactivateEntry(dn, False)
def __convert_to_gssapi_replication(self):
@@ -439,7 +444,7 @@ class KrbInstance(service.Service):
self.fqdn,
self.dm_password)
repl.convert_to_gssapi_replication(self.master_fqdn,
- r_binddn="cn=Directory Manager",
+ r_binddn=DN(('cn', 'Directory Manager')),
r_bindpw=self.dm_password)
def uninstall(self):
diff --git a/ipaserver/install/ldapupdate.py b/ipaserver/install/ldapupdate.py
index 949b86ad9..a51edff99 100644
--- a/ipaserver/install/ldapupdate.py
+++ b/ipaserver/install/ldapupdate.py
@@ -33,9 +33,8 @@ import uuid
from ipalib import util
from ipalib import errors
from ipalib import api
-from ipalib.dn import DN
+from ipapython.dn import DN
import ldap
-from ldap.dn import escape_dn_chars
from ipapython.ipa_log_manager import *
import krbV
import platform
@@ -52,22 +51,62 @@ from ipaserver.install.plugins import FIRST, MIDDLE, LAST
class BadSyntax(installutils.ScriptError):
def __init__(self, value):
self.value = value
- self.msg = "There is a syntax error in this update file: \n %s" % value
+ self.msg = "LDAPUpdate: syntax error: \n %s" % value
self.rval = 1
def __str__(self):
return repr(self.value)
class LDAPUpdate:
+ action_keywords = ["default", "add", "remove", "only", "deleteentry", "replace", "addifnew", "addifexist"]
+
def __init__(self, dm_password, sub_dict={}, live_run=True,
online=True, ldapi=False, plugins=False):
- """dm_password = Directory Manager password
- sub_dict = substitution dictionary
- live_run = Apply the changes or just test
- online = do an online LDAP update or use an experimental LDIF updater
- ldapi = bind using ldapi. This assumes autobind is enabled.
- plugins = execute the pre/post update plugins
- """
+ '''
+ :parameters:
+ dm_password
+ Directory Manager password
+ sub_dict
+ substitution dictionary
+ live_run
+ Apply the changes or just test
+ online
+ Do an online LDAP update or use an experimental LDIF updater
+ ldapi
+ Bind using ldapi. This assumes autobind is enabled.
+ plugins
+ execute the pre/post update plugins
+
+ Data Structure Example:
+ -----------------------
+
+ dn_by_rdn_count = {
+ 3: 'cn=config,dc=example,dc=com':
+ 4: 'cn=bob,ou=people,dc=example,dc=com',
+ }
+
+ all_updates = {
+ 'dn': 'cn=config,dc=example,dc=com':
+ {
+ 'dn': 'cn=config,dc=example,dc=com',
+ 'default': ['attr1':default1'],
+ 'updates': ['action:attr1:value1',
+ 'action:attr2:value2]
+ },
+ 'dn': 'cn=bob,ou=people,dc=example,dc=com':
+ {
+ 'dn': 'cn=bob,ou=people,dc=example,dc=com',
+ 'default': ['attr3':default3'],
+ 'updates': ['action:attr3:value3',
+ 'action:attr4:value4],
+ }
+ }
+
+ The default and update lists are "dispositions"
+
+
+ '''
+ log_mgr.get_logger(self, True)
self.sub_dict = sub_dict
self.live_run = live_run
self.dm_password = dm_password
@@ -77,6 +116,8 @@ class LDAPUpdate:
self.ldapi = ldapi
self.plugins = plugins
self.pw_name = pwd.getpwuid(os.geteuid()).pw_name
+ self.realm = None
+ suffix = None
if sub_dict.get("REALM"):
self.realm = sub_dict["REALM"]
@@ -89,8 +130,10 @@ class LDAPUpdate:
self.realm = None
suffix = None
+ if suffix is not None:
+ assert isinstance(suffix, DN)
domain = ipautil.get_domain_name()
- libarch = self.__identify_arch()
+ libarch = self._identify_arch()
fqdn = installutils.get_fqdn()
if fqdn is None:
@@ -110,7 +153,7 @@ class LDAPUpdate:
if not self.sub_dict.get("SUFFIX") and suffix is not None:
self.sub_dict["SUFFIX"] = suffix
if not self.sub_dict.get("ESCAPED_SUFFIX"):
- self.sub_dict["ESCAPED_SUFFIX"] = escape_dn_chars(suffix)
+ self.sub_dict["ESCAPED_SUFFIX"] = str(suffix)
if not self.sub_dict.get("LIBARCH"):
self.sub_dict["LIBARCH"] = libarch
if not self.sub_dict.get("TIME"):
@@ -123,7 +166,7 @@ class LDAPUpdate:
try:
conn = ipaldap.IPAdmin(fqdn, ldapi=self.ldapi, realm=self.realm)
if self.dm_password:
- conn.do_simple_bind(binddn="cn=directory manager", bindpw=self.dm_password)
+ conn.do_simple_bind(binddn=DN(('cn', 'directory manager')), bindpw=self.dm_password)
elif os.getegid() == 0:
try:
# autobind
@@ -145,13 +188,13 @@ class LDAPUpdate:
# The following 2 functions were taken from the Python
# documentation at http://docs.python.org/library/csv.html
- def __utf_8_encoder(self, unicode_csv_data):
+ def _utf_8_encoder(self, unicode_csv_data):
for line in unicode_csv_data:
yield line.encode('utf-8')
- def __unicode_csv_reader(self, unicode_csv_data, quote_char="'", dialect=csv.excel, **kwargs):
+ def _unicode_csv_reader(self, unicode_csv_data, quote_char="'", dialect=csv.excel, **kwargs):
# csv.py doesn't do Unicode; encode temporarily as UTF-8:
- csv_reader = csv.reader(self.__utf_8_encoder(unicode_csv_data),
+ csv_reader = csv.reader(self._utf_8_encoder(unicode_csv_data),
dialect=dialect, delimiter=',',
quotechar=quote_char,
skipinitialspace=True,
@@ -160,7 +203,7 @@ class LDAPUpdate:
# decode UTF-8 back to Unicode, cell by cell:
yield [unicode(cell, 'utf-8') for cell in row]
- def __identify_arch(self):
+ def _identify_arch(self):
"""On multi-arch systems some libraries may be in /lib64, /usr/lib64,
etc. Determine if a suffix is needed based on the current
architecture.
@@ -178,7 +221,7 @@ class LDAPUpdate:
except KeyError, e:
raise BadSyntax("Unknown template keyword %s" % e)
- def __parse_values(self, line):
+ def _parse_values(self, line):
"""Parse a comma-separated string into separate values and convert them
into a list. This should handle quoted-strings with embedded commas
"""
@@ -186,7 +229,7 @@ class LDAPUpdate:
quote_char = "'"
else:
quote_char = '"'
- reader = self.__unicode_csv_reader([line], quote_char)
+ reader = self._unicode_csv_reader([line], quote_char)
value = []
for row in reader:
value = value + row
@@ -201,7 +244,7 @@ class LDAPUpdate:
if fd != sys.stdin: fd.close()
return text
- def __entry_to_entity(self, ent):
+ def _entry_to_entity(self, ent):
"""Tne Entry class is a bare LDAP entry. The Entity class has a lot more
helper functions that we need, so convert to dict and then to Entity.
"""
@@ -215,113 +258,158 @@ class LDAPUpdate:
entry[key] = value[0]
return entity.Entity(entry)
- def __combine_updates(self, dn_list, all_updates, update):
- """Combine a new update with the list of total updates
-
- Updates are stored in 2 lists:
- dn_list: contains a unique list of DNs in the updates
- all_updates: the actual updates that need to be applied
-
- We want to apply the updates from the shortest to the longest
- path so if new child and parent entries are in different updates
- we can be sure the parent gets written first. This also lets
- us apply any schema first since it is in the very short cn=schema.
- """
+ def _combine_updates(self, all_updates, update):
+ 'Combine a new update with the list of total updates'
dn = update.get('dn')
- dns = ldap.explode_dn(dn.lower())
- l = len(dns)
- if dn_list.get(l):
- if dn not in dn_list[l]:
- dn_list[l].append(dn)
- else:
- dn_list[l] = [dn]
+ assert isinstance(dn, DN)
+
if not all_updates.get(dn):
all_updates[dn] = update
return all_updates
- e = all_updates[dn]
+ existing_update = all_updates[dn]
if 'default' in update:
- if 'default' in e:
- e['default'] = e['default'] + update['default']
- else:
- e['default'] = update['default']
+ disposition_list = existing_update.setdefault('default', [])
+ disposition_list.extend(update['default'])
elif 'updates' in update:
- if 'updates' in e:
- e['updates'] = e['updates'] + update['updates']
- else:
- e['updates'] = update['updates']
+ disposition_list = existing_update.setdefault('updates', [])
+ disposition_list.extend(update['updates'])
else:
- root_logger.debug("Unknown key in updates %s" % update.keys())
-
- all_updates[dn] = e
+ self.debug("Unknown key in updates %s" % update.keys())
+
+ def merge_updates(self, all_updates, updates):
+ '''
+ Add the new_update dict to the all_updates dict. If an entry
+ in the new_update already has an entry in all_updates merge
+ the two entries sensibly assuming the new entries take
+ precedence. Otherwise just add the new entry.
+ '''
+
+ for new_update in updates:
+ for new_dn, new_entry in new_update.iteritems():
+ existing_entry = all_updates.get(new_dn)
+ if existing_entry:
+ # If the existing entry is marked for deletion but the
+ # new entry is not also a delete then clear the delete
+ # flag otherwise the newer update will be lost.
+ if existing_entry.has_key('deleteentry') and not new_entry.has_key('deleteentry'):
+ self.warning("ldapupdate: entry '%s' previously marked for deletion but" +
+ " this subsequent update reestablishes it: %s", new_dn, new_entry)
+ del existing_entry['deleteentry']
+ existing_entry.update(new_entry)
+ else:
+ all_updates[new_dn] = new_entry
- return all_updates
- def parse_update_file(self, data, all_updates, dn_list):
+ def parse_update_file(self, data_source_name, source_data, all_updates):
"""Parse the update file into a dictonary of lists and apply the update
for each DN in the file."""
- valid_keywords = ["default", "add", "remove", "only", "deleteentry", "replace", "addifnew", "addifexist"]
update = {}
- d = ""
- index = ""
+ logical_line = ""
+ action = ""
dn = None
lcount = 0
- for line in data:
- # Strip out \n and extra white space
- lcount = lcount + 1
- # skip comments and empty lines
- line = line.rstrip()
- if line.startswith('#') or line == '': continue
+ def emit_item(logical_line):
+ '''
+ Given a logical line containing an item to process perform the following:
- if line.lower().startswith('dn:'):
- if dn is not None:
- all_updates = self.__combine_updates(dn_list, all_updates, update)
+ * Strip leading & trailing whitespace
+ * Substitute any variables
+ * Get the action, attribute, and value
+ * Each update has one list per disposition, append to specified disposition list
+ '''
- update = {}
- dn = line[3:].strip()
- update['dn'] = self._template_str(dn)
- else:
- if dn is None:
- raise BadSyntax, "dn is not defined in the update"
-
- line = self._template_str(line)
- if line.startswith(' '):
- v = d[len(d) - 1]
- v = v + line[1:]
- d[len(d) - 1] = v
- update[index] = d
- continue
- line = line.strip()
- values = line.split(':', 2)
- if len(values) != 3:
- raise BadSyntax, "Bad formatting on line %d: %s" % (lcount,line)
+ logical_line = logical_line.strip()
+ if logical_line == '':
+ return
+
+ # Perform variable substitution on constructued line
+ logical_line = self._template_str(logical_line)
- index = values[0].strip().lower()
+ items = logical_line.split(':', 2)
- if index not in valid_keywords:
- raise BadSyntax, "Unknown keyword %s" % index
+ if len(items) == 0:
+ raise BadSyntax, "Bad formatting on line %s:%d: %s" % (data_source_name, lcount, logical_line)
- attr = values[1].strip()
- value = values[2].strip()
+ action = items[0].strip().lower()
- new_value = ""
- if index == "default":
+ if action not in self.action_keywords:
+ raise BadSyntax, "Unknown update action '%s', data source=%s" % (action, data_source_name)
+
+ if action == 'deleteentry':
+ new_value = None
+ disposition = "deleteentry"
+ else:
+ if len(items) != 3:
+ raise BadSyntax, "Bad formatting on line %s:%d: %s" % (data_source_name, lcount, logical_line)
+
+ attr = items[1].strip()
+ value = items[2].strip()
+
+ if action == "default":
new_value = attr + ":" + value
+ disposition = "default"
else:
- new_value = index + ":" + attr + ":" + value
- index = "updates"
+ new_value = action + ":" + attr + ":" + value
+ disposition = "updates"
+
+ disposition_list = update.setdefault(disposition, [])
+ disposition_list.append(new_value)
+
+ def emit_update(update):
+ '''
+ When processing a dn is completed emit the update by merging it into
+ the set of all updates.
+ '''
+
+ self._combine_updates(all_updates, update)
+
+ # Iterate over source input lines
+ for source_line in source_data:
+ lcount += 1
+
+ # strip trailing whitespace and newline
+ source_line = source_line.rstrip()
- d = update.get(index, [])
+ # skip comments and empty lines
+ if source_line.startswith('#') or source_line == '':
+ continue
- d.append(new_value)
+ if source_line.lower().startswith('dn:'):
+ # Starting new dn
+ if dn is not None:
+ # Emit previous dn
+ emit_item(logical_line)
+ logical_line = ''
+ emit_update(update)
+ update = {}
+
+ dn = source_line[3:].strip()
+ dn = DN(self._template_str(dn))
+ update['dn'] = dn
+ else:
+ # Process items belonging to dn
+ if dn is None:
+ raise BadSyntax, "dn is not defined in the update, data source=%s" % (data_source_name)
- update[index] = d
+ # If continuation line, append to existing logical line & continue,
+ # otherwise flush the previous item.
+ if source_line.startswith(' '):
+ logical_line += source_line[1:]
+ continue
+ else:
+ emit_item(logical_line)
+ logical_line = ''
+ logical_line = source_line
if dn is not None:
- all_updates = self.__combine_updates(dn_list, all_updates, update)
+ emit_item(logical_line)
+ logical_line = ''
+ emit_update(update)
+ update = {}
- return (all_updates, dn_list)
+ return all_updates
def create_index_task(self, attribute):
"""Create a task to update an index for an attribute"""
@@ -337,15 +425,15 @@ class LDAPUpdate:
cn = "indextask_%s_%s_%s" % (attribute, cn_uuid.time, cn_uuid.clock_seq)
dn = DN(('cn', cn), ('cn', 'index'), ('cn', 'tasks'), ('cn', 'config'))
- e = ipaldap.Entry(str(dn))
+ e = ipaldap.Entry(dn)
e.setValues('objectClass', ['top', 'extensibleObject'])
e.setValue('cn', cn)
e.setValue('nsInstance', 'userRoot')
e.setValues('nsIndexAttribute', attribute)
- root_logger.info("Creating task to index attribute: %s", attribute)
- root_logger.debug("Task id: %s", dn)
+ self.info("Creating task to index attribute: %s", attribute)
+ self.debug("Task id: %s", dn)
if self.live_run:
self.conn.addEntry(e)
@@ -356,6 +444,8 @@ class LDAPUpdate:
"""Give a task DN monitor it and wait until it has completed (or failed)
"""
+ assert isinstance(dn, DN)
+
if not self.live_run:
# If not doing this live there is nothing to monitor
return
@@ -370,10 +460,10 @@ class LDAPUpdate:
try:
entry = self.conn.getEntry(dn, ldap.SCOPE_BASE, "(objectclass=*)", attrlist)
except errors.NotFound, e:
- root_logger.error("Task not found: %s", dn)
+ self.error("Task not found: %s", dn)
return
except errors.DatabaseError, e:
- root_logger.error("Task lookup failure %s", e)
+ self.error("Task lookup failure %s", e)
return
status = entry.getValue('nstaskstatus')
@@ -383,200 +473,158 @@ class LDAPUpdate:
continue
if status.lower().find("finished") > -1:
- root_logger.info("Indexing finished")
+ self.info("Indexing finished")
break
- root_logger.debug("Indexing in progress")
+ self.debug("Indexing in progress")
time.sleep(1)
return
- def __create_default_entry(self, dn, default):
+ def _create_default_entry(self, dn, default):
"""Create the default entry from the values provided.
The return type is entity.Entity
"""
+ assert isinstance(dn, DN)
entry = ipaldap.Entry(dn)
if not default:
# This means that the entire entry needs to be created with add
- return self.__entry_to_entity(entry)
+ return self._entry_to_entity(entry)
- for line in default:
+ for item in default:
# We already do syntax-parsing so this is safe
- (k, v) = line.split(':',1)
- e = entry.getValues(k)
+ (attr, value) = item.split(':',1)
+ e = entry.getValues(attr)
if e:
# multi-valued attribute
e = list(e)
- e.append(v)
+ e.append(value)
else:
- e = v
- entry.setValues(k, e)
+ e = value
+ entry.setValues(attr, e)
- return self.__entry_to_entity(entry)
+ return self._entry_to_entity(entry)
- def __get_entry(self, dn):
+ def _get_entry(self, dn):
"""Retrieve an object from LDAP.
The return type is ipaldap.Entry
"""
+ assert isinstance(dn, DN)
searchfilter="objectclass=*"
sattrs = ["*", "aci", "attributeTypes", "objectClasses"]
scope = ldap.SCOPE_BASE
return self.conn.getList(dn, scope, searchfilter, sattrs)
- def __update_managed_entries(self):
- """Update and move legacy Managed Entry Plugins."""
-
- suffix = ipautil.realm_to_suffix(self.realm)
- searchfilter = '(objectclass=*)'
- definitions_managed_entries = []
- old_template_container = 'cn=etc,%s' % suffix
- old_definition_container = 'cn=Managed Entries,cn=plugins,cn=config'
- new = 'cn=Managed Entries,cn=etc,%s' % suffix
- sub = ['cn=Definitions,', 'cn=Templates,']
- new_managed_entries = []
- old_templates = []
- template = None
- try:
- definitions_managed_entries = self.conn.getList(old_definition_container, ldap.SCOPE_ONELEVEL, searchfilter,[])
- except errors.NotFound, e:
- return new_managed_entries
- for entry in definitions_managed_entries:
- new_definition = {}
- definition_managed_entry_updates = {}
- definitions_managed_entries
- old_definition = {'dn': entry.dn, 'deleteentry': ['dn: %s' % entry.dn]}
- old_template = entry.getValue('managedtemplate')
- entry.setValues('managedtemplate', entry.getValue('managedtemplate').replace(old_template_container, sub[1] + new))
- new_definition['dn'] = entry.dn.replace(old_definition_container, sub[0] + new)
- new_definition['default'] = str(entry).strip().replace(': ', ':').split('\n')[1:]
- definition_managed_entry_updates[new_definition['dn']] = new_definition
- definition_managed_entry_updates[old_definition['dn']] = old_definition
- old_templates.append(old_template)
- new_managed_entries.append(definition_managed_entry_updates)
- for old_template in old_templates:
- try:
- template = self.conn.getEntry(old_template, ldap.SCOPE_BASE, searchfilter,[])
- new_template = {}
- template_managed_entry_updates = {}
- old_template = {'dn': template.dn, 'deleteentry': ['dn: %s' % template.dn]}
- new_template['dn'] = template.dn.replace(old_template_container, sub[1] + new)
- new_template['default'] = str(template).strip().replace(': ', ':').split('\n')[1:]
- template_managed_entry_updates[new_template['dn']] = new_template
- template_managed_entry_updates[old_template['dn']] = old_template
- new_managed_entries.append(template_managed_entry_updates)
- except errors.NotFound, e:
- pass
- if len(new_managed_entries) > 0:
- new_managed_entries.sort(reverse=True)
-
- return new_managed_entries
-
- def __apply_updates(self, updates, entry):
- """updates is a list of changes to apply
- entry is the thing to apply them to
+ def _apply_update_disposition(self, updates, entry):
+ """
+ updates is a list of changes to apply
+ entry is the thing to apply them to
- Returns the modified entry
+ Returns the modified entry
"""
if not updates:
return entry
only = {}
- for u in updates:
+ for update in updates:
# We already do syntax-parsing so this is safe
- (utype, k, values) = u.split(':',2)
- values = self.__parse_values(values)
-
- e = entry.getValues(k)
- if not isinstance(e, list):
- if e is None:
- e = []
+ (action, attr, update_values) = update.split(':',2)
+ update_values = self._parse_values(update_values)
+
+ # If the attribute is known to be a DN convert it to a DN object.
+ # This has to be done after _parse_values() due to quoting and comma separated lists.
+ if self.conn.has_dn_syntax(attr):
+ update_values = [DN(x) for x in update_values]
+
+ entry_values = entry.getValues(attr)
+ if not isinstance(entry_values, list):
+ if entry_values is None:
+ entry_values = []
else:
- e = [e]
- for v in values:
- if utype == 'remove':
- root_logger.debug("remove: '%s' from %s, current value %s", v, k, e)
+ entry_values = [entry_values]
+ for update_value in update_values:
+ if action == 'remove':
+ self.debug("remove: '%s' from %s, current value %s", update_value, attr, entry_values)
try:
- e.remove(v)
+ entry_values.remove(update_value)
except ValueError:
- root_logger.warning("remove: '%s' not in %s", v, k)
+ self.warning("remove: '%s' not in %s", update_value, attr)
pass
- entry.setValues(k, e)
- root_logger.debug('remove: updated value %s', e)
- elif utype == 'add':
- root_logger.debug("add: '%s' to %s, current value %s", v, k, e)
+ entry.setValues(attr, entry_values)
+ self.debug('remove: updated value %s', entry_values)
+ elif action == 'add':
+ self.debug("add: '%s' to %s, current value %s", update_value, attr, entry_values)
# Remove it, ignoring errors so we can blindly add it later
try:
- e.remove(v)
+ entry_values.remove(update_value)
except ValueError:
pass
- e.append(v)
- root_logger.debug('add: updated value %s', e)
- entry.setValues(k, e)
- elif utype == 'addifnew':
- root_logger.debug("addifnew: '%s' to %s, current value %s", v, k, e)
+ entry_values.append(update_value)
+ self.debug('add: updated value %s', entry_values)
+ entry.setValues(attr, entry_values)
+ elif action == 'addifnew':
+ self.debug("addifnew: '%s' to %s, current value %s", update_value, attr, entry_values)
# Only add the attribute if it doesn't exist. Only works
# with single-value attributes.
- if len(e) == 0:
- e.append(v)
- root_logger.debug('addifnew: set %s to %s', k, e)
- entry.setValues(k, e)
- elif utype == 'addifexist':
- root_logger.debug("addifexist: '%s' to %s, current value %s", v, k, e)
+ if len(entry_values) == 0:
+ entry_values.append(update_value)
+ self.debug('addifnew: set %s to %s', attr, entry_values)
+ entry.setValues(attr, entry_values)
+ elif action == 'addifexist':
+ self.debug("addifexist: '%s' to %s, current value %s", update_value, attr, entry_values)
# Only add the attribute if the entry doesn't exist. We
# determine this based on whether it has an objectclass
if entry.getValues('objectclass'):
- e.append(v)
- root_logger.debug('addifexist: set %s to %s', k, e)
- entry.setValues(k, e)
- elif utype == 'only':
- root_logger.debug("only: set %s to '%s', current value %s", k, v, e)
- if only.get(k):
- e.append(v)
+ entry_values.append(update_value)
+ self.debug('addifexist: set %s to %s', attr, entry_values)
+ entry.setValues(attr, entry_values)
+ elif action == 'only':
+ self.debug("only: set %s to '%s', current value %s", attr, update_value, entry_values)
+ if only.get(attr):
+ entry_values.append(update_value)
else:
- e = [v]
- only[k] = True
- entry.setValues(k, e)
- root_logger.debug('only: updated value %s', e)
- elif utype == 'deleteentry':
+ entry_values = [update_value]
+ only[attr] = True
+ entry.setValues(attr, entry_values)
+ self.debug('only: updated value %s', entry_values)
+ elif action == 'deleteentry':
# skip this update type, it occurs in __delete_entries()
return None
- elif utype == 'replace':
- # v has the format "old::new"
+ elif action == 'replace':
+ # value has the format "old::new"
try:
- (old, new) = v.split('::', 1)
+ (old, new) = update_value.split('::', 1)
except ValueError:
- raise BadSyntax, "bad syntax in replace, needs to be in the format old::new in %s" % v
+ raise BadSyntax, "bad syntax in replace, needs to be in the format old::new in %s" % update_value
try:
- e.remove(old)
- e.append(new)
- root_logger.debug('replace: updated value %s', e)
- entry.setValues(k, e)
+ entry_values.remove(old)
+ entry_values.append(new)
+ self.debug('replace: updated value %s', entry_values)
+ entry.setValues(attr, entry_values)
except ValueError:
- root_logger.debug('replace: %s not found, skipping', old)
-
- self.print_entity(entry)
+ self.debug('replace: %s not found, skipping', old)
return entry
def print_entity(self, e, message=None):
"""The entity object currently lacks a str() method"""
- root_logger.debug("---------------------------------------------")
+ self.debug("---------------------------------------------")
if message:
- root_logger.debug("%s", message)
- root_logger.debug("dn: " + e.dn)
+ self.debug("%s", message)
+ self.debug("dn: %s", e.dn)
attr = e.attrList()
for a in attr:
value = e.getValues(a)
- if isinstance(value,str):
- root_logger.debug(a + ": " + value)
- else:
- root_logger.debug(a + ": ")
+ if isinstance(value, (list, tuple)):
+ self.debug('%s:', a)
for l in value:
- root_logger.debug("\t" + l)
+ self.debug("\t%s", l)
+ else:
+ self.debug('%s: %s', a, value)
def is_schema_updated(self, s):
"""Compare the schema in 's' with the current schema in the DS to
@@ -598,48 +646,59 @@ class LDAPUpdate:
s = s.ldap_entry()
# Get a fresh copy and convert into a SubSchema
- n = self.__get_entry("cn=schema")[0]
- n = dict(n.data)
- n = ldap.schema.SubSchema(n)
+ n = self._get_entry(DN(('cn', 'schema')))[0]
+
+ # Convert IPA data types back to strings
+ d = dict()
+ for k,v in n.data.items():
+ d[k] = [str(x) for x in v]
+
+ # Convert to subschema dict
+ n = ldap.schema.SubSchema(d)
n = n.ldap_entry()
+ # Are they equal?
if s == n:
return False
else:
return True
- def __update_record(self, update):
+ def _update_record(self, update):
found = False
- new_entry = self.__create_default_entry(update.get('dn'),
- update.get('default'))
+ # If the entry is going to be deleted no point in processing it.
+ if update.has_key('deleteentry'):
+ return
+
+ new_entry = self._create_default_entry(update.get('dn'),
+ update.get('default'))
try:
- e = self.__get_entry(new_entry.dn)
+ e = self._get_entry(new_entry.dn)
if len(e) > 1:
# we should only ever get back one entry
raise BadSyntax, "More than 1 entry returned on a dn search!? %s" % new_entry.dn
- entry = self.__entry_to_entity(e[0])
+ entry = self._entry_to_entity(e[0])
found = True
- root_logger.info("Updating existing entry: %s", entry.dn)
+ self.info("Updating existing entry: %s", entry.dn)
except errors.NotFound:
# Doesn't exist, start with the default entry
entry = new_entry
- root_logger.info("New entry: %s", entry.dn)
+ self.info("New entry: %s", entry.dn)
except errors.DatabaseError:
# Doesn't exist, start with the default entry
entry = new_entry
- root_logger.info("New entry, using default value: %s", entry.dn)
+ self.info("New entry, using default value: %s", entry.dn)
- self.print_entity(entry)
+ self.print_entity(entry, "Initial value")
# Bring this entry up to date
- entry = self.__apply_updates(update.get('updates'), entry)
+ entry = self._apply_update_disposition(update.get('updates'), entry)
if entry is None:
# It might be None if it is just deleting an entry
return
- self.print_entity(entry, "Final value")
+ self.print_entity(entry, "Final value after applying updates")
if not found:
# New entries get their orig_data set to the entry itself. We want to
@@ -657,47 +716,47 @@ class LDAPUpdate:
except errors.NotFound:
# parent entry of the added entry does not exist
# this may not be an error (e.g. entries in NIS container)
- root_logger.info("Parent DN of %s may not exist, cannot create the entry",
+ self.info("Parent DN of %s may not exist, cannot create the entry",
entry.dn)
return
self.modified = True
except Exception, e:
- root_logger.error("Add failure %s", e)
+ self.error("Add failure %s", e)
else:
# Update LDAP
try:
updated = False
changes = self.conn.generateModList(entry.origDataDict(), entry.toDict())
- if (entry.dn == "cn=schema"):
+ if (entry.dn == DN(('cn', 'schema'))):
updated = self.is_schema_updated(entry.toDict())
else:
if len(changes) >= 1:
updated = True
- root_logger.debug("%s" % changes)
- root_logger.debug("Live %d, updated %d" % (self.live_run, updated))
+ self.debug("%s" % changes)
+ self.debug("Live %d, updated %d" % (self.live_run, updated))
if self.live_run and updated:
self.conn.updateEntry(entry.dn, entry.origDataDict(), entry.toDict())
- root_logger.info("Done")
+ self.info("Done")
except errors.EmptyModlist:
- root_logger.info("Entry already up-to-date")
+ self.info("Entry already up-to-date")
updated = False
except errors.DatabaseError, e:
- root_logger.error("Update failed: %s", e)
+ self.error("Update failed: %s", e)
updated = False
except errors.ACIError, e:
- root_logger.error("Update failed: %s", e)
+ self.error("Update failed: %s", e)
updated = False
- if ("cn=index" in entry.dn and
- "cn=userRoot" in entry.dn):
- taskid = self.create_index_task(entry.cn)
+ if (DN(('cn', 'index')) in entry.dn and
+ DN(('cn', 'userRoot')) in entry.dn):
+ taskid = self.create_index_task(entry.getValue('cn'))
self.monitor_index_task(taskid)
if updated:
self.modified = True
return
- def __delete_record(self, updates):
+ def _delete_record(self, updates):
"""
Run through all the updates again looking for any that should be
deleted.
@@ -706,38 +765,21 @@ class LDAPUpdate:
considered first so we don't end up trying to delete a parent
and child in the wrong order.
"""
- dn = updates['dn']
- deletes = updates.get('deleteentry', [])
- for d in deletes:
- try:
- root_logger.info("Deleting entry %s", dn)
- if self.live_run:
- self.conn.deleteEntry(dn)
- self.modified = True
- except errors.NotFound, e:
- root_logger.info("%s did not exist:%s", dn, e)
- self.modified = True
- except errors.DatabaseError, e:
- root_logger.error("Delete failed: %s", e)
-
- updates = updates.get('updates', [])
- for u in updates:
- # We already do syntax-parsing so this is safe
- (utype, k, values) = u.split(':',2)
- if utype == 'deleteentry':
- try:
- root_logger.info("Deleting entry %s", dn)
- if self.live_run:
- self.conn.deleteEntry(dn)
- self.modified = True
- except errors.NotFound, e:
- root_logger.info("%s did not exist:%s", dn, e)
- self.modified = True
- except errors.DatabaseError, e:
- root_logger.error("Delete failed: %s", e)
+ if not updates.has_key('deleteentry'):
+ return
- return
+ dn = updates['dn']
+ try:
+ self.info("Deleting entry %s", dn)
+ if self.live_run:
+ self.conn.deleteEntry(dn)
+ self.modified = True
+ except errors.NotFound, e:
+ self.info("%s did not exist:%s", dn, e)
+ self.modified = True
+ except errors.DatabaseError, e:
+ self.error("Delete failed: %s", e)
def get_all_files(self, root, recursive=False):
"""Get all update files"""
@@ -761,7 +803,7 @@ class LDAPUpdate:
realm=self.realm)
try:
if self.dm_password:
- self.conn.do_simple_bind(binddn="cn=directory manager", bindpw=self.dm_password)
+ self.conn.do_simple_bind(binddn=DN(('cn', 'directory manager')), bindpw=self.dm_password)
elif os.getegid() == 0:
try:
# autobind
@@ -776,19 +818,28 @@ class LDAPUpdate:
else:
raise RuntimeError("Offline updates are not supported.")
- def __run_updates(self, dn_list, all_updates):
+ def _run_updates(self, all_updates):
# For adds and updates we want to apply updates from shortest
# to greatest length of the DN. For deletes we want the reverse.
- sortedkeys = dn_list.keys()
+
+ dn_by_rdn_count = {}
+ for dn in all_updates.keys():
+ assert isinstance(dn, DN)
+ rdn_count = len(dn)
+ rdn_count_list = dn_by_rdn_count.setdefault(rdn_count, [])
+ if dn not in rdn_count_list:
+ rdn_count_list.append(dn)
+
+ sortedkeys = dn_by_rdn_count.keys()
sortedkeys.sort()
- for k in sortedkeys:
- for dn in dn_list[k]:
- self.__update_record(all_updates[dn])
+ for rdn_count in sortedkeys:
+ for dn in dn_by_rdn_count[rdn_count]:
+ self._update_record(all_updates[dn])
sortedkeys.reverse()
- for k in sortedkeys:
- for dn in dn_list[k]:
- self.__delete_record(all_updates[dn])
+ for rdn_count in sortedkeys:
+ for dn in dn_by_rdn_count[rdn_count]:
+ self._delete_record(all_updates[dn])
def update(self, files):
"""Execute the update. files is a list of the update files to use.
@@ -796,71 +847,46 @@ class LDAPUpdate:
returns True if anything was changed, otherwise False
"""
- updates = None
+ all_updates = {}
if self.plugins:
- root_logger.info('PRE_UPDATE')
+ self.info('PRE_UPDATE')
updates = api.Backend.updateclient.update(PRE_UPDATE, self.dm_password, self.ldapi, self.live_run)
-
+ self.merge_updates(all_updates, updates)
try:
self.create_connection()
- all_updates = {}
- dn_list = {}
- # Start with any updates passed in from pre-update plugins
- if updates:
- for entry in updates:
- all_updates.update(entry)
- for upd in updates:
- for dn in upd:
- dn_explode = ldap.explode_dn(dn.lower())
- l = len(dn_explode)
- if dn_list.get(l):
- if dn not in dn_list[l]:
- dn_list[l].append(dn)
- else:
- dn_list[l] = [dn]
for f in files:
try:
- root_logger.info("Parsing file %s" % f)
+ self.info("Parsing update file '%s'" % f)
data = self.read_file(f)
except Exception, e:
- print e
+ self.error("error reading update file '%s'", f)
sys.exit(e)
- (all_updates, dn_list) = self.parse_update_file(data, all_updates, dn_list)
+ self.parse_update_file(f, data, all_updates)
- self.__run_updates(dn_list, all_updates)
+ self._run_updates(all_updates)
finally:
if self.conn: self.conn.unbind()
if self.plugins:
- root_logger.info('POST_UPDATE')
+ self.info('POST_UPDATE')
+ all_updates = {}
updates = api.Backend.updateclient.update(POST_UPDATE, self.dm_password, self.ldapi, self.live_run)
- dn_list = {}
- for upd in updates:
- for dn in upd:
- dn_explode = ldap.explode_dn(dn.lower())
- l = len(dn_explode)
- if dn_list.get(l):
- if dn not in dn_list[l]:
- dn_list[l].append(dn)
- else:
- dn_list[l] = [dn]
- self.__run_updates(dn_list, updates)
+ self.merge_updates(all_updates, updates)
+ self._run_updates(all_updates)
return self.modified
- def update_from_dict(self, dn_list, updates):
+ def update_from_dict(self, updates):
"""
Apply updates internally as opposed to from a file.
-
- dn_list is a list of dns to be updated
updates is a dictionary containing the updates
"""
if not self.conn:
self.create_connection()
- self.__run_updates(dn_list, updates)
+ self._run_updates(updates)
return self.modified
diff --git a/ipaserver/install/plugins/adtrust.py b/ipaserver/install/plugins/adtrust.py
index c32d82e3a..555a28b8f 100644
--- a/ipaserver/install/plugins/adtrust.py
+++ b/ipaserver/install/plugins/adtrust.py
@@ -20,7 +20,7 @@
from ipaserver.install.plugins import MIDDLE
from ipaserver.install.plugins.baseupdate import PostUpdate
from ipalib import api, errors
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipapython.ipa_log_manager import *
DEFAULT_ID_RANGE_SIZE = 200000
@@ -34,7 +34,7 @@ class update_default_range(PostUpdate):
def execute(self, **options):
ldap = self.obj.backend
- dn = str(DN(api.env.container_ranges, api.env.basedn))
+ dn = DN(api.env.container_ranges, api.env.basedn)
search_filter = "objectclass=ipaDomainIDRange"
try:
(entries, truncated) = ldap.find_entries(search_filter, [], dn)
@@ -44,7 +44,7 @@ class update_default_range(PostUpdate):
root_logger.debug("default_range: ipaDomainIDRange entry found, skip plugin")
return (False, False, [])
- dn = str(DN(('cn', 'admins'), api.env.container_group, api.env.basedn))
+ dn = DN(('cn', 'admins'), api.env.container_group, api.env.basedn)
try:
(dn, admins_entry) = ldap.get_entry(dn, ['gidnumber'])
except errors.NotFound:
@@ -65,12 +65,10 @@ class update_default_range(PostUpdate):
]
updates = {}
- dn = str(DN(('cn', '%s_id_range' % api.env.realm),
- api.env.container_ranges, api.env.basedn))
+ dn = DN(('cn', '%s_id_range' % api.env.realm),
+ api.env.container_ranges, api.env.basedn)
- # make sure everything is str or otherwise python-ldap would complain
- range_entry = map(str, range_entry)
- updates[dn] = {'dn' : dn, 'default' : range_entry}
+ updates[dn] = {'dn': dn, 'default': range_entry}
# Default range entry has a hard-coded range size to 200000 which is
# a default range size in ipa-server-install. This could cause issues
@@ -78,7 +76,7 @@ class update_default_range(PostUpdate):
# bigger range (option --idmax).
# We should make our best to check if this is the case and provide
# user with an information how to fix it.
- dn = str(DN(api.env.container_dna_posix_ids, api.env.basedn))
+ dn = DN(api.env.container_dna_posix_ids, api.env.basedn)
search_filter = "objectclass=dnaSharedConfig"
attrs = ['dnaHostname', 'dnaRemainingValues']
try:
diff --git a/ipaserver/install/plugins/dns.py b/ipaserver/install/plugins/dns.py
index e11c331a4..d55596704 100644
--- a/ipaserver/install/plugins/dns.py
+++ b/ipaserver/install/plugins/dns.py
@@ -21,7 +21,7 @@ from ipaserver.install.plugins import MIDDLE
from ipaserver.install.plugins.baseupdate import PostUpdate
from ipaserver.install.plugins import baseupdate
from ipalib import api, errors, util
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipalib.plugins.dns import dns_container_exists
from ipapython.ipa_log_manager import *
@@ -89,31 +89,29 @@ class update_dns_permissions(PostUpdate):
entries otherwise.
"""
- _write_dns_perm_dn = DN('cn=Write DNS Configuration',
- api.env.container_permission,
- api.env.basedn)
+ _write_dns_perm_dn = DN(('cn', 'Write DNS Configuration'),
+ api.env.container_permission, api.env.basedn)
_write_dns_perm_entry = ['objectClass:groupofnames',
'objectClass:top',
'cn:Write DNS Configuration',
'description:Write DNS Configuration',
- 'member:cn=DNS Administrators,cn=privileges,cn=pbac,%s' \
- % api.env.basedn,
- 'member:cn=DNS Servers,cn=privileges,cn=pbac,%s' \
- % api.env.basedn]
-
- _read_dns_perm_dn = DN('cn=Read DNS Entries',
- api.env.container_permission,
- api.env.basedn)
+ 'member:%s' % DN(('cn', 'DNS Administrators'), ('cn', 'privileges'), ('cn', 'pbac'),
+ api.env.basedn),
+ 'member:%s' % DN(('cn', 'DNS Servers'), ('cn', 'privileges'), ('cn', 'pbac'),
+ api.env.basedn)]
+
+ _read_dns_perm_dn = DN(('cn', 'Read DNS Entries'),
+ api.env.container_permission, api.env.basedn)
_read_dns_perm_entry = ['objectClass:top',
'objectClass:groupofnames',
'objectClass:ipapermission',
'cn:Read DNS Entries',
'description:Read DNS entries',
'ipapermissiontype:SYSTEM',
- 'member:cn=DNS Administrators,cn=privileges,cn=pbac,%s' \
- % api.env.basedn,
- 'member:cn=DNS Servers,cn=privileges,cn=pbac,%s' \
- % api.env.basedn,]
+ 'member:%s' % DN(('cn', 'DNS Administrators'), ('cn', 'privileges'), ('cn', 'pbac'),
+ api.env.basedn),
+ 'member:%s' % DN(('cn', 'DNS Servers'), ('cn', 'privileges'), ('cn', 'pbac'),
+ api.env.basedn),]
_write_dns_aci_dn = DN(api.env.basedn)
_write_dns_aci_entry = ['add:aci:\'(targetattr = "idnsforwardpolicy || idnsforwarders || idnsallowsyncptr || idnszonerefresh || idnspersistentsearch")(target = "ldap:///cn=dns,%(realm)s")(version 3.0;acl "permission:Write DNS Configuration";allow (write) groupdn = "ldap:///cn=Write DNS Configuration,cn=permissions,cn=pbac,%(realm)s";)\'' % dict(realm=api.env.basedn)]
@@ -135,10 +133,7 @@ class update_dns_permissions(PostUpdate):
(self._write_dns_aci_dn, 'updates', self._write_dns_aci_entry),
(self._read_dns_aci_dn, 'updates', self._read_dns_aci_entry)):
- dn = str(dn)
- # make sure everything is str or otherwise python-ldap would complain
- entry = map(str, entry)
- dnsupdates[dn] = {'dn' : dn, container : entry}
+ dnsupdates[dn] = {'dn': dn, container: entry}
return (False, True, [dnsupdates])
@@ -161,9 +156,9 @@ class update_dns_limits(PostUpdate):
return (False, False, [])
dns_principal = 'DNS/%s@%s' % (self.env.host, self.env.realm)
- dns_service_dn = str(DN(('krbprincipalname', dns_principal),
- self.env.container_service,
- self.env.basedn))
+ dns_service_dn = DN(('krbprincipalname', dns_principal),
+ self.env.container_service,
+ self.env.basedn)
try:
(dn, entry) = ldap.get_entry(dns_service_dn, self.limit_attributes)
diff --git a/ipaserver/install/plugins/fix_replica_memberof.py b/ipaserver/install/plugins/fix_replica_memberof.py
index 23bde0c9f..d4ab75348 100644
--- a/ipaserver/install/plugins/fix_replica_memberof.py
+++ b/ipaserver/install/plugins/fix_replica_memberof.py
@@ -44,7 +44,7 @@ class update_replica_exclude_attribute_list(PreUpdate):
entries = repl.find_replication_agreements()
self.log.debug("Found %d agreement(s)", len(entries))
for replica in entries:
- self.log.debug(replica.description)
+ self.log.debug(replica.getValue('description'))
attrlist = replica.getValue('nsDS5ReplicatedAttributeList')
if attrlist is None:
self.log.debug("Adding nsDS5ReplicatedAttributeList and nsDS5ReplicatedAttributeListTotal")
@@ -68,7 +68,7 @@ class update_replica_exclude_attribute_list(PreUpdate):
self.log.debug("Attribute list needs updating")
current = replica.toDict()
replica.setValue('nsDS5ReplicatedAttributeList',
- replica.nsDS5ReplicatedAttributeList + ' %s' % ' '.join(missing))
+ replica.getValue('nsDS5ReplicatedAttributeList') + ' %s' % ' '.join(missing))
try:
repl.conn.updateEntry(replica.dn, current, replica.toDict())
self.log.debug("Updated")
diff --git a/ipaserver/install/plugins/rename_managed.py b/ipaserver/install/plugins/rename_managed.py
index a9eed0be3..99dac8148 100644
--- a/ipaserver/install/plugins/rename_managed.py
+++ b/ipaserver/install/plugins/rename_managed.py
@@ -24,6 +24,7 @@ from ipalib.frontend import Updater
from ipaserver.install.plugins import baseupdate
from ipalib import api, errors
from ipapython import ipautil
+from ipapython.dn import DN, EditableDN
import ldap as _ldap
def entry_to_update(entry):
@@ -44,67 +45,99 @@ def entry_to_update(entry):
return update
-def generate_update(ldap, deletes=False):
- """
- We need to separate the deletes that need to happen from the
- new entries that need to be added.
- """
- suffix = ipautil.realm_to_suffix(api.env.realm)
- searchfilter = '(objectclass=*)'
- definitions_managed_entries = []
- old_template_container = 'cn=etc,%s' % suffix
- old_definition_container = 'cn=managed entries,cn=plugins,cn=config'
- new = 'cn=Managed Entries,cn=etc,%s' % suffix
- sub = ['cn=Definitions,', 'cn=Templates,']
- new_managed_entries = []
- old_templates = []
- template = None
- restart = False
-
- # If the old entries don't exist the server has already been updated.
- try:
- (definitions_managed_entries, truncated) = ldap.find_entries(
- searchfilter, ['*'], old_definition_container, _ldap.SCOPE_ONELEVEL, normalize=False
- )
- except errors.NotFound, e:
- return (False, new_managed_entries)
-
- for entry in definitions_managed_entries:
- new_definition = {}
- definition_managed_entry_updates = {}
- if deletes:
- old_definition = {'dn': str(entry[0]), 'deleteentry': ['dn: %s' % str(entry[0])]}
- old_template = str(entry[1]['managedtemplate'][0])
- definition_managed_entry_updates[old_definition['dn']] = old_definition
- old_templates.append(old_template)
- else:
- entry[1]['managedtemplate'] = str(entry[1]['managedtemplate'][0].replace(old_template_container, sub[1] + new))
- new_definition['dn'] = str(entry[0].replace(old_definition_container, sub[0] + new))
- new_definition['default'] = entry_to_update(entry[1])
- definition_managed_entry_updates[new_definition['dn']] = new_definition
- new_managed_entries.append(definition_managed_entry_updates)
- for old_template in old_templates: # Only happens when deletes is True
- try:
- (dn, template) = ldap.get_entry(old_template, ['*'], normalize=False)
- dn = str(dn)
- new_template = {}
- template_managed_entry_updates = {}
- old_template = {'dn': dn, 'deleteentry': ['dn: %s' % dn]}
- new_template['dn'] = str(dn.replace(old_template_container, sub[1] + new))
- new_template['default'] = entry_to_update(template)
- template_managed_entry_updates[new_template['dn']] = new_template
- template_managed_entry_updates[old_template['dn']] = old_template
- new_managed_entries.append(template_managed_entry_updates)
- except errors.NotFound, e:
- pass
+class GenerateUpdateMixin(object):
+ def generate_update(self, deletes=False):
+ """
+ We need to separate the deletes that need to happen from the
+ new entries that need to be added.
+ """
+ ldap = self.obj.backend
- if len(new_managed_entries) > 0:
- restart = True
- new_managed_entries.sort(reverse=True)
+ suffix = ipautil.realm_to_suffix(api.env.realm)
+ searchfilter = '(objectclass=*)'
+ definitions_managed_entries = []
- return (restart, new_managed_entries)
+ old_template_container = DN(('cn', 'etc'), suffix)
+ new_template_container = DN(('cn', 'Templates'), ('cn', 'Managed Entries'), ('cn', 'etc'), suffix)
-class update_managed_post_first(PreUpdate):
+ old_definition_container = DN(('cn', 'managed entries'), ('cn', 'plugins'), ('cn', 'config'), suffix)
+ new_definition_container = DN(('cn', 'Definitions'), ('cn', 'Managed Entries'), ('cn', 'etc'), suffix)
+
+ definitions_dn = DN(('cn', 'Definitions'))
+ update_list = []
+ restart = False
+
+ # If the old entries don't exist the server has already been updated.
+ try:
+ (definitions_managed_entries, truncated) = ldap.find_entries(
+ searchfilter, ['*'], old_definition_container, _ldap.SCOPE_ONELEVEL, normalize=False
+ )
+ except errors.NotFound, e:
+ return (False, update_list)
+
+ for entry in definitions_managed_entries:
+ assert isinstance(entry.dn, DN)
+ if deletes:
+ old_dn = entry.data['managedtemplate'][0]
+ assert isinstance(old_dn, DN)
+ try:
+ (old_dn, entry) = ldap.get_entry(old_dn, ['*'], normalize=False)
+ except errors.NotFound, e:
+ pass
+ else:
+ # Compute the new dn by replacing the old container with the new container
+ new_dn = EditableDN(old_dn)
+ if new_dn.replace(old_template_container, new_template_container) != 1:
+ self.error("unable to replace '%s' with '%s' in '%s'",
+ old_template_container, new_template_container, old_dn)
+ continue
+
+ new_dn = DN(new_dn)
+
+ # The old attributes become defaults for the new entry
+ new_update = {'dn': new_dn,
+ 'default': entry_to_update(entry)}
+
+ # Delete the old entry
+ old_update = {'dn': old_dn, 'deleteentry': None}
+
+ # Add the delete and replacement updates to the list of all updates
+ update_list.append({old_dn: old_update, new_dn: new_update})
+
+ else:
+ # Update the template dn by replacing the old containter with the new container
+ old_dn = entry.data['managedtemplate'][0]
+ new_dn = EditableDN(old_dn)
+ if new_dn.replace(old_template_container, new_template_container) != 1:
+ self.error("unable to replace '%s' with '%s' in '%s'",
+ old_template_container, new_template_container, old_dn)
+ continue
+ new_dn = DN(new_dn)
+ entry.data['managedtemplate'] = new_dn
+
+ # Edit the dn, then convert it back to an immutable DN
+ old_dn = entry.dn
+ new_dn = EditableDN(old_dn)
+ if new_dn.replace(old_definition_container, new_definition_container) != 1:
+ self.error("unable to replace '%s' with '%s' in '%s'",
+ old_definition_container, new_definition_container, old_dn)
+ continue
+ new_dn = DN(new_dn)
+
+ # The old attributes become defaults for the new entry
+ new_update = {'dn': new_dn,
+ 'default': entry_to_update(entry.data)}
+
+ # Add the replacement update to the collection of all updates
+ update_list.append({new_dn: new_update})
+
+ if len(update_list) > 0:
+ restart = True
+ update_list.sort(reverse=True)
+
+ return (restart, update_list)
+
+class update_managed_post_first(PreUpdate, GenerateUpdateMixin):
"""
Update managed entries
"""
@@ -112,21 +145,21 @@ class update_managed_post_first(PreUpdate):
def execute(self, **options):
# Never need to restart with the pre-update changes
- (ignore, new_managed_entries) = generate_update(self.obj.backend, False)
+ (ignore, update_list) = self.generate_update(False)
- return (False, True, new_managed_entries)
+ return (False, True, update_list)
api.register(update_managed_post_first)
-class update_managed_post(PostUpdate):
+class update_managed_post(PostUpdate, GenerateUpdateMixin):
"""
Update managed entries
"""
order=LAST
def execute(self, **options):
- (restart, new_managed_entries) = generate_update(self.obj.backend, True)
+ (restart, update_list) = self.generate_update(True)
- return (restart, True, new_managed_entries)
+ return (restart, True, update_list)
api.register(update_managed_post)
diff --git a/ipaserver/install/plugins/updateclient.py b/ipaserver/install/plugins/updateclient.py
index e23769471..dca2c75dd 100644
--- a/ipaserver/install/plugins/updateclient.py
+++ b/ipaserver/install/plugins/updateclient.py
@@ -25,6 +25,7 @@ from ipaserver.install.ldapupdate import LDAPUpdate
from ipapython.ipautil import wait_for_open_socket
from ipalib import api
from ipalib import backend
+from ipapython.dn import DN
import ldap as _ldap
class updateclient(backend.Executioner):
@@ -44,7 +45,7 @@ class updateclient(backend.Executioner):
updates is a dictionary keyed on dn. The value of an update is a
dictionary with the following possible values:
- - dn: str, duplicate of the key
+ - dn: DN, equal to the dn attribute
- updates: list of updates against the dn
- default: list of the default entry to be added if it doesn't
exist
@@ -103,7 +104,7 @@ class updateclient(backend.Executioner):
autobind = False
else:
autobind = True
- self.Backend.ldap2.connect(bind_dn='cn=Directory Manager', bind_pw=dm_password, autobind=autobind)
+ self.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password, autobind=autobind)
def order(self, updatetype):
"""Return plugins of the given updatetype in sorted order.
@@ -125,22 +126,12 @@ class updateclient(backend.Executioner):
(restart, apply_now, res) = self.run(update.name, **kw)
if restart:
self.restart(dm_password, live_run)
- dn_list = {}
- for upd in res:
- for dn in upd:
- dn_explode = _ldap.explode_dn(dn.lower())
- l = len(dn_explode)
- if dn_list.get(l):
- if dn not in dn_list[l]:
- dn_list[l].append(dn)
- else:
- dn_list[l] = [dn]
- updates = {}
- for entry in res:
- updates.update(entry)
if apply_now:
- ld.update_from_dict(dn_list, updates)
+ updates = {}
+ for entry in res:
+ updates.update(entry)
+ ld.update_from_dict(updates)
elif res:
result.extend(res)
diff --git a/ipaserver/install/replication.py b/ipaserver/install/replication.py
index 38abfe210..8fe73ca77 100644
--- a/ipaserver/install/replication.py
+++ b/ipaserver/install/replication.py
@@ -28,17 +28,16 @@ from ipapython import services as ipaservices
from ldap import modlist
from ipalib import api, util, errors
from ipapython import ipautil
-from ipalib.dn import DN
+from ipapython.dn import DN
-DIRMAN_CN = "cn=directory manager"
CACERT = "/etc/ipa/ca.crt"
# the default container used by AD for user entries
-WIN_USER_CONTAINER = "cn=Users"
+WIN_USER_CONTAINER = DN(('cn', 'Users'))
# the default container used by IPA for user entries
-IPA_USER_CONTAINER = "cn=users,cn=accounts"
+IPA_USER_CONTAINER = DN(('cn', 'users'), ('cn', 'accounts'))
PORT = 636
TIMEOUT = 120
-REPL_MAN_DN = "cn=replication manager,cn=config"
+REPL_MAN_DN = DN(('cn', 'replication manager'), ('cn', 'config'))
IPA_REPLICA = 1
WINSYNC = 2
@@ -94,9 +93,10 @@ def enable_replication_version_checking(hostname, realm, dirman_passwd):
conn.do_simple_bind(bindpw=dirman_passwd)
else:
conn.do_sasl_gssapi_bind()
- entry = conn.search_s('cn=IPA Version Replication,cn=plugins,cn=config', ldap.SCOPE_BASE, 'objectclass=*')
- if entry[0].getValue('nsslapd-pluginenabled') == 'off':
- conn.modify_s(entry[0].dn, [(ldap.MOD_REPLACE, 'nsslapd-pluginenabled', 'on')])
+ entry = conn.getEntry(DN(('cn', 'IPA Version Replication'), ('cn', 'plugins'), ('cn', 'config')),
+ ldap.SCOPE_BASE, 'objectclass=*')
+ if entry.getValue('nsslapd-pluginenabled') == 'off':
+ conn.modify_s(entry.dn, [(ldap.MOD_REPLACE, 'nsslapd-pluginenabled', 'on')])
conn.unbind()
serverid = "-".join(realm.split("."))
ipaservices.knownservices.dirsrv.restart(instance_name=serverid)
@@ -112,8 +112,7 @@ class ReplicationManager(object):
self.dirman_passwd = dirman_passwd
self.realm = realm
self.starttls = starttls
- tmp = ipautil.realm_to_suffix(realm)
- self.suffix = str(DN(tmp)).lower()
+ self.suffix = ipautil.realm_to_suffix(realm)
self.need_memberof_fixup = False
# The caller is allowed to pass in an existing IPAdmin connection.
@@ -150,25 +149,28 @@ class ReplicationManager(object):
"""
# First see if there is already one set
dn = self.replica_dn()
+ assert isinstance(dn, DN)
try:
- replica = conn.search_s(dn, ldap.SCOPE_BASE, "objectclass=*")[0]
+ replica = conn.getEntry(dn, ldap.SCOPE_BASE, "objectclass=*")
+ except errors.NotFound:
+ pass
+ else:
if replica.getValue('nsDS5ReplicaId'):
return int(replica.getValue('nsDS5ReplicaId'))
- except ldap.NO_SUCH_OBJECT:
- pass
# Ok, either the entry doesn't exist or the attribute isn't set
# so get it from the other master
retval = -1
- dn = str(DN(('cn','replication'),('cn','etc'), self.suffix))
+ dn = DN(('cn','replication'),('cn','etc'), self.suffix)
try:
- replica = master_conn.search_s(dn, ldap.SCOPE_BASE, "objectclass=*")[0]
- if not replica.getValue('nsDS5ReplicaId'):
- root_logger.debug("Unable to retrieve nsDS5ReplicaId from remote server")
- raise RuntimeError("Unable to retrieve nsDS5ReplicaId from remote server")
- except ldap.NO_SUCH_OBJECT:
+ replica = master_conn.getEntry(dn, ldap.SCOPE_BASE, "objectclass=*")
+ except errors.NotFound:
root_logger.debug("Unable to retrieve nsDS5ReplicaId from remote server")
raise
+ else:
+ if replica.getValue('nsDS5ReplicaId') is None:
+ root_logger.debug("Unable to retrieve nsDS5ReplicaId from remote server")
+ raise RuntimeError("Unable to retrieve nsDS5ReplicaId from remote server")
# Now update the value on the master
retval = int(replica.getValue('nsDS5ReplicaId'))
@@ -195,8 +197,9 @@ class ReplicationManager(object):
"""
filt = "(|(objectclass=nsDSWindowsReplicationAgreement)(objectclass=nsds5ReplicationAgreement))"
try:
- ents = self.conn.search_s("cn=mapping tree,cn=config", ldap.SCOPE_SUBTREE, filt)
- except ldap.NO_SUCH_OBJECT:
+ ents = self.conn.getList(DN(('cn', 'mapping tree'), ('cn', 'config')),
+ ldap.SCOPE_SUBTREE, filt)
+ except errors.NotFound:
ents = []
return ents
@@ -212,13 +215,13 @@ class ReplicationManager(object):
filt = "(objectclass=nsds5ReplicationAgreement)"
try:
- ents = self.conn.search_s("cn=mapping tree,cn=config",
- ldap.SCOPE_SUBTREE, filt)
- except ldap.NO_SUCH_OBJECT:
+ ents = self.conn.getList(DN(('cn', 'mapping tree'), ('cn', 'config')),
+ ldap.SCOPE_SUBTREE, filt)
+ except errors.NotFound:
return res
for ent in ents:
- res.append(ent.nsds5replicahost)
+ res.append(ent.getValue('nsds5replicahost'))
return res
@@ -234,24 +237,23 @@ class ReplicationManager(object):
filt = "(&(|(objectclass=nsds5ReplicationAgreement)(objectclass=nsDSWindowsReplicationAgreement))(nsDS5ReplicaHost=%s))" % hostname
try:
- entry = self.conn.search_s("cn=mapping tree,cn=config",
- ldap.SCOPE_SUBTREE, filt)
- except ldap.NO_SUCH_OBJECT:
+ entries = self.conn.getList(DN(('cn', 'mapping tree'), ('cn', 'config')),
+ ldap.SCOPE_SUBTREE, filt)
+ except errors.NotFound:
return None
- if len(entry) == 0:
+ if len(entries) == 0:
return None
else:
- return entry[0] # There can be only one
+ return entries[0] # There can be only one
def add_replication_manager(self, conn, dn, pw):
"""
Create a pseudo user to use for replication.
"""
-
- edn = ldap.dn.str2dn(dn)
- rdn_attr = edn[0][0][0]
- rdn_val = edn[0][0][1]
+ assert isinstance(dn, DN)
+ rdn_attr = dn[0].attr
+ rdn_val = dn[0].value
ent = ipaldap.Entry(dn)
ent.setValues("objectclass", "top", "person")
@@ -266,6 +268,7 @@ class ReplicationManager(object):
pass
def delete_replication_manager(self, conn, dn=REPL_MAN_DN):
+ assert isinstance(dn, DN)
try:
conn.delete_s(dn)
except ldap.NO_SUCH_OBJECT:
@@ -278,16 +281,18 @@ class ReplicationManager(object):
return "2"
def replica_dn(self):
- return str(DN(('cn','replica'),('cn',self.suffix),('cn','mapping tree'),('cn','config')))
+ return DN(('cn','replica'),('cn',self.suffix),('cn','mapping tree'),('cn','config'))
def replica_config(self, conn, replica_id, replica_binddn):
+ assert isinstance(replica_binddn, DN)
dn = self.replica_dn()
+ assert isinstance(dn, DN)
try:
entry = conn.getEntry(dn, ldap.SCOPE_BASE)
managers = entry.getValues('nsDS5ReplicaBindDN')
for m in managers:
- if DN(replica_binddn) == DN(m):
+ if replica_binddn == DN(m):
return
# Add the new replication manager
mod = [(ldap.MOD_ADD, 'nsDS5ReplicaBindDN', replica_binddn)]
@@ -303,7 +308,7 @@ class ReplicationManager(object):
entry = ipaldap.Entry(dn)
entry.setValues('objectclass', "top", "nsds5replica", "extensibleobject")
entry.setValues('cn', "replica")
- entry.setValues('nsds5replicaroot', self.suffix)
+ entry.setValues('nsds5replicaroot', str(self.suffix))
entry.setValues('nsds5replicaid', str(replica_id))
entry.setValues('nsds5replicatype', replica_type)
entry.setValues('nsds5flags', "1")
@@ -313,7 +318,7 @@ class ReplicationManager(object):
conn.addEntry(entry)
def setup_changelog(self, conn):
- dn = "cn=changelog5, cn=config"
+ dn = DN(('cn', 'changelog5'), ('cn', 'config'))
dirpath = conn.dbdir + "/cldb"
entry = ipaldap.Entry(dn)
entry.setValues('objectclass', "top", "extensibleobject")
@@ -325,7 +330,7 @@ class ReplicationManager(object):
return
def setup_chaining_backend(self, conn):
- chaindn = "cn=chaining database, cn=plugins, cn=config"
+ chaindn = DN(('cn', 'chaining database'), ('cn', 'plugins'), ('cn', 'config'))
benamebase = "chaindb"
urls = [self.to_ldap_url(conn)]
cn = ""
@@ -334,11 +339,11 @@ class ReplicationManager(object):
while not done:
try:
cn = benamebase + str(benum) # e.g. localdb1
- dn = "cn=" + cn + ", " + chaindn
+ dn = DN(('cn', cn), chaindn)
entry = ipaldap.Entry(dn)
entry.setValues('objectclass', 'top', 'extensibleObject', 'nsBackendInstance')
entry.setValues('cn', cn)
- entry.setValues('nsslapd-suffix', self.suffix)
+ entry.setValues('nsslapd-suffix', str(self.suffix))
entry.setValues('nsfarmserverurl', urls)
entry.setValues('nsmultiplexorbinddn', self.repl_man_dn)
entry.setValues('nsmultiplexorcredentials', self.repl_man_passwd)
@@ -365,7 +370,7 @@ class ReplicationManager(object):
def get_mapping_tree_entry(self):
try:
- entry = self.conn.getEntry("cn=mapping tree,cn=config", ldap.SCOPE_ONELEVEL,
+ entry = self.conn.getEntry(DN(('cn', 'mapping tree'), ('cn', 'config')), ldap.SCOPE_ONELEVEL,
"(cn=\"%s\")" % (self.suffix))
except errors.NotFound, e:
root_logger.debug("failed to find mappting tree entry for %s" % self.suffix)
@@ -378,7 +383,7 @@ class ReplicationManager(object):
mtent = self.get_mapping_tree_entry()
dn = mtent.dn
- plgent = self.conn.getEntry("cn=Multimaster Replication Plugin,cn=plugins,cn=config",
+ plgent = self.conn.getEntry(DN(('cn', 'Multimaster Replication Plugin'), ('cn', 'plugins'), ('cn', 'config')),
ldap.SCOPE_BASE, "(objectclass=*)", ['nsslapd-pluginPath'])
path = plgent.getValue('nsslapd-pluginPath')
@@ -397,7 +402,7 @@ class ReplicationManager(object):
self.enable_chain_on_update(chainbe)
def add_passsync_user(self, conn, password):
- pass_dn = "uid=passsync,cn=sysaccounts,cn=etc,%s" % self.suffix
+ pass_dn = DN(('uid', 'passsync'), ('cn', 'sysaccounts'), ('cn', 'etc'), self.suffix)
print "The user for the Windows PassSync service is %s" % pass_dn
try:
conn.getEntry(pass_dn, ldap.SCOPE_BASE)
@@ -414,7 +419,7 @@ class ReplicationManager(object):
conn.addEntry(entry)
# Add it to the list of users allowed to bypass password policy
- extop_dn = "cn=ipa_pwd_extop,cn=plugins,cn=config"
+ extop_dn = DN(('cn', 'ipa_pwd_extop'), ('cn', 'plugins'), ('cn', 'config'))
entry = conn.getEntry(extop_dn, ldap.SCOPE_BASE)
pass_mgrs = entry.getValues('passSyncManagersDNs')
if not pass_mgrs:
@@ -435,9 +440,9 @@ class ReplicationManager(object):
def setup_winsync_agmt(self, entry, win_subtree=None):
if win_subtree is None:
- win_subtree = WIN_USER_CONTAINER + "," + self.ad_suffix
- ds_subtree = IPA_USER_CONTAINER + "," + self.suffix
- windomain = '.'.join(ldap.explode_dn(self.suffix, 1))
+ win_subtree = DN(WIN_USER_CONTAINER, self.ad_suffix)
+ ds_subtree = DN(IPA_USER_CONTAINER, self.suffix)
+ windomain = ipautil.suffix_to_realm(self.suffix)
entry.setValues("objectclass", "nsDSWindowsReplicationAgreement")
entry.setValues("nsds7WindowsReplicaSubtree", win_subtree)
@@ -454,7 +459,7 @@ class ReplicationManager(object):
tell which side we want.
"""
cn = "meTo%s" % (hostname)
- dn = "cn=%s, %s" % (cn, self.replica_dn())
+ dn = DN(('cn', cn), self.replica_dn())
return (cn, dn)
@@ -469,6 +474,9 @@ class ReplicationManager(object):
isn't a dogtag replication agreement.
"""
+ if repl_man_dn is not None:
+ assert isinstance(repl_man_dn, DN)
+
cn, dn = self.agreement_dn(b_hostname, master=master)
try:
a_conn.getEntry(dn, ldap.SCOPE_BASE)
@@ -482,7 +490,7 @@ class ReplicationManager(object):
entry.setValues('nsds5replicahost', b_hostname)
entry.setValues('nsds5replicaport', str(port))
entry.setValues('nsds5replicatimeout', str(TIMEOUT))
- entry.setValues('nsds5replicaroot', self.suffix)
+ entry.setValues('nsds5replicaroot', str(self.suffix))
if master is None:
entry.setValues('nsDS5ReplicatedAttributeList',
'(objectclass=*) $ EXCLUDE %s' % " ".join(EXCLUDES))
@@ -538,10 +546,15 @@ class ReplicationManager(object):
while (retries > 0 ):
root_logger.info('Getting ldap service principals for conversion: %s and %s' % (filter_a, filter_b))
- a_entry = b.search_s(self.suffix, ldap.SCOPE_SUBTREE,
- filterstr=filter_a)
- b_entry = a.search_s(self.suffix, ldap.SCOPE_SUBTREE,
- filterstr=filter_b)
+ try:
+ a_entry = b.search_s(self.suffix, ldap.SCOPE_SUBTREE, filterstr=filter_a)
+ except errors.NotFound:
+ pass
+
+ try:
+ b_entry = a.search_s(self.suffix, ldap.SCOPE_SUBTREE, filterstr=filter_b)
+ except errors.NotFound:
+ pass
if a_entry and b_entry:
root_logger.debug('Found both principals.')
@@ -578,7 +591,10 @@ class ReplicationManager(object):
"""
rep_dn = self.replica_dn()
+ assert isinstance(rep_dn, DN)
(a_dn, b_dn) = self.get_replica_principal_dns(a, b, retries=10)
+ assert isinstance(a_dn, DN)
+ assert isinstance(b_dn, DN)
# Add kerberos principal DNs as valid bindDNs for replication
try:
@@ -623,12 +639,10 @@ class ReplicationManager(object):
return self.conn.deleteEntry(dn)
def delete_referral(self, hostname):
- esc1_suffix = self.suffix.replace('=', '\\3D').replace(',', '\\2C')
- esc2_suffix = self.suffix.replace('=', '%3D').replace(',', '%2C')
- dn = 'cn=%s,cn=mapping tree,cn=config' % esc1_suffix
+ dn = DN(('cn', self.suffix), ('cn', 'mapping tree'), ('cn', 'config'))
# TODO: should we detect proto/port somehow ?
mod = [(ldap.MOD_DELETE, 'nsslapd-referral',
- 'ldap://%s/%s' % (ipautil.format_netloc(hostname, 389), esc2_suffix))]
+ 'ldap://%s/%s' % (ipautil.format_netloc(hostname, 389), self.suffix))]
try:
self.conn.modify_s(dn, mod)
@@ -648,9 +662,9 @@ class ReplicationManager(object):
print "Error reading status from agreement", agmtdn
hasError = 1
else:
- refresh = entry.nsds5BeginReplicaRefresh
- inprogress = entry.nsds5replicaUpdateInProgress
- status = entry.nsds5ReplicaLastInitStatus
+ refresh = entry.getValue('nsds5BeginReplicaRefresh')
+ inprogress = entry.getValue('nsds5replicaUpdateInProgress')
+ status = entry.getValue('nsds5ReplicaLastInitStatus')
if not refresh: # done - check status
if not status:
print "No status yet"
@@ -683,10 +697,10 @@ class ReplicationManager(object):
print "Error reading status from agreement", agmtdn
hasError = 1
else:
- inprogress = entry.nsds5replicaUpdateInProgress
- status = entry.nsds5ReplicaLastUpdateStatus
- start = entry.nsds5ReplicaLastUpdateStart
- end = entry.nsds5ReplicaLastUpdateEnd
+ inprogress = entry.getValue('nsds5replicaUpdateInProgress')
+ status = entry.getValue('nsds5ReplicaLastUpdateStatus')
+ start = entry.getValue('nsds5ReplicaLastUpdateStart')
+ end = entry.getValue('nsds5ReplicaLastUpdateEnd')
# incremental update is done if inprogress is false and end >= start
done = inprogress and inprogress.lower() == 'false' and start and end and (start <= end)
root_logger.info("Replication Update in progress: %s: status: %s: start: %s: end: %s" %
@@ -733,6 +747,7 @@ class ReplicationManager(object):
return self.wait_for_repl_init(conn, dn)
def basic_replication_setup(self, conn, replica_id, repldn, replpw):
+ assert isinstance(repldn, DN)
if replpw is not None:
self.add_replication_manager(conn, repldn, replpw)
self.replica_config(conn, replica_id, repldn)
@@ -741,6 +756,7 @@ class ReplicationManager(object):
def setup_replication(self, r_hostname, r_port=389, r_sslport=636,
r_binddn=None, r_bindpw=None, starttls=False,
is_cs_replica=False):
+ assert isinstance(r_binddn, DN)
# note - there appears to be a bug in python-ldap - it does not
# allow connections using two different CA certs
if starttls:
@@ -836,7 +852,7 @@ class ReplicationManager(object):
root_logger.info("Agreement is ready, starting replication . . .")
# Add winsync replica to the public DIT
- dn = str(DN(('cn',ad_dc_name),('cn','replicas'),('cn','ipa'),('cn','etc'), self.suffix))
+ dn = DN(('cn',ad_dc_name),('cn','replicas'),('cn','ipa'),('cn','etc'), self.suffix)
entry = ipaldap.Entry(dn)
entry.setValues("objectclass", ["nsContainer", "ipaConfigObject"])
entry.setValues("cn", ad_dc_name)
@@ -910,17 +926,17 @@ class ReplicationManager(object):
filter = '(&(nsDS5ReplicaHost=%s)' \
'(|(objectclass=nsDSWindowsReplicationAgreement)' \
'(objectclass=nsds5ReplicationAgreement)))' % hostname
- entry = conn.search_s("cn=config", ldap.SCOPE_SUBTREE, filter)
- if len(entry) == 0:
+ entries = conn.getList(DN(('cn', 'config')), ldap.SCOPE_SUBTREE, filter)
+ if len(entries) == 0:
root_logger.error("Unable to find replication agreement for %s" %
(hostname))
raise RuntimeError("Unable to proceed")
- if len(entry) > 1:
+ if len(entries) > 1:
root_logger.error("Found multiple agreements for %s" % hostname)
- root_logger.error("Using the first one only (%s)" % entry[0].dn)
+ root_logger.error("Using the first one only (%s)" % entries[0].dn)
- dn = entry[0].dn
- schedule = entry[0].nsds5replicaupdateschedule
+ dn = entries[0].dn
+ schedule = entries[0].getValue('nsds5replicaupdateschedule')
# On the remote chance of a match. We force a synch to happen right
# now by setting the schedule to something and quickly removing it.
@@ -965,16 +981,14 @@ class ReplicationManager(object):
# delete master kerberos key and all its svc principals
try:
filter='(krbprincipalname=*/%s@%s)' % (replica, realm)
- entries = self.conn.search_s(self.suffix, ldap.SCOPE_SUBTREE,
- filterstr=filter)
+ entries = self.conn.getList(self.suffix, ldap.SCOPE_SUBTREE,
+ filterstr=filter)
if len(entries) != 0:
dnset = self.conn.get_dns_sorted_by_length(entries,
reverse=True)
for dns in dnset:
for dn in dns:
self.conn.deleteEntry(dn)
- except ldap.NO_SUCH_OBJECT:
- pass
except errors.NotFound:
pass
except Exception, e:
@@ -984,18 +998,18 @@ class ReplicationManager(object):
err = e
# remove replica memberPrincipal from s4u2proxy configuration
- dn1 = DN(u'cn=ipa-http-delegation', api.env.container_s4u2proxy, self.suffix)
+ dn1 = DN(('cn', 'ipa-http-delegation'), api.env.container_s4u2proxy, self.suffix)
member_principal1 = "HTTP/%(fqdn)s@%(realm)s" % dict(fqdn=replica, realm=realm)
- dn2 = DN(u'cn=ipa-ldap-delegation-targets', api.env.container_s4u2proxy, self.suffix)
+ dn2 = DN(('cn', 'ipa-ldap-delegation-targets'), api.env.container_s4u2proxy, self.suffix)
member_principal2 = "ldap/%(fqdn)s@%(realm)s" % dict(fqdn=replica, realm=realm)
- dn3 = DN(u'cn=ipa-cifs-delegation-targets', api.env.container_s4u2proxy, self.suffix)
+ dn3 = DN(('cn', 'ipa-cifs-delegation-targets'), api.env.container_s4u2proxy, self.suffix)
member_principal3 = "cifs/%(fqdn)s@%(realm)s" % dict(fqdn=replica, realm=realm)
- for (dn, member_principal) in ((str(dn1), member_principal1),
- (str(dn2), member_principal2),
- (str(dn3), member_principal3)):
+ for (dn, member_principal) in ((dn1, member_principal1),
+ (dn2, member_principal2),
+ (dn3, member_principal3)):
try:
mod = [(ldap.MOD_DELETE, 'memberPrincipal', member_principal)]
self.conn.modify_s(dn, mod)
@@ -1010,16 +1024,14 @@ class ReplicationManager(object):
# delete master entry with all active services
try:
- dn = 'cn=%s,cn=masters,cn=ipa,cn=etc,%s' % (replica, self.suffix)
- entries = self.conn.search_s(dn, ldap.SCOPE_SUBTREE)
+ dn = DN(('cn', replica), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), self.suffix)
+ entries = self.conn.getList(dn, ldap.SCOPE_SUBTREE)
if len(entries) != 0:
dnset = self.conn.get_dns_sorted_by_length(entries,
reverse=True)
for dns in dnset:
for dn in dns:
self.conn.deleteEntry(dn)
- except ldap.NO_SUCH_OBJECT:
- pass
except errors.NotFound:
pass
except Exception, e:
@@ -1029,15 +1041,13 @@ class ReplicationManager(object):
err = e
try:
- basedn = 'cn=etc,%s' % self.suffix
+ basedn = DN(('cn', 'etc'), self.suffix)
filter = '(dnaHostname=%s)' % replica
- entries = self.conn.search_s(basedn, ldap.SCOPE_SUBTREE,
- filterstr=filter)
+ entries = self.conn.getList(basedn, ldap.SCOPE_SUBTREE,
+ filterstr=filter)
if len(entries) != 0:
for e in entries:
self.conn.deleteEntry(e.dn)
- except ldap.NO_SUCH_OBJECT:
- pass
except errors.NotFound:
pass
except Exception, e:
@@ -1047,18 +1057,16 @@ class ReplicationManager(object):
err = e
try:
- dn = 'cn=default,ou=profile,%s' % self.suffix
- ret = self.conn.search_s(dn, ldap.SCOPE_BASE,
- '(objectclass=*)')[0]
- srvlist = ret.data.get('defaultServerList')
- if len(srvlist) > 0:
- srvlist = srvlist[0].split()
+ dn = DN(('cn', 'default'), ('ou', 'profile'), self.suffix)
+ ret = self.conn.getEntry(dn, ldap.SCOPE_BASE, '(objectclass=*)')
+ srvlist = ret.getValue('defaultServerList', '')
+ srvlist = srvlist[0].split()
if replica in srvlist:
srvlist.remove(replica)
attr = ' '.join(srvlist)
mod = [(ldap.MOD_REPLACE, 'defaultServerList', attr)]
self.conn.modify_s(dn, mod)
- except ldap.NO_SUCH_OBJECT:
+ except errors.NotFound:
pass
except ldap.NO_SUCH_ATTRIBUTE:
pass
diff --git a/ipaserver/install/service.py b/ipaserver/install/service.py
index 198cb3870..dcfcbc27f 100644
--- a/ipaserver/install/service.py
+++ b/ipaserver/install/service.py
@@ -25,6 +25,7 @@ from ipapython import sysrestore
from ipapython import ipautil
from ipapython import services as ipaservices
from ipalib import errors
+from ipapython.dn import DN
import ldap
from ipaserver import ipaldap
import base64
@@ -78,7 +79,7 @@ class Service(object):
self.sstore = sysrestore.StateFile('/var/lib/ipa/sysrestore')
self.realm = None
- self.suffix = None
+ self.suffix = DN()
self.principal = None
self.dercert = None
@@ -150,7 +151,7 @@ class Service(object):
# use URI of admin connection
if not self.admin_conn:
self.ldap_connect()
- args += ["-H", self.admin_conn._uri]
+ args += ["-H", self.admin_conn.uri]
auth_parms = []
if self.dm_password:
@@ -183,15 +184,15 @@ class Service(object):
cn=kerberos to cn=services
"""
- dn = "krbprincipalname=%s,cn=%s,cn=kerberos,%s" % (principal, self.realm, self.suffix)
+ dn = DN(('krbprincipalname', principal), ('cn', self.realm), ('cn', 'kerberos'), self.suffix)
try:
entry = self.admin_conn.getEntry(dn, ldap.SCOPE_BASE)
except errors.NotFound:
# There is no service in the wrong location, nothing to do.
# This can happen when installing a replica
- return
- newdn = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (principal, self.suffix)
- hostdn = "fqdn=%s,cn=computers,cn=accounts,%s" % (self.fqdn, self.suffix)
+ return None
+ newdn = DN(('krbprincipalname', principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix)
+ hostdn = DN(('fqdn', self.fqdn), ('cn', 'computers'), ('cn', 'accounts'), self.suffix)
self.admin_conn.deleteEntry(dn)
entry.dn = newdn
classes = entry.getValues("objectclass")
@@ -211,8 +212,8 @@ class Service(object):
if not self.admin_conn:
self.ldap_connect()
- dn = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (principal, self.suffix)
- hostdn = "fqdn=%s,cn=computers,cn=accounts,%s" % (self.fqdn, self.suffix)
+ dn = DN(('krbprincipalname', principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix)
+ hostdn = DN(('fqdn', self.fqdn), ('cn', 'computers'), ('cn', 'accounts'), self.suffix)
entry = ipaldap.Entry(dn)
entry.setValues("objectclass", ["krbprincipal", "krbprincipalaux", "krbticketpolicyaux", "ipaobject", "ipaservice", "pkiuser"])
entry.setValue("krbprincipalname", principal)
@@ -242,7 +243,7 @@ class Service(object):
self.ldap_disconnect()
self.ldap_connect()
- dn = "krbprincipalname=%s,cn=services,cn=accounts,%s" % (self.principal, self.suffix)
+ dn = DN(('krbprincipalname', self.principal), ('cn', 'services'), ('cn', 'accounts'), self.suffix)
mod = [(ldap.MOD_ADD, 'userCertificate', self.dercert)]
try:
self.admin_conn.modify_s(dn, mod)
@@ -327,13 +328,12 @@ class Service(object):
self.steps = []
def ldap_enable(self, name, fqdn, dm_password, ldap_suffix):
+ assert isinstance(ldap_suffix, DN)
self.disable()
if not self.admin_conn:
self.ldap_connect()
- entry_name = "cn=%s,cn=%s,%s,%s" % (name, fqdn,
- "cn=masters,cn=ipa,cn=etc",
- ldap_suffix)
+ entry_name = DN(('cn', name), ('cn', fqdn), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), ldap_suffix)
order = SERVICE_LIST[name][1]
entry = ipaldap.Entry(entry_name)
entry.setValues("objectclass",
@@ -362,6 +362,8 @@ class SimpleServiceInstance(Service):
self.step("configuring %s to start on boot" % self.service_name, self.__enable)
self.start_creation("Configuring %s" % self.service_name)
+ suffix = ipautil.dn_attribute_property('_ldap_suffix')
+
def __start(self):
self.backup_state("running", self.is_running())
self.restart()
diff --git a/ipaserver/ipaldap.py b/ipaserver/ipaldap.py
index e4fa2c644..2e1b91a56 100644
--- a/ipaserver/ipaldap.py
+++ b/ipaserver/ipaldap.py
@@ -34,9 +34,11 @@ import ldap.sasl
import ldapurl
from ldap.controls import LDAPControl
from ldap.ldapobject import SimpleLDAPObject
+from ipapython.ipa_log_manager import *
from ipapython import ipautil
from ipalib import errors
from ipapython.ipautil import format_netloc, wait_for_open_socket, wait_for_open_ports
+from ipapython.dn import DN
from ipapython.entity import Entity
from ipaserver.plugins.ldap2 import IPASimpleLDAPObject
@@ -92,7 +94,7 @@ class Entry:
a list of values. In python-ldap, entries are returned as a list of
2-tuples. Instance variables:
- * dn - string - the string DN of the entry
+ * dn - DN object - the DN of the entry
* data - CIDict - case insensitive dict of the attributes and values
"""
def __init__(self,entrydata):
@@ -103,13 +105,22 @@ class Entry:
if isinstance(entrydata,tuple):
self.dn = entrydata[0]
self.data = ipautil.CIDict(entrydata[1])
- elif isinstance(entrydata,str) or isinstance(entrydata,unicode):
+ elif isinstance(entrydata,DN):
self.dn = entrydata
self.data = ipautil.CIDict()
+ elif isinstance(entrydata, basestring):
+ self.dn = DN(entrydata)
+ self.data = ipautil.CIDict()
+ else:
+ raise TypeError("entrydata must be 2-tuple, DN, or basestring, got %s" % type(entrydata))
else:
- self.dn = ''
+ self.dn = DN()
self.data = ipautil.CIDict()
+ assert isinstance(self.dn, DN)
+
+ dn = ipautil.dn_attribute_property('_dn')
+
def __nonzero__(self):
"""This allows us to do tests like if entry: returns false if there is no data,
true otherwise"""
@@ -119,23 +130,16 @@ class Entry:
"""Return True if this entry has an attribute named name, False otherwise"""
return self.data and self.data.has_key(name)
- def __getattr__(self,name):
- """If name is the name of an LDAP attribute, return the first value for that
- attribute - equivalent to getValue - this allows the use of
- entry.cn
- instead of
- entry.getValue('cn')
- This also allows us to return None if an attribute is not found rather than
- throwing an exception"""
- return self.getValue(name)
-
def getValues(self,name):
"""Get the list (array) of values for the attribute named name"""
return self.data.get(name)
- def getValue(self,name):
+ def getValue(self,name, default=None):
"""Get the first value for the attribute named name"""
- return self.data.get(name,[None])[0]
+ value = self.data.get(name, default)
+ if isinstance(value, (list, tuple)):
+ return value[0]
+ return value
def setValue(self, name, *value):
"""
@@ -179,6 +183,7 @@ class Entry:
def toDict(self):
"""Convert the attrs and values to a dict. The dict is keyed on the
attribute name. The value is either single value or a list of values."""
+ assert isinstance(self.dn, DN)
result = ipautil.CIDict(self.data)
for i in result.keys():
result[i] = ipautil.utf8_encode_values(result[i])
@@ -206,7 +211,7 @@ class Entry:
# (1000)
newdata = {}
newdata.update(self.data)
- ldif.LDIFWriter(sio,Entry.base64_attrs,1000).unparse(self.dn,newdata)
+ ldif.LDIFWriter(sio,Entry.base64_attrs,1000).unparse(str(self.dn),newdata)
return sio.getvalue()
class IPAdmin(IPAEntryLDAPObject):
@@ -233,6 +238,7 @@ class IPAdmin(IPAEntryLDAPObject):
that we can call it from places other than instance creation
e.g. when we just need to reconnect
"""
+ log_mgr.get_logger(self, True)
if debug and debug.lower() == "on":
ldap.set_option(ldap.OPT_DEBUG_LEVEL,255)
if cacert is not None:
@@ -251,7 +257,6 @@ class IPAdmin(IPAEntryLDAPObject):
self.ldapi = ldapi
self.realm = realm
self.suffixes = {}
- self.schema = None
self.__localinit()
def __lateinit(self):
@@ -260,7 +265,7 @@ class IPAdmin(IPAEntryLDAPObject):
values.
"""
try:
- ent = self.getEntry('cn=config,cn=ldbm database,cn=plugins,cn=config',
+ ent = self.getEntry(DN(('cn', 'config'), ('cn', 'ldbm database'), ('cn', 'plugins'), ('cn', 'config')),
ldap.SCOPE_BASE, '(objectclass=*)',
[ 'nsslapd-directory' ])
@@ -299,6 +304,9 @@ class IPAdmin(IPAEntryLDAPObject):
if not isinstance(e,ldap.TIMEOUT):
desc = e.args[0]['desc'].strip()
info = e.args[0].get('info','').strip()
+ arg_desc = kw.get('arg_desc')
+ if arg_desc is not None:
+ info += " arguments: %s" % arg_desc
else:
desc = ''
info = ''
@@ -334,7 +342,7 @@ class IPAdmin(IPAEntryLDAPObject):
raise errors.DatabaseError(desc=desc,info=info)
def __wait_for_connection(self, timeout):
- lurl = ldapurl.LDAPUrl(self._uri)
+ lurl = ldapurl.LDAPUrl(self.uri)
if lurl.urlscheme == 'ldapi':
wait_for_open_socket(lurl.hostport, timeout)
else:
@@ -365,25 +373,25 @@ class IPAdmin(IPAEntryLDAPObject):
try:
if krbccache is not None:
os.environ["KRB5CCNAME"] = krbccache
- self.sasl_interactive_bind_s("", SASL_AUTH)
+ self.sasl_interactive_bind_s(None, SASL_AUTH)
self.principal = principal
self.proxydn = None
except ldap.LDAPError, e:
self.__handle_errors(e)
- def do_simple_bind(self, binddn="cn=directory manager", bindpw="", timeout=DEFAULT_TIMEOUT):
- self.binddn = binddn
+ def do_simple_bind(self, binddn=DN(('cn', 'directory manager')), bindpw="", timeout=DEFAULT_TIMEOUT):
+ self.binddn = binddn # FIXME, self.binddn & self.bindpwd never referenced.
self.bindpwd = bindpw
self.__bind_with_wait(self.simple_bind_s, timeout, binddn, bindpw)
self.__lateinit()
def do_sasl_gssapi_bind(self, timeout=DEFAULT_TIMEOUT):
- self.__bind_with_wait(self.sasl_interactive_bind_s, timeout, '', SASL_AUTH)
+ self.__bind_with_wait(self.sasl_interactive_bind_s, timeout, None, SASL_AUTH)
self.__lateinit()
def do_external_bind(self, user_name=None, timeout=DEFAULT_TIMEOUT):
auth_tokens = ldap.sasl.external(user_name)
- self.__bind_with_wait(self.sasl_interactive_bind_s, timeout, '', auth_tokens)
+ self.__bind_with_wait(self.sasl_interactive_bind_s, timeout, None, auth_tokens)
self.__lateinit()
def getEntry(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
@@ -491,13 +499,15 @@ class IPAdmin(IPAEntryLDAPObject):
self.set_option(ldap.OPT_SERVER_CONTROLS, sctrl)
self.add_s(entry.dn, entry.toTupleList())
except ldap.LDAPError, e:
- arg_desc = 'entry=%s' % (entry.toTupleList())
+ arg_desc = 'entry=%s: %s' % (entry.dn, entry.toTupleList())
self.__handle_errors(e, arg_desc=arg_desc)
return True
def updateRDN(self, dn, newrdn):
"""Wrap the modrdn function."""
+ assert isinstance(dn, DN)
+ assert isinstance(newrdn, DN)
sctrl = self.__get_server_controls()
if dn == newrdn:
@@ -516,6 +526,7 @@ class IPAdmin(IPAEntryLDAPObject):
"""This wraps the mod function. It assumes that the entry is already
populated with all of the desired objectclasses and attributes"""
+ assert isinstance(dn, DN)
sctrl = self.__get_server_controls()
modlist = self.generateModList(oldentry, newentry)
@@ -575,7 +586,7 @@ class IPAdmin(IPAEntryLDAPObject):
# You can't remove schema online. An add will automatically
# replace any existing schema.
- if old_entry.get('dn') == 'cn=schema':
+ if old_entry.get('dn', DN()) == DN(('cn', 'schema')):
if len(adds) > 0:
modlist.append((ldap.MOD_ADD, key, adds))
else:
@@ -590,11 +601,12 @@ class IPAdmin(IPAEntryLDAPObject):
return modlist
- def inactivateEntry(self,dn,has_key):
+ def inactivateEntry(self,dn, has_key):
"""Rather than deleting entries we mark them as inactive.
has_key defines whether the entry already has nsAccountlock
set so we can determine which type of mod operation to run."""
+ assert isinstance(dn, DN)
sctrl = self.__get_server_controls()
modlist=[]
@@ -616,6 +628,7 @@ class IPAdmin(IPAEntryLDAPObject):
def deleteEntry(self, dn):
"""This wraps the delete function. Use with caution."""
+ assert isinstance(dn, DN)
sctrl = self.__get_server_controls()
try:
@@ -627,7 +640,7 @@ class IPAdmin(IPAEntryLDAPObject):
self.__handle_errors(e, arg_desc=arg_desc)
return True
- def modifyPassword(self,dn,oldpass,newpass):
+ def modifyPassword(self, dn, oldpass, newpass):
"""Set the user password using RFC 3062, LDAP Password Modify Extended
Operation. This ends up calling the IPA password slapi plugin
handler so the Kerberos password gets set properly.
@@ -635,6 +648,7 @@ class IPAdmin(IPAEntryLDAPObject):
oldpass is not mandatory
"""
+ assert isinstance(dn, DN)
sctrl = self.__get_server_controls()
try:
@@ -656,6 +670,7 @@ class IPAdmin(IPAEntryLDAPObject):
if isinstance(dn,Entry):
dn = dn.dn
+ assert isinstance(dn, DN)
# wait for entry and/or attr to show up
if not quiet:
@@ -691,6 +706,7 @@ class IPAdmin(IPAEntryLDAPObject):
running, true if done - if true, second is the exit code - if dowait
is True, this function will block until the task is complete
"""
+ assert isinstance(dn, DN)
attrlist = ['nsTaskLog', 'nsTaskStatus', 'nsTaskExitCode', 'nsTaskCurrentItem', 'nsTaskTotalItems']
done = False
exitCode = 0
@@ -701,26 +717,13 @@ class IPAdmin(IPAEntryLDAPObject):
break
if verbose:
print entry
- if entry.nsTaskExitCode:
- exitCode = int(entry.nsTaskExitCode)
+ if entry.getValue('nsTaskExitCode'):
+ exitCode = int(entry.getValue('nsTaskExitCode'))
done = True
if dowait: time.sleep(1)
else: break
return (done, exitCode)
- def get_schema(self):
- """
- Retrieve cn=schema and convert it into a python-ldap schema
- object.
- """
- if self.schema:
- return self.schema
- schema = self.getEntry('cn=schema', ldap.SCOPE_BASE,
- '(objectclass=*)', ['attributetypes', 'objectclasses'])
- schema = schema.toDict()
- self.schema = ldap.schema.SubSchema(schema)
- return self.schema
-
def get_single_value(self, attr):
"""
Check the schema to see if the attribute is single-valued.
@@ -730,8 +733,6 @@ class IPAdmin(IPAEntryLDAPObject):
If there is a problem loading the schema or the attribute is
not in the schema return None
"""
- if not self.schema:
- self.get_schema()
obj = self.schema.get_obj(ldap.schema.AttributeType, attr)
return obj and obj.single_value
@@ -744,19 +745,27 @@ class IPAdmin(IPAEntryLDAPObject):
starting from the leafs and go up to delete nodes only when all its
leafs are removed.
- Returns a "sorted" dict keyed by dn lengths and corresponding list
- of DNs.
- {'1': [dn1, dn2, dn3], '2': [dn4, dn5], ..}
+ Returns a list of list of dn's. Every dn in the dn list has
+ the same number of RDN's. The outer list is sorted according
+ to the number of RDN's in each inner list.
+
+ Example:
+
+ [['cn=bob', cn=tom], ['cn=bob,ou=people', cn=tom,ou=people]]
+
+ dn's in list[0] have 1 RDN
+ dn's in list[1] have 2 RDN's
"""
res = dict()
for e in entries:
- sdn = ldap.dn.str2dn(e.dn)
- l = len(sdn)
- if not l in res:
- res[l] = []
- res[l].append(e.dn)
+ dn = e.dn
+ assert isinstance(dn, DN)
+ rdn_count = len(dn)
+ rdn_count_list = res.setdefault(rdn_count, [])
+ if dn not in rdn_count_list:
+ rdn_count_list.append(dn)
keys = res.keys()
keys.sort(reverse=reverse)
diff --git a/ipaserver/plugins/dogtag.py b/ipaserver/plugins/dogtag.py
index 8accb56d2..baa41ad3c 100644
--- a/ipaserver/plugins/dogtag.py
+++ b/ipaserver/plugins/dogtag.py
@@ -238,6 +238,8 @@ digits and nothing else follows.
from lxml import etree
import datetime
+from ipapython.dn import DN
+from ldap.filter import escape_filter_chars
# These are general status return values used when
# CMSServlet.outputError() is invoked.
@@ -1239,8 +1241,8 @@ class ra(rabase.rabase):
Check if a specified host is a master for a specified service.
"""
- base_dn = 'cn=%s,cn=masters,cn=ipa,cn=etc,%s' % (host, api.env.basedn)
- filter = '(&(objectClass=ipaConfigObject)(cn=%s)(ipaConfigString=enabledService))' % service
+ base_dn = DN(('cn', host), ('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
+ filter = '(&(objectClass=ipaConfigObject)(cn=%s)(ipaConfigString=enabledService))' % escape_filter_chars(service)
try:
ldap2 = self.api.Backend.ldap2
ent,trunc = ldap2.find_entries(filter=filter, base_dn=base_dn)
@@ -1258,14 +1260,16 @@ class ra(rabase.rabase):
Select any host which is a master for a specified service.
"""
- base_dn = 'cn=masters,cn=ipa,cn=etc,%s' % api.env.basedn
- filter = '(&(objectClass=ipaConfigObject)(cn=%s)(ipaConfigString=enabledService))' % service
+ base_dn = DN(('cn', 'masters'), ('cn', 'ipa'), ('cn', 'etc'), api.env.basedn)
+ filter = '(&(objectClass=ipaConfigObject)(cn=%s)(ipaConfigString=enabledService))' % escape_filter_chars(service)
try:
ldap2 = self.api.Backend.ldap2
ent,trunc = ldap2.find_entries(filter=filter, base_dn=base_dn)
if len(ent):
entry = random.choice(ent)
- return ldap.explode_dn(dn=entry[0],notypes=True)[1]
+ dn = entry[0]
+ assert isinstance(dn, DN)
+ return dn[1].value
except Exception, e:
pass
return None
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index 6a3d2164e..a0b91fd5d 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -1,5 +1,6 @@
# Authors:
# Pavel Zuna <pzuna@redhat.com>
+# John Dennis <jdennis@redhat.com>
#
# Copyright (C) 2009 Red Hat
# see file 'COPYING' for use and warranty information
@@ -35,6 +36,8 @@ import tempfile
import time
import re
import pwd
+import sys
+from decimal import Decimal
import krbV
from ipapython.ipa_log_manager import *
@@ -42,6 +45,12 @@ import ldap as _ldap
from ldap.ldapobject import SimpleLDAPObject
import ldap.filter as _ldap_filter
import ldap.sasl as _ldap_sasl
+from ipapython.dn import DN, RDN
+from ipapython.ipautil import CIDict
+from collections import namedtuple
+from ipalib.errors import NetworkError, DatabaseError
+
+
try:
from ldap.controls.simple import GetEffectiveRightsControl #pylint: disable=F0401,E0611
except ImportError:
@@ -56,17 +65,26 @@ except ImportError:
def __init__(self, criticality, authzId=None):
LDAPControl.__init__(self, '1.3.6.1.4.1.42.2.27.9.5.2', criticality, authzId)
# for backward compatibility
-from ldap.functions import explode_dn
-from ipalib.dn import DN
from ipalib import _
import krbV
from ipalib import api, errors
from ipalib.crud import CrudBackend
-from ipalib.encoder import Encoder, encode_args, decode_retval
from ipalib.request import context
+_debug_log_ldap = False
+
+# Make python-ldap tuple style result compatible with Entry and Entity
+# objects by allowing access to the dn (tuple index 0) via the 'dn'
+# attribute name and the attr dict (tuple index 1) via the 'data'
+# attribute name. Thus:
+# r = result[0]
+# r[0] == r.dn
+# r[1] == r.data
+LDAPEntry = namedtuple('LDAPEntry', ['dn', 'data'])
+
+
# Group Member types
MEMBERS_ALL = 0
MEMBERS_DIRECT = 1
@@ -75,264 +93,541 @@ MEMBERS_INDIRECT = 2
# SASL authentication mechanism
SASL_AUTH = _ldap_sasl.sasl({}, 'GSSAPI')
-class IPASimpleLDAPObject(SimpleLDAPObject):
+DN_SYNTAX_OID = '1.3.6.1.4.1.1466.115.121.1.12'
+
+def unicode_from_utf8(val):
'''
- This is a thin layer over SimpleLDAPObject which allows us to utilize
- IPA specific types with the python-ldap API without the IPA caller needing
- to perform the type translation, consider this a convenience layer for the
- IPA programmer.
+ val is a UTF-8 encoded string, return a unicode object.
+ '''
+ return val.decode('utf-8')
- This subclass performs the following translations:
+def value_to_utf8(val):
+ '''
+ Coerce the val parameter to a UTF-8 encoded string representation
+ of the val.
+ '''
+
+ # If val is not a string we need to convert it to a string
+ # (specifically a unicode string). Naively we might think we need to
+ # call str(val) to convert to a string. This is incorrect because if
+ # val is already a unicode object then str() will call
+ # encode(default_encoding) returning a str object encoded with
+ # default_encoding. But we don't want to apply the default_encoding!
+ # Rather we want to guarantee the val object has been converted to a
+ # unicode string because from a unicode string we want to explicitly
+ # encode to a str using our desired encoding (utf-8 in this case).
+ #
+ # Note: calling unicode on a unicode object simply returns the exact
+ # same object (with it's ref count incremented). This means calling
+ # unicode on a unicode object is effectively a no-op, thus it's not
+ # inefficient.
- * DN objects may be passed into any ldap function expecting a dn. The DN
- object will be converted to a string before being passed to the python-ldap
- function. This allows us to maintain DN objects as DN objects in the rest
- of the code (useful for DN manipulation and DN information) and not have
- to worry about conversion to a string prior to passing it ldap.
+ return unicode(val).encode('utf-8')
+class _ServerSchema(object):
+ '''
+ Properties of a schema retrieved from an LDAP server.
'''
- def __init__(self, *args, **kwds):
- SimpleLDAPObject.__init__(self, *args, **kwds)
- def add(self, dn, modlist):
- return SimpleLDAPObject.add(self, str(dn), modlist)
+ def __init__(self, server, schema):
+ self.server = server
+ self.schema = schema
+ self.retrieve_timestamp = time.time()
- def add_ext(self, dn, modlist, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.add_ext(self, str(dn), modlist, serverctrls, clientctrls)
+class SchemaCache(object):
+ '''
+ Cache the schema's from individual LDAP servers.
+ '''
- def add_ext_s(self, dn, modlist, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.add_ext_s(self, str(dn), modlist, serverctrls, clientctrls)
+ def __init__(self):
+ log_mgr.get_logger(self, True)
+ self.servers = {}
- def add_s(self, dn, modlist):
- return SimpleLDAPObject.add_s(self, str(dn), modlist)
+ def get_schema(self, url, conn=None, force_update=False):
+ '''
+ Return schema belonging to a specific LDAP server.
- def compare(self, dn, attr, value):
- return SimpleLDAPObject.compare(self, str(dn), attr, value)
+ For performance reasons the schema is retrieved once and
+ cached unless force_update is True. force_update flushes the
+ existing schema for the server from the cache and reacquires
+ it.
+ '''
- def compare_ext(self, dn, attr, value, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.compare_ext(self, str(dn), attr, value, serverctrls, clientctrls)
+ if force_update:
+ self.flush(url)
- def compare_ext_s(self, dn, attr, value, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.compare_ext_s(self, str(dn), attr, value, serverctrls, clientctrls)
+ server_schema = self.servers.get(url)
+ if server_schema is None:
+ schema = self._retrieve_schema_from_server(url, conn)
+ server_schema = _ServerSchema(url, schema)
+ self.servers[url] = server_schema
+ return server_schema.schema
- def compare_s(self, dn, attr, value):
- return SimpleLDAPObject.compare_s(self, str(dn), attr, value)
+ def flush(self, url):
+ self.debug('flushing %s from SchemaCache', url)
+ try:
+ del self.servers[url]
+ except KeyError:
+ pass
- def delete(self, dn):
- return SimpleLDAPObject.delete(self, str(dn))
+ def _retrieve_schema_from_server(self, url, conn=None):
+ """
+ Retrieve the LDAP schema from the provided url and determine if
+ User-Private Groups (upg) are configured.
- def delete_ext(self, dn, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.delete_ext(self, str(dn), serverctrls, clientctrls)
+ Bind using kerberos credentials. If in the context of the
+ in-tree "lite" server then use the current ccache. If in the context of
+ Apache then create a new ccache and bind using the Apache HTTP service
+ principal.
- def delete_ext_s(self, dn, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.delete_ext_s(self, str(dn), serverctrls, clientctrls)
+ If a connection is provided then it the credentials bound to it are
+ used. The connection is not closed when the request is done.
+ """
+ tmpdir = None
+ has_conn = conn is not None
- def delete_s(self, dn):
- return SimpleLDAPObject.delete_s(self, str(dn))
+ self.debug('retrieving schema for SchemaCache url=%s conn=%s', url, conn)
- def modify(self, dn, modlist):
- return SimpleLDAPObject.modify(self, str(dn), modlist)
+ try:
+ if api.env.context == 'server' and conn is None:
+ # FIXME: is this really what we want to do?
+ # This seems like this logic is in the wrong place and may conflict with other state.
+ try:
+ # Create a new credentials cache for this Apache process
+ tmpdir = tempfile.mkdtemp(prefix = "tmp-")
+ ccache_file = 'FILE:%s/ccache' % tmpdir
+ krbcontext = krbV.default_context()
+ principal = str('HTTP/%s@%s' % (api.env.host, api.env.realm))
+ keytab = krbV.Keytab(name='/etc/httpd/conf/ipa.keytab', context=krbcontext)
+ principal = krbV.Principal(name=principal, context=krbcontext)
+ prev_ccache = os.environ.get('KRB5CCNAME')
+ os.environ['KRB5CCNAME'] = ccache_file
+ ccache = krbV.CCache(name=ccache_file, context=krbcontext, primary_principal=principal)
+ ccache.init(principal)
+ ccache.init_creds_keytab(keytab=keytab, principal=principal)
+ except krbV.Krb5Error, e:
+ raise StandardError('Unable to retrieve LDAP schema. Error initializing principal %s in %s: %s' % (principal.name, '/etc/httpd/conf/ipa.keytab', str(e)))
+ finally:
+ if prev_ccache is not None:
+ os.environ['KRB5CCNAME'] = prev_ccache
+
+
+ if conn is None:
+ conn = IPASimpleLDAPObject(url)
+ if url.startswith('ldapi://'):
+ conn.set_option(_ldap.OPT_HOST_NAME, api.env.host)
+ conn.sasl_interactive_bind_s(None, SASL_AUTH)
+
+ schema_entry = conn.search_s('cn=schema', _ldap.SCOPE_BASE,
+ attrlist=['attributetypes', 'objectclasses'])[0]
+ if not has_conn:
+ conn.unbind_s()
+ except _ldap.SERVER_DOWN:
+ raise NetworkError(uri=url,
+ error=u'LDAP Server Down, unable to retrieve LDAP schema')
+ except _ldap.LDAPError, e:
+ desc = e.args[0]['desc'].strip()
+ info = e.args[0].get('info', '').strip()
+ raise DatabaseError(desc = u'uri=%s' % url,
+ info = u'Unable to retrieve LDAP schema: %s: %s' % (desc, info))
+ except IndexError:
+ # no 'cn=schema' entry in LDAP? some servers use 'cn=subschema'
+ # TODO: DS uses 'cn=schema', support for other server?
+ # raise a more appropriate exception
+ raise
+ finally:
+ if tmpdir:
+ shutil.rmtree(tmpdir)
+
+ return _ldap.schema.SubSchema(schema_entry[1])
+
+schema_cache = SchemaCache()
+
+class IPASimpleLDAPObject(object):
+ '''
+ The purpose of this class is to provide a boundary between IPA and
+ python-ldap. In IPA we use IPA defined types because they are
+ richer and are designed to meet our needs. We also require that we
+ consistently use those types without exception. On the other hand
+ python-ldap uses different types. The goal is to be able to have
+ IPA code call python-ldap methods using the types native to
+ IPA. This class accomplishes that goal by exposing python-ldap
+ methods which take IPA types, convert them to python-ldap types,
+ call python-ldap, and then convert the results returned by
+ python-ldap into IPA types.
+
+ IPA code should never call python-ldap directly, it should only
+ call python-ldap methods in this class.
+ '''
- def modify_ext(self, dn, modlist, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.modify_ext(self, str(dn), modlist, serverctrls, clientctrls)
+ # Note: the oid for dn syntax is: 1.3.6.1.4.1.1466.115.121.1.12
- def modify_ext_s(self, dn, modlist, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.modify_ext_s(self, str(dn), modlist, serverctrls, clientctrls)
+ _SYNTAX_MAPPING = {
+ '1.3.6.1.4.1.1466.115.121.1.1' : str, # ACI item
+ '1.3.6.1.4.1.1466.115.121.1.4' : str, # Audio
+ '1.3.6.1.4.1.1466.115.121.1.5' : str, # Binary
+ '1.3.6.1.4.1.1466.115.121.1.8' : str, # Certificate
+ '1.3.6.1.4.1.1466.115.121.1.9' : str, # Certificate List
+ '1.3.6.1.4.1.1466.115.121.1.10' : str, # Certificate Pair
+ '1.3.6.1.4.1.1466.115.121.1.23' : str, # Fax
+ '1.3.6.1.4.1.1466.115.121.1.28' : str, # JPEG
+ '1.3.6.1.4.1.1466.115.121.1.40' : str, # OctetString (same as Binary)
+ '1.3.6.1.4.1.1466.115.121.1.49' : str, # Supported Algorithm
+ '1.3.6.1.4.1.1466.115.121.1.51' : str, # Teletext Terminal Identifier
+
+ DN_SYNTAX_OID : DN, # DN, member, memberof
+ '2.16.840.1.113730.3.8.3.3' : DN, # enrolledBy
+ '2.16.840.1.113730.3.8.3.18' : DN, # managedBy
+ '2.16.840.1.113730.3.8.3.5' : DN, # memberUser
+ '2.16.840.1.113730.3.8.3.7' : DN, # memberHost
+ '2.16.840.1.113730.3.8.3.20' : DN, # memberService
+ '2.16.840.1.113730.3.8.11.4' : DN, # ipaNTFallbackPrimaryGroup
+ '2.16.840.1.113730.3.8.11.21' : DN, # ipaAllowToImpersonate
+ '2.16.840.1.113730.3.8.11.22' : DN, # ipaAllowedTarget
+ '2.16.840.1.113730.3.8.7.1' : DN, # memberAllowCmd
+ '2.16.840.1.113730.3.8.7.2' : DN, # memberDenyCmd
+
+ '2.16.840.1.113719.1.301.4.14.1' : DN, # krbRealmReferences
+ '2.16.840.1.113719.1.301.4.17.1' : DN, # krbKdcServers
+ '2.16.840.1.113719.1.301.4.18.1' : DN, # krbPwdServers
+ '2.16.840.1.113719.1.301.4.26.1' : DN, # krbPrincipalReferences
+ '2.16.840.1.113719.1.301.4.29.1' : DN, # krbAdmServers
+ '2.16.840.1.113719.1.301.4.36.1' : DN, # krbPwdPolicyReference
+ '2.16.840.1.113719.1.301.4.40.1' : DN, # krbTicketPolicyReference
+ '2.16.840.1.113719.1.301.4.41.1' : DN, # krbSubTrees
+ '2.16.840.1.113719.1.301.4.52.1' : DN, # krbObjectReferences
+ '2.16.840.1.113719.1.301.4.53.1' : DN, # krbPrincContainerRef
+ }
- def modify_s(self, dn, modlist):
- return SimpleLDAPObject.modify_s(self, str(dn), modlist)
+ # In most cases we lookup the syntax from the schema returned by
+ # the server. However, sometimes attributes may not be defined in
+ # the schema (e.g. extensibleObject which permits undefined
+ # attributes), or the schema was incorrectly defined (i.e. giving
+ # an attribute the syntax DirectoryString when in fact it's really
+ # a DN). This (hopefully sparse) table allows us to trap these
+ # anomalies and force them to be the syntax we know to be in use.
+ #
+ # FWIW, many entries under cn=config are undefined :-(
+
+ _SCHEMA_OVERRIDE = CIDict({
+ 'managedtemplate': DN_SYNTAX_OID, # DN
+ 'managedbase': DN_SYNTAX_OID, # DN
+ 'originscope': DN_SYNTAX_OID, # DN
+ })
+
+ def __init__(self, uri):
+ log_mgr.get_logger(self, True)
+ self.uri = uri
+ self.conn = SimpleLDAPObject(uri)
+ self._schema = None
+
+ def _get_schema(self):
+ if self._schema is None:
+ # The schema may be updated during install or during
+ # updates, make sure we have a current version of the
+ # schema, not an out of date cached version.
+ force_update = api.env.context in ('installer', 'updates')
+ self._schema = schema_cache.get_schema(self.uri, self.conn, force_update=force_update)
+ return self._schema
+
+ schema = property(_get_schema, None, None, 'schema associated with this LDAP server')
+
+
+ def flush_cached_schema(self):
+ '''
+ Force this instance to forget it's cached schema and reacquire
+ it from the schema cache.
+ '''
+
+ # Currently this is called during bind operations to assure
+ # we're working with valid schema for a specific
+ # connection. This causes self._get_schema() to query the
+ # schema cache for the server's schema passing along a flag
+ # indicating if we're in a context that requires freshly
+ # loading the schema vs. returning the last cached version of
+ # the schema. If we're in a mode that permits use of
+ # previously cached schema the flush and reacquire is a very
+ # low cost operation.
+ #
+ # The schema is reacquired whenever this object is
+ # instantiated or when binding occurs. The schema is not
+ # reacquired for operations during a bound connection, it is
+ # presumed schema cannot change during this interval. This
+ # provides for maximum efficiency in contexts which do need
+ # schema refreshing by only peforming the refresh inbetween
+ # logical operations that have the potential to cause a schema
+ # change.
+
+ self._schema = None
+
+ def get_syntax(self, attr):
+ # Is this a special case attribute?
+ syntax = self._SCHEMA_OVERRIDE.get(attr)
+ if syntax is not None:
+ return syntax
+
+ # Try to lookup the syntax in the schema returned by the server
+ obj = self.schema.get_obj(_ldap.schema.AttributeType, attr)
+ if obj is not None:
+ return obj.syntax
+ else:
+ return None
- def modrdn(self, dn, newrdn, delold=1):
- return SimpleLDAPObject.modrdn(self, str(dn), str(newrdn), delold)
+ def has_dn_syntax(self, attr):
+ """
+ Check the schema to see if the attribute uses DN syntax.
- def modrdn_s(self, dn, newrdn, delold=1):
- return SimpleLDAPObject.modrdn_s(self, str(dn), str(newrdn), delold)
+ Returns True/False
+ """
+ syntax = self.get_syntax(attr)
+ return syntax == DN_SYNTAX_OID
+
+
+ def encode(self, val):
+ '''
+ '''
+ # Booleans are both an instance of bool and int, therefore
+ # test for bool before int otherwise the int clause will be
+ # entered for a boolean value instead of the boolean clause.
+ if isinstance(val, bool):
+ if val:
+ return 'TRUE'
+ else:
+ return 'FALSE'
+ elif isinstance(val, (unicode, float, int, long, Decimal, DN)):
+ return value_to_utf8(val)
+ elif isinstance(val, str):
+ return val
+ elif isinstance(val, list):
+ return [self.encode(m) for m in val]
+ elif isinstance(val, tuple):
+ return tuple(self.encode(m) for m in val)
+ elif isinstance(val, dict):
+ dct = dict((self.encode(k), self.encode(v)) for k, v in val.iteritems())
+ return dct
+ elif val is None:
+ return None
+ else:
+ raise TypeError("attempt to pass unsupported type to ldap, value=%s type=%s" %(val, type(val)))
- def read_subschemasubentry_s(self, subschemasubentry_dn, attrs=None):
- return SimpleLDAPObject.read_subschemasubentry_s(self, str(subschemasubentry_dn), attrs)
+ def convert_value_list(self, attr, target_type, values):
+ '''
+ '''
- def rename(self, dn, newrdn, newsuperior=None, delold=1, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.rename(self, str(dn), str(newrdn), newsuperior, delold, serverctrls, clientctrls)
+ ipa_values = []
- def rename_s(self, dn, newrdn, newsuperior=None, delold=1, serverctrls=None, clientctrls=None):
- return SimpleLDAPObject.rename_s(self, str(dn), str(newrdn), newsuperior, delold, serverctrls, clientctrls)
+ for original_value in values:
+ if isinstance(target_type, type) and isinstance(original_value, target_type):
+ ipa_value = original_value
+ else:
+ try:
+ ipa_value = target_type(original_value)
+ except Exception, e:
+ msg = 'unable to convert the attribute "%s" value "%s" to type %s' % (attr, original_value, target_type)
+ self.error(msg)
+ raise ValueError(msg)
- def search(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
- return SimpleLDAPObject.search(self, str(base), scope, filterstr, attrlist, attrsonly)
+ ipa_values.append(ipa_value)
- def search_ext(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0,
- serverctrls=None, clientctrls=None, timeout=-1, sizelimit=0):
- return SimpleLDAPObject.search_ext(self, str(base), scope, filterstr, attrlist, attrsonly,
- serverctrls, clientctrls, timeout, sizelimit)
+ return ipa_values
- def search_ext_s(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0,
- serverctrls=None, clientctrls=None, timeout=-1, sizelimit=0):
- return SimpleLDAPObject.search_ext_s(self, str(base), scope, filterstr, attrlist, attrsonly,
- serverctrls, clientctrls, timeout, sizelimit)
+ def convert_result(self, result):
+ '''
+ result is a python-ldap result tuple of the form (dn, attrs),
+ where dn is a string containing the dn (distinguished name) of
+ the entry, and attrs is a dictionary containing the attributes
+ associated with the entry. The keys of attrs are strings, and
+ the associated values are lists of strings.
- def search_s(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
- return SimpleLDAPObject.search_s(self, str(base), scope, filterstr, attrlist, attrsonly)
+ We convert the dn to a DN object.
- def search_st(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0, timeout=-1):
- return SimpleLDAPObject.search_st(self, str(base), scope, filterstr, attrlist, attrsonly, timeout)
+ We convert every value associated with an attribute according
+ to it's syntax into the desired Python type.
- def search_subschemasubentry_s(self, dn=''):
- return SimpleLDAPObject.search_subschemasubentry_s(self, str(dn))
+ returns a IPA result tuple of the same form as a python-ldap
+ result tuple except everything inside of the result tuple has
+ been converted to it's preferred IPA python type.
+ '''
-# universal LDAPError handler
-def _handle_errors(e, **kw):
- """
- Centralize error handling in one place.
+ ipa_result = []
+ for dn_tuple in result:
+ original_dn = dn_tuple[0]
+ original_attrs = dn_tuple[1]
- e is the error to be raised
- **kw is an exception-specific list of options
- """
- if not isinstance(e, _ldap.TIMEOUT):
- desc = e.args[0]['desc'].strip()
- info = e.args[0].get('info', '').strip()
- else:
- desc = ''
- info = ''
-
- try:
- # re-raise the error so we can handle it
- raise e
- except _ldap.NO_SUCH_OBJECT:
- # args = kw.get('args', '')
- # raise errors.NotFound(msg=notfound(args))
- raise errors.NotFound(reason='no such entry')
- except _ldap.ALREADY_EXISTS:
- raise errors.DuplicateEntry()
- except _ldap.CONSTRAINT_VIOLATION:
- # This error gets thrown by the uniqueness plugin
- if info.startswith('Another entry with the same attribute value already exists'):
- raise errors.DuplicateEntry()
- else:
- raise errors.DatabaseError(desc=desc, info=info)
- except _ldap.INSUFFICIENT_ACCESS:
- raise errors.ACIError(info=info)
- except _ldap.INVALID_CREDENTIALS:
- raise errors.ACIError(info="%s %s" % (info, desc))
- except _ldap.NO_SUCH_ATTRIBUTE:
- # this is raised when a 'delete' attribute isn't found.
- # it indicates the previous attribute was removed by another
- # update, making the oldentry stale.
- raise errors.MidairCollision()
- except _ldap.INVALID_SYNTAX:
- raise errors.InvalidSyntax(attr=info)
- except _ldap.OBJECT_CLASS_VIOLATION:
- raise errors.ObjectclassViolation(info=info)
- except _ldap.ADMINLIMIT_EXCEEDED:
- raise errors.LimitsExceeded()
- except _ldap.SIZELIMIT_EXCEEDED:
- raise errors.LimitsExceeded()
- except _ldap.TIMELIMIT_EXCEEDED:
- raise errors.LimitsExceeded()
- except _ldap.NOT_ALLOWED_ON_RDN:
- raise errors.NotAllowedOnRDN(attr=info)
- except _ldap.FILTER_ERROR:
- raise errors.BadSearchFilter(info=info)
- except _ldap.SUCCESS:
- pass
- except _ldap.LDAPError, e:
- if 'NOT_ALLOWED_TO_DELEGATE' in info:
- raise errors.ACIError(info="KDC returned NOT_ALLOWED_TO_DELEGATE")
- root_logger.info('Unhandled LDAPError: %s' % str(e))
- raise errors.DatabaseError(desc=desc, info=info)
-
-
-def get_schema(url, conn=None):
- """
- Perform global initialization when the module is loaded.
+ ipa_dn = DN(original_dn)
+ ipa_attrs = dict()
- Retrieve the LDAP schema from the provided url and determine if
- User-Private Groups (upg) are configured.
+ for attr, original_values in original_attrs.items():
+ target_type = self._SYNTAX_MAPPING.get(self.get_syntax(attr), unicode_from_utf8)
+ ipa_attrs[attr.lower()] = self.convert_value_list(attr, target_type, original_values)
- Bind using kerberos credentials. If in the context of the
- in-tree "lite" server then use the current ccache. If in the context of
- Apache then create a new ccache and bind using the Apache HTTP service
- principal.
+ ipa_result.append(LDAPEntry(ipa_dn, ipa_attrs))
- If a connection is provided then it the credentials bound to it are
- used. The connection is not closed when the request is done.
- """
- tmpdir = None
- has_conn = conn is not None
+ if _debug_log_ldap:
+ self.debug('ldap.result: %s', ipa_result)
+ return ipa_result
- if ((not api.env.in_server or api.env.context not in ['lite', 'server'])
- and conn is None):
- # The schema is only needed on the server side
- return None
+ #---------- python-ldap emulations ----------
- try:
- if api.env.context == 'server' and conn is None:
- try:
- # Create a new credentials cache for this Apache process
- tmpdir = tempfile.mkdtemp(prefix = "tmp-")
- ccache_file = 'FILE:%s/ccache' % tmpdir
- krbcontext = krbV.default_context()
- principal = str('HTTP/%s@%s' % (api.env.host, api.env.realm))
- keytab = krbV.Keytab(name='/etc/httpd/conf/ipa.keytab', context=krbcontext)
- principal = krbV.Principal(name=principal, context=krbcontext)
- os.environ['KRB5CCNAME'] = ccache_file
- ccache = krbV.CCache(name=ccache_file, context=krbcontext, primary_principal=principal)
- ccache.init(principal)
- ccache.init_creds_keytab(keytab=keytab, principal=principal)
- except krbV.Krb5Error, e:
- raise StandardError('Unable to retrieve LDAP schema. Error initializing principal %s in %s: %s' % (principal.name, '/etc/httpd/conf/ipa.keytab', str(e)))
-
- if conn is None:
- conn = IPASimpleLDAPObject(url)
- if url.startswith('ldapi://'):
- conn.set_option(_ldap.OPT_HOST_NAME, api.env.host)
- conn.sasl_interactive_bind_s('', SASL_AUTH)
-
- schema_entry = conn.search_s(
- 'cn=schema', _ldap.SCOPE_BASE,
- attrlist=['attributetypes', 'objectclasses']
- )[0]
- if not has_conn:
- conn.unbind_s()
- except _ldap.SERVER_DOWN:
- return None
- except _ldap.LDAPError, e:
- desc = e.args[0]['desc'].strip()
- info = e.args[0].get('info', '').strip()
- raise StandardError('Unable to retrieve LDAP schema: %s: %s' % (desc, info))
- except IndexError:
- # no 'cn=schema' entry in LDAP? some servers use 'cn=subschema'
- # TODO: DS uses 'cn=schema', support for other server?
- # raise a more appropriate exception
- raise
- finally:
- if tmpdir:
- shutil.rmtree(tmpdir)
-
- return _ldap.schema.SubSchema(schema_entry[1])
-
-# Global schema
-_schema = None
-
-class ldap2(CrudBackend, Encoder):
+ def add(self, dn, modlist):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ modlist = self.encode(modlist)
+ return self.conn.add(dn, modlist)
+
+ def add_ext(self, dn, modlist, serverctrls=None, clientctrls=None):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ modlist = self.encode(modlist)
+ return self.conn.add_ext(dn, modlist, serverctrls, clientctrls)
+
+ def add_ext_s(self, dn, modlist, serverctrls=None, clientctrls=None):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ modlist = self.encode(modlist)
+ return self.conn.add_ext_s(dn, modlist, serverctrls, clientctrls)
+
+ def add_s(self, dn, modlist):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ modlist = self.encode(modlist)
+ return self.conn.add_s(dn, modlist)
+
+ def bind(self, who, cred, method=_ldap.AUTH_SIMPLE):
+ self.flush_cached_schema()
+ if who is None:
+ who = DN()
+ assert isinstance(who, DN)
+ who = str(who)
+ cred = self.encode(cred)
+ return self.conn.bind(who, cred, method)
+
+ def delete(self, dn):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ return self.conn.delete(dn)
+
+ def delete_s(self, dn):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ return self.conn.delete_s(dn)
+
+ def get_option(self, option):
+ return self.conn.get_option(option)
+
+ def modify_s(self, dn, modlist):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ modlist = [(x[0], self.encode(x[1]), self.encode(x[2])) for x in modlist]
+ return self.conn.modify_s(dn, modlist)
+
+ def modrdn_s(self, dn, newrdn, delold=1):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ assert isinstance(newrdn, (DN, RDN))
+ newrdn = str(newrdn)
+ return self.conn.modrdn_s(dn, newrdn, delold)
+
+ def passwd_s(self, dn, oldpw, newpw, serverctrls=None, clientctrls=None):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ oldpw = self.encode(oldpw)
+ newpw = self.encode(newpw)
+ return self.conn.passwd_s(dn, oldpw, newpw, serverctrls, clientctrls)
+
+ def rename_s(self, dn, newrdn, newsuperior=None, delold=1, serverctrls=None, clientctrls=None):
+ assert isinstance(dn, DN)
+ dn = str(dn)
+ assert isinstance(newrdn, (DN, RDN))
+ newrdn = str(newrdn)
+ return self.conn.rename_s(dn, newrdn, newsuperior, delold, serverctrls, clientctrls)
+
+ def result(self, msgid=_ldap.RES_ANY, all=1, timeout=None):
+ resp_type, resp_data = self.conn.result(msgid, all, timeout)
+ resp_data = self.convert_result(resp_data)
+ return resp_type, resp_data
+
+ def sasl_interactive_bind_s(self, who, auth, serverctrls=None, clientctrls=None, sasl_flags=_ldap.SASL_QUIET):
+ self.flush_cached_schema()
+ if who is None:
+ who = DN()
+ assert isinstance(who, DN)
+ who = str(who)
+ return self.conn.sasl_interactive_bind_s(who, auth, serverctrls, clientctrls, sasl_flags)
+
+ def search(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
+ assert isinstance(base, DN)
+ base = str(base)
+ filterstr = self.encode(filterstr)
+ attrlist = self.encode(attrlist)
+ return self.conn.search(base, scope, filterstr, attrlist, attrsonly)
+
+ def search_ext(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0, serverctrls=None, clientctrls=None, timeout=-1, sizelimit=0):
+ assert isinstance(base, DN)
+ base = str(base)
+ filterstr = self.encode(filterstr)
+ attrlist = self.encode(attrlist)
+
+ if _debug_log_ldap:
+ self.debug("ldap.search_ext: dn: %s\nfilter: %s\nattrs_list: %s", base, filterstr, attrlist)
+
+
+ return self.conn.search_ext(base, scope, filterstr, attrlist, attrsonly, serverctrls, clientctrls, timeout, sizelimit)
+
+ def search_ext_s(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0, serverctrls=None, clientctrls=None, timeout=-1, sizelimit=0):
+ assert isinstance(base, DN)
+ base = str(base)
+ filterstr = self.encode(filterstr)
+ attrlist = self.encode(attrlist)
+ ldap_result = self.conn.search_ext_s(base, scope, filterstr, attrlist, attrsonly, serverctrls, clientctrls, timeout, sizelimit)
+ ipa_result = self.convert_result(ldap_result)
+ return ipa_result
+
+ def search_s(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0):
+ assert isinstance(base, DN)
+ base = str(base)
+ filterstr = self.encode(filterstr)
+ attrlist = self.encode(attrlist)
+ ldap_result = self.conn.search_s(base, scope, filterstr, attrlist, attrsonly)
+ ipa_result = self.convert_result(ldap_result)
+ return ipa_result
+
+ def search_st(self, base, scope, filterstr='(objectClass=*)', attrlist=None, attrsonly=0, timeout=-1):
+ assert isinstance(base, DN)
+ base = str(base)
+ filterstr = self.encode(filterstr)
+ attrlist = self.encode(attrlist)
+ ldap_result = self.conn.search_st(base, scope, filterstr, attrlist, attrsonly, timeout)
+ ipa_result = self.convert_result(ldap_result)
+ return ipa_result
+
+ def set_option(self, option, invalue):
+ return self.conn.set_option(option, invalue)
+
+ def simple_bind_s(self, who=None, cred='', serverctrls=None, clientctrls=None):
+ self.flush_cached_schema()
+ if who is None:
+ who = DN()
+ assert isinstance(who, DN)
+ who = str(who)
+ cred = self.encode(cred)
+ return self.conn.simple_bind_s(who, cred, serverctrls, clientctrls)
+
+ def start_tls_s(self):
+ return self.conn.start_tls_s()
+
+ def unbind(self):
+ self.flush_cached_schema()
+ return self.conn.unbind()
+
+ def unbind_s(self):
+ self.flush_cached_schema()
+ return self.conn.unbind_s()
+
+class ldap2(CrudBackend):
"""
LDAP Backend Take 2.
"""
- # attribute syntax to python type mapping, 'SYNTAX OID': type
- # everything not in this dict is considered human readable unicode
- _SYNTAX_MAPPING = {
- '1.3.6.1.4.1.1466.115.121.1.1': str, # ACI item
- '1.3.6.1.4.1.1466.115.121.1.4': str, # Audio
- '1.3.6.1.4.1.1466.115.121.1.5': str, # Binary
- '1.3.6.1.4.1.1466.115.121.1.8': str, # Certificate
- '1.3.6.1.4.1.1466.115.121.1.9': str, # Certificate List
- '1.3.6.1.4.1.1466.115.121.1.10': str, # Certificate Pair
- '1.3.6.1.4.1.1466.115.121.1.23': str, # Fax
- '1.3.6.1.4.1.1466.115.121.1.28': str, # JPEG
- '1.3.6.1.4.1.1466.115.121.1.40': str, # OctetString (same as Binary)
- '1.3.6.1.4.1.1466.115.121.1.49': str, # Supported Algorithm
- '1.3.6.1.4.1.1466.115.121.1.51': str, # Teletext Terminal Identifier
- }
-
# attributes in this list cannot be deleted by update_entry
# only MOD_REPLACE operations are generated for them
_FORCE_REPLACE_ON_UPDATE_ATTRS = []
@@ -349,27 +644,19 @@ class ldap2(CrudBackend, Encoder):
def __init__(self, shared_instance=True, ldap_uri=None, base_dn=None,
schema=None):
- global _schema
+ log_mgr.get_logger(self, True)
CrudBackend.__init__(self, shared_instance=shared_instance)
- Encoder.__init__(self)
- self.encoder_settings.encode_dict_keys = True
- self.encoder_settings.decode_dict_keys = True
- self.encoder_settings.decode_dict_vals_postprocess = False
- self.encoder_settings.decode_dict_vals_table = self._SYNTAX_MAPPING
- self.encoder_settings.decode_dict_vals_table_keygen = self.get_syntax
- self.encoder_settings.decode_postprocessor = lambda x: string.lower(x)
try:
self.ldap_uri = ldap_uri or api.env.ldap_uri
except AttributeError:
self.ldap_uri = 'ldap://example.com'
try:
if base_dn is not None:
- self.base_dn = base_dn
+ self.base_dn = DN(base_dn)
else:
- self.base_dn = api.env.basedn
+ self.base_dn = DN(api.env.basedn)
except AttributeError:
- self.base_dn = ''
- self.schema = schema or _schema
+ self.base_dn = DN()
def __del__(self):
if self.isconnected():
@@ -378,18 +665,83 @@ class ldap2(CrudBackend, Encoder):
def __str__(self):
return self.ldap_uri
+ def _get_schema(self):
+ return self.conn.schema
+ schema = property(_get_schema, None, None, 'schema associated with this LDAP server')
+
+ # universal LDAPError handler
+ def handle_errors(self, e):
+ """
+ Centralize error handling in one place.
+
+ e is the error to be raised
+ """
+ if not isinstance(e, _ldap.TIMEOUT):
+ desc = e.args[0]['desc'].strip()
+ info = e.args[0].get('info', '').strip()
+ else:
+ desc = ''
+ info = ''
+
+ try:
+ # re-raise the error so we can handle it
+ raise e
+ except _ldap.NO_SUCH_OBJECT:
+ raise errors.NotFound(reason='no such entry')
+ except _ldap.ALREADY_EXISTS:
+ raise errors.DuplicateEntry()
+ except _ldap.CONSTRAINT_VIOLATION:
+ # This error gets thrown by the uniqueness plugin
+ if info.startswith('Another entry with the same attribute value already exists'):
+ raise errors.DuplicateEntry()
+ else:
+ raise errors.DatabaseError(desc=desc, info=info)
+ except _ldap.INSUFFICIENT_ACCESS:
+ raise errors.ACIError(info=info)
+ except _ldap.INVALID_CREDENTIALS:
+ raise errors.ACIError(info="%s %s" % (info, desc))
+ except _ldap.NO_SUCH_ATTRIBUTE:
+ # this is raised when a 'delete' attribute isn't found.
+ # it indicates the previous attribute was removed by another
+ # update, making the oldentry stale.
+ raise errors.MidairCollision()
+ except _ldap.INVALID_SYNTAX:
+ raise errors.InvalidSyntax(attr=info)
+ except _ldap.OBJECT_CLASS_VIOLATION:
+ raise errors.ObjectclassViolation(info=info)
+ except _ldap.ADMINLIMIT_EXCEEDED:
+ raise errors.LimitsExceeded()
+ except _ldap.SIZELIMIT_EXCEEDED:
+ raise errors.LimitsExceeded()
+ except _ldap.TIMELIMIT_EXCEEDED:
+ raise errors.LimitsExceeded()
+ except _ldap.NOT_ALLOWED_ON_RDN:
+ raise errors.NotAllowedOnRDN(attr=info)
+ except _ldap.FILTER_ERROR:
+ raise errors.BadSearchFilter(info=info)
+ except _ldap.SUCCESS:
+ pass
+ except _ldap.LDAPError, e:
+ if 'NOT_ALLOWED_TO_DELEGATE' in info:
+ raise errors.ACIError(info="KDC returned NOT_ALLOWED_TO_DELEGATE")
+ self.info('Unhandled LDAPError: %s' % str(e))
+ raise errors.DatabaseError(desc=desc, info=info)
+
def get_syntax(self, attr, value):
- if not self.schema:
- self.get_schema()
+ if self.schema is None:
+ return None
obj = self.schema.get_obj(_ldap.schema.AttributeType, attr)
if obj is not None:
return obj.syntax
else:
return None
+ def has_dn_syntax(self, attr):
+ return self.conn.has_dn_syntax(attr)
+
def get_allowed_attributes(self, objectclasses, raise_on_unknown=False):
- if not self.schema:
- self.get_schema()
+ if self.schema is None:
+ return None
allowed_attributes = []
for oc in objectclasses:
obj = self.schema.get_obj(_ldap.schema.ObjectClass, oc)
@@ -408,13 +760,12 @@ class ldap2(CrudBackend, Encoder):
If there is a problem loading the schema or the attribute is
not in the schema return None
"""
- if not self.schema:
- self.get_schema()
+ if self.schema is None:
+ return None
obj = self.schema.get_obj(_ldap.schema.AttributeType, attr)
return obj and obj.single_value
- @encode_args(2, 3, 'bind_dn', 'bind_pw')
- def create_connection(self, ccache=None, bind_dn='', bind_pw='',
+ def create_connection(self, ccache=None, bind_dn=None, bind_pw='',
tls_cacertfile=None, tls_certfile=None, tls_keyfile=None,
debug_level=0, autobind=False):
"""
@@ -433,7 +784,9 @@ class ldap2(CrudBackend, Encoder):
Extends backend.Connectible.create_connection.
"""
- global _schema
+ if bind_dn is None:
+ bind_dn = DN()
+ assert isinstance(bind_dn, DN)
if tls_cacertfile is not None:
_ldap.set_option(_ldap.OPT_X_TLS_CACERTFILE, tls_cacertfile)
if tls_certfile is not None:
@@ -445,7 +798,7 @@ class ldap2(CrudBackend, Encoder):
_ldap.set_option(_ldap.OPT_DEBUG_LEVEL, debug_level)
try:
- conn = _ldap.initialize(self.ldap_uri)
+ conn = IPASimpleLDAPObject(self.ldap_uri)
if self.ldap_uri.startswith('ldapi://') and ccache:
conn.set_option(_ldap.OPT_HOST_NAME, api.env.host)
minssf = conn.get_option(_ldap.OPT_X_SASL_SSF_MIN)
@@ -459,7 +812,7 @@ class ldap2(CrudBackend, Encoder):
conn.set_option(_ldap.OPT_X_SASL_SSF_MAX, minssf)
if ccache is not None:
os.environ['KRB5CCNAME'] = ccache
- conn.sasl_interactive_bind_s('', SASL_AUTH)
+ conn.sasl_interactive_bind_s(None, SASL_AUTH)
principal = krbV.CCache(name=ccache,
context=krbV.default_context()).principal().name
setattr(context, 'principal', principal)
@@ -468,15 +821,13 @@ class ldap2(CrudBackend, Encoder):
if autobind:
pent = pwd.getpwuid(os.geteuid())
auth_tokens = _ldap.sasl.external(pent.pw_name)
- conn.sasl_interactive_bind_s("", auth_tokens)
+ conn.sasl_interactive_bind_s(None, auth_tokens)
else:
conn.simple_bind_s(bind_dn, bind_pw)
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
- if _schema:
- object.__setattr__(self, 'schema', _schema)
return conn
def destroy_connection(self):
@@ -489,55 +840,41 @@ class ldap2(CrudBackend, Encoder):
def normalize_dn(self, dn):
"""
- Normalize distinguished name.
+ Normalize distinguished name by assuring it ends with
+ the base_dn.
Note: You don't have to normalize DN's before passing them to
ldap2 methods. It's done internally for you.
"""
- rdns = explode_dn(dn)
- if rdns:
- dn = ','.join(rdns)
- if not dn.endswith(self.base_dn):
- dn = '%s,%s' % (dn, self.base_dn)
- return dn
- return self.base_dn
-
- def get_container_rdn(self, name):
- """Get relative distinguished name of cotainer."""
- env_container = 'container_%s' % name
- if env_container in self.api.env:
- return self.api.env[env_container]
- return ''
- def make_rdn_from_attr(self, attr, value):
- """Make relative distinguished name from attribute."""
- if isinstance(value, (list, tuple)):
- value = value[0]
- attr = _ldap.dn.escape_dn_chars(attr)
- value = _ldap.dn.escape_dn_chars(value)
- return '%s=%s' % (attr, value)
+ assert isinstance(dn, DN)
- def make_dn_from_rdn(self, rdn, parent_dn=''):
- """
- Make distinguished name from relative distinguished name.
+ if not dn.endswith(self.base_dn):
+ # DN's are mutable, don't use in-place addtion (+=) which would
+ # modify the dn passed in with unintended side-effects. Addition
+ # returns a new DN object which is the concatenation of the two.
+ dn = dn + self.base_dn
- Keyword arguments:
- parent_dn -- DN of the parent entry (default '')
- """
- parent_dn = self.normalize_dn(parent_dn)
- return '%s,%s' % (rdn, parent_dn)
+ return dn
- def make_dn_from_attr(self, attr, value, parent_dn=''):
+ def make_dn_from_attr(self, attr, value, parent_dn=None):
"""
Make distinguished name from attribute.
Keyword arguments:
parent_dn -- DN of the parent entry (default '')
"""
- rdn = self.make_rdn_from_attr(attr, value)
- return self.make_dn_from_rdn(rdn, parent_dn)
+ if parent_dn is None:
+ parent_dn = DN()
+ assert isinstance(parent_dn, DN)
+ parent_dn = self.normalize_dn(parent_dn)
+
+ if isinstance(value, (list, tuple)):
+ value = value[0]
+
+ return DN((attr, value), parent_dn)
- def make_dn(self, entry_attrs, primary_key='cn', parent_dn=''):
+ def make_dn(self, entry_attrs, primary_key='cn', parent_dn=None):
"""
Make distinguished name from entry attributes.
@@ -545,23 +882,32 @@ class ldap2(CrudBackend, Encoder):
primary_key -- attribute from which to make RDN (default 'cn')
parent_dn -- DN of the parent entry (default '')
"""
+
assert primary_key in entry_attrs
- rdn = self.make_rdn_from_attr(primary_key, entry_attrs[primary_key])
- return self.make_dn_from_rdn(rdn, parent_dn)
- @encode_args(1, 2)
+ if parent_dn is None:
+ parent_dn = DN()
+
+ parent_dn = self.normalize_dn(parent_dn)
+ return DN((primary_key, entry_attrs[primary_key]), parent_dn)
+
def add_entry(self, dn, entry_attrs, normalize=True):
"""Create a new entry."""
+
+ assert isinstance(dn, DN)
+
if normalize:
dn = self.normalize_dn(dn)
- # remove all None values, python-ldap hates'em
+ # remove all None or [] values, python-ldap hates'em
entry_attrs = dict(
- (k, v) for (k, v) in entry_attrs.iteritems() if v
+ # FIXME, shouldn't these values be an error?
+ (k, v) for (k, v) in entry_attrs.iteritems()
+ if v is not None and v != []
)
try:
self.conn.add_s(dn, list(entry_attrs.iteritems()))
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
# generating filters for find_entry
# some examples:
@@ -580,7 +926,9 @@ class ldap2(CrudBackend, Encoder):
Keyword arguments:
rules -- see ldap2.make_filter
"""
+
assert isinstance(filters, (list, tuple))
+
filters = [f for f in filters if f]
if filters and rules == self.MATCH_NONE: # unary operator
return '(%s%s)' % (self.MATCH_NONE,
@@ -598,7 +946,6 @@ class ldap2(CrudBackend, Encoder):
flt = '%s)' % flt
return flt
- @encode_args(1, 2)
def make_filter_from_attr(self, attr, value, rules='|', exact=True,
leading_wildcard=True, trailing_wildcard=True):
"""
@@ -620,7 +967,7 @@ class ldap2(CrudBackend, Encoder):
trailing_wildcard=trailing_wildcard) for v in value ]
return self.combine_filters(flts, rules)
elif value is not None:
- value = _ldap_filter.escape_filter_chars(value)
+ value = _ldap_filter.escape_filter_chars(value_to_utf8(value))
if not exact:
template = '%s'
if leading_wildcard:
@@ -671,9 +1018,7 @@ class ldap2(CrudBackend, Encoder):
)
return self.combine_filters(flts, rules)
- @encode_args(1, 2, 3)
- @decode_retval()
- def find_entries(self, filter=None, attrs_list=None, base_dn='',
+ def find_entries(self, filter=None, attrs_list=None, base_dn=None,
scope=_ldap.SCOPE_SUBTREE, time_limit=None, size_limit=None,
normalize=True, search_refs=False):
"""
@@ -691,6 +1036,9 @@ class ldap2(CrudBackend, Encoder):
normalize -- normalize the DN (default True)
search_refs -- allow search references to be returned (default skips these entries)
"""
+ if base_dn is None:
+ base_dn = DN()
+ assert isinstance(base_dn, DN)
if normalize:
base_dn = self.normalize_dn(base_dn)
if not filter:
@@ -731,7 +1079,7 @@ class ldap2(CrudBackend, Encoder):
_ldap.SIZELIMIT_EXCEEDED), e:
truncated = True
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
if not res and not truncated:
raise errors.NotFound(reason='no such entry')
@@ -756,7 +1104,8 @@ class ldap2(CrudBackend, Encoder):
del r[1]['memberOf']
else:
continue
- (direct, indirect) = self.get_memberof(r[0], memberof, time_limit=time_limit, size_limit=size_limit, normalize=normalize)
+ (direct, indirect) = self.get_memberof(r[0], memberof, time_limit=time_limit,
+ size_limit=size_limit, normalize=normalize)
if len(direct) > 0:
r[1]['memberof'] = direct
if len(indirect) > 0:
@@ -764,8 +1113,7 @@ class ldap2(CrudBackend, Encoder):
return (res, truncated)
- def find_entry_by_attr(self, attr, value, object_class, attrs_list=None,
- base_dn=''):
+ def find_entry_by_attr(self, attr, value, object_class, attrs_list=None, base_dn=None):
"""
Find entry (dn, entry_attrs) by attribute and object class.
@@ -773,6 +1121,11 @@ class ldap2(CrudBackend, Encoder):
attrs_list - list of attributes to return, all if None (default None)
base_dn - dn of the entry at which to start the search (default '')
"""
+
+ if base_dn is None:
+ base_dn = DN()
+ assert isinstance(base_dn, DN)
+
search_kw = {attr: value, 'objectClass': object_class}
filter = self.make_filter(search_kw, rules=self.MATCH_ALL)
(entries, truncated) = self.find_entries(filter, attrs_list, base_dn)
@@ -793,6 +1146,9 @@ class ldap2(CrudBackend, Encoder):
Keyword arguments:
attrs_list - list of attributes to return, all if None (default None)
"""
+
+ assert isinstance(dn, DN)
+
(entry, truncated) = self.find_entries(
None, attrs_list, dn, self.SCOPE_BASE, time_limit=time_limit,
size_limit=size_limit, normalize=normalize
@@ -805,7 +1161,12 @@ class ldap2(CrudBackend, Encoder):
config_defaults = {'ipasearchtimelimit': [2], 'ipasearchrecordslimit': [0]}
def get_ipa_config(self, attrs_list=None):
"""Returns the IPA configuration entry (dn, entry_attrs)."""
- cdn = "%s,%s" % (api.Object.config.get_dn(), api.env.basedn)
+
+ odn = api.Object.config.get_dn()
+ assert isinstance(odn, DN)
+ assert isinstance(api.env.basedn, DN)
+ cdn = DN(odn, api.env.basedn)
+
try:
config_entry = getattr(context, 'config_entry')
return (cdn, copy.deepcopy(config_entry))
@@ -828,35 +1189,17 @@ class ldap2(CrudBackend, Encoder):
setattr(context, 'config_entry', copy.deepcopy(config_entry))
return (cdn, config_entry)
- def get_schema(self, deepcopy=False):
- """Returns either a reference to current schema or its deep copy"""
- global _schema
- if not _schema:
- _schema = get_schema(self.ldap_uri, self.conn)
- if not _schema:
- raise errors.DatabaseError(desc='Unable to retrieve LDAP schema', info='Unable to proceed with request')
- # explicitly use setattr here so the schema can be set after
- # the object is finalized.
- object.__setattr__(self, 'schema', _schema)
-
- if (deepcopy):
- return copy.deepcopy(self.schema)
- else:
- return self.schema
-
def has_upg(self):
"""Returns True/False whether User-Private Groups are enabled.
This is determined based on whether the UPG Template exists.
"""
- upg_dn = str(DN('cn=UPG Definition,cn=Definitions,cn=Managed Entries,cn=etc', api.env.basedn))
+ upg_dn = DN(('cn', 'UPG Definition'), ('cn', 'Definitions'), ('cn', 'Managed Entries'),
+ ('cn', 'etc'), api.env.basedn)
try:
- upg_entry = self.conn.search_s(
- upg_dn,
- _ldap.SCOPE_BASE,
- attrlist=['*']
- )[0]
+ upg_entry = self.conn.search_s(upg_dn, _ldap.SCOPE_BASE,
+ attrlist=['*'])[0]
disable_attr = '(objectclass=disable)'
if 'originfilter' in upg_entry[1]:
org_filter = upg_entry[1]['originfilter']
@@ -866,27 +1209,32 @@ class ldap2(CrudBackend, Encoder):
except _ldap.NO_SUCH_OBJECT, e:
return False
- @encode_args(1, 2)
def get_effective_rights(self, dn, entry_attrs):
"""Returns the rights the currently bound user has for the given DN.
Returns 2 attributes, the attributeLevelRights for the given list of
attributes and the entryLevelRights for the entry itself.
"""
+
+ assert isinstance(dn, DN)
+
principal = getattr(context, 'principal')
(binddn, attrs) = self.find_entry_by_attr("krbprincipalname", principal, "krbPrincipalAux")
- sctrl = [GetEffectiveRightsControl(True, "dn: " + binddn.encode('UTF-8'))]
+ assert isinstance(binddn, DN)
+ sctrl = [GetEffectiveRightsControl(True, "dn: " + str(binddn))]
self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, sctrl)
(dn, attrs) = self.get_entry(dn, entry_attrs)
# remove the control so subsequent operations don't include GER
self.conn.set_option(_ldap.OPT_SERVER_CONTROLS, [])
return (dn, attrs)
- @encode_args(1, 2)
def can_write(self, dn, attr):
"""Returns True/False if the currently bound user has write permissions
on the attribute. This only operates on a single attribute at a time.
"""
+
+ assert isinstance(dn, DN)
+
(dn, attrs) = self.get_effective_rights(dn, [attr])
if 'attributelevelrights' in attrs:
attr_rights = attrs.get('attributelevelrights')[0].decode('UTF-8')
@@ -896,11 +1244,12 @@ class ldap2(CrudBackend, Encoder):
return False
- @encode_args(1, 2)
def can_read(self, dn, attr):
"""Returns True/False if the currently bound user has read permissions
on the attribute. This only operates on a single attribute at a time.
"""
+ assert isinstance(dn, DN)
+
(dn, attrs) = self.get_effective_rights(dn, [attr])
if 'attributelevelrights' in attrs:
attr_rights = attrs.get('attributelevelrights')[0].decode('UTF-8')
@@ -919,11 +1268,13 @@ class ldap2(CrudBackend, Encoder):
# v - View the entry
#
- @encode_args(1)
def can_delete(self, dn):
"""Returns True/False if the currently bound user has delete permissions
on the entry.
"""
+
+ assert isinstance(dn, DN)
+
(dn, attrs) = self.get_effective_rights(dn, ["*"])
if 'entrylevelrights' in attrs:
entry_rights = attrs['entrylevelrights'][0].decode('UTF-8')
@@ -932,11 +1283,11 @@ class ldap2(CrudBackend, Encoder):
return False
- @encode_args(1)
def can_add(self, dn):
"""Returns True/False if the currently bound user has add permissions
on the entry.
"""
+ assert isinstance(dn, DN)
(dn, attrs) = self.get_effective_rights(dn, ["*"])
if 'entrylevelrights' in attrs:
entry_rights = attrs['entrylevelrights'][0].decode('UTF-8')
@@ -945,7 +1296,6 @@ class ldap2(CrudBackend, Encoder):
return False
- @encode_args(1, 2)
def update_entry_rdn(self, dn, new_rdn, del_old=True):
"""
Update entry's relative distinguished name.
@@ -953,22 +1303,25 @@ class ldap2(CrudBackend, Encoder):
Keyword arguments:
del_old -- delete old RDN value (default True)
"""
+
+ assert isinstance(dn, DN)
+ assert isinstance(new_rdn, RDN)
+
dn = self.normalize_dn(dn)
- if dn.startswith(new_rdn + ","):
+ if dn[0] == new_rdn:
raise errors.EmptyModlist()
try:
self.conn.rename_s(dn, new_rdn, delold=int(del_old))
time.sleep(.3) # Give memberOf plugin a chance to work
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
def _generate_modlist(self, dn, entry_attrs, normalize):
+ assert isinstance(dn, DN)
+
# get original entry
(dn, entry_attrs_old) = self.get_entry(dn, entry_attrs.keys(), normalize=normalize)
- # get_entry returns a decoded entry, encode it back
- # we could call search_s directly, but this saves a lot of code at
- # the expense of a little bit of performace
- entry_attrs_old = self.encode(entry_attrs_old)
+
# generate modlist
# for multi value attributes: no MOD_REPLACE to handle simultaneous
# updates better
@@ -1009,13 +1362,14 @@ class ldap2(CrudBackend, Encoder):
return modlist
- @encode_args(1, 2)
def update_entry(self, dn, entry_attrs, normalize=True):
"""
Update entry's attributes.
An attribute value set to None deletes all current values.
"""
+
+ assert isinstance(dn, DN)
if normalize:
dn = self.normalize_dn(dn)
@@ -1028,37 +1382,40 @@ class ldap2(CrudBackend, Encoder):
try:
self.conn.modify_s(dn, modlist)
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
- @encode_args(1)
def delete_entry(self, dn, normalize=True):
"""Delete entry."""
+
+ assert isinstance(dn, DN)
if normalize:
dn = self.normalize_dn(dn)
+
try:
self.conn.delete_s(dn)
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
- @encode_args(1, 2, 3)
def modify_password(self, dn, new_pass, old_pass=''):
"""Set user password."""
+
+ assert isinstance(dn, DN)
dn = self.normalize_dn(dn)
# The python-ldap passwd command doesn't verify the old password
# so we'll do a simple bind to validate it.
if old_pass != '':
try:
- conn = _ldap.initialize(self.ldap_uri)
+ conn = IPASimpleLDAPObject(self.ldap_uri)
conn.simple_bind_s(dn, old_pass)
conn.unbind()
except _ldap.LDAPError, e:
- _handle_errors(e, **{})
+ self.handle_errors(e)
try:
self.conn.passwd_s(dn, old_pass, new_pass)
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
def add_entry_to_group(self, dn, group_dn, member_attr='member', allow_same=False):
"""
@@ -1068,12 +1425,18 @@ class ldap2(CrudBackend, Encoder):
Adding a group as a member of itself is not allowed unless allow_same
is True.
"""
+
+ assert isinstance(dn, DN)
+ assert isinstance(group_dn, DN)
+
+ self.debug("add_entry_to_group: dn=%s group_dn=%s member_attr=%s", dn, group_dn, member_attr)
# check if the entry exists
(dn, entry_attrs) = self.get_entry(dn, ['objectclass'])
# get group entry
(group_dn, group_entry_attrs) = self.get_entry(group_dn, [member_attr])
+ self.debug("add_entry_to_group: group_entry_attrs=%s", group_entry_attrs)
# check if we're not trying to add group into itself
if dn == group_dn and not allow_same:
raise errors.SameGroupError()
@@ -1091,16 +1454,23 @@ class ldap2(CrudBackend, Encoder):
def remove_entry_from_group(self, dn, group_dn, member_attr='member'):
"""Remove entry from group."""
+
+ assert isinstance(dn, DN)
+ assert isinstance(group_dn, DN)
+
+ self.debug("remove_entry_from_group: dn=%s group_dn=%s member_attr=%s", dn, group_dn, member_attr)
# get group entry
(group_dn, group_entry_attrs) = self.get_entry(group_dn, [member_attr])
+ self.debug("remove_entry_from_group: group_entry_attrs=%s", group_entry_attrs)
# remove dn from group entry's `member_attr` attribute
- members = [DN(m) for m in group_entry_attrs.get(member_attr, [])]
+ members = group_entry_attrs.get(member_attr, [])
+ assert all([isinstance(x, DN) for x in members])
try:
- members.remove(DN(dn))
+ members.remove(dn)
except ValueError:
raise errors.NotGroupMember()
- group_entry_attrs[member_attr] = [str(m) for m in members]
+ group_entry_attrs[member_attr] = members
# update group entry
self.update_entry(group_dn, group_entry_attrs)
@@ -1118,10 +1488,14 @@ class ldap2(CrudBackend, Encoder):
Returns a list of DNs.
"""
+
+ assert isinstance(group_dn, DN)
+
if membertype not in [MEMBERS_ALL, MEMBERS_DIRECT, MEMBERS_INDIRECT]:
return None
- search_group_dn = _ldap_filter.escape_filter_chars(group_dn)
+ self.debug("get_members: group_dn=%s members=%s membertype=%s", group_dn, members, membertype)
+ search_group_dn = _ldap_filter.escape_filter_chars(str(group_dn))
searchfilter = "(memberof=%s)" % search_group_dn
attr_list.append("member")
@@ -1130,18 +1504,23 @@ class ldap2(CrudBackend, Encoder):
results = []
if membertype == MEMBERS_ALL or membertype == MEMBERS_INDIRECT:
- checkmembers = copy.deepcopy(members)
- for member in checkmembers:
+ user_container_dn = DN(api.env.container_user, api.env.basedn) # FIXME, initialize once
+ host_container_dn = DN(api.env.container_host, api.env.basedn)
+ checkmembers = set(DN(x) for x in members)
+ checked = set()
+ while checkmembers:
+ member_dn = checkmembers.pop()
+ checked.add(member_dn)
+
# No need to check entry types that are not nested for
# additional members
- dn = DN(member)
- if dn.endswith(DN(api.env.container_user, api.env.basedn)) or \
- dn.endswith(DN(api.env.container_host, api.env.basedn)):
- results.append([member, {}])
+ if member_dn.endswith(user_container_dn) or \
+ member_dn.endswith(host_container_dn):
+ results.append([member_dn, {}])
continue
try:
(result, truncated) = self.find_entries(searchfilter,
- attr_list, member, time_limit=time_limit,
+ attr_list, member_dn, time_limit=time_limit,
size_limit=size_limit, scope=_ldap.SCOPE_BASE,
normalize=normalize)
if truncated:
@@ -1150,8 +1529,8 @@ class ldap2(CrudBackend, Encoder):
for m in result[0][1].get('member', []):
# This member may contain other members, add it to our
# candidate list
- if m not in checkmembers:
- checkmembers.append(m)
+ if m not in checked:
+ checkmembers.add(m)
except errors.NotFound:
pass
@@ -1164,21 +1543,18 @@ class ldap2(CrudBackend, Encoder):
(dn, group) = self.get_entry(group_dn, ['dn', 'member'],
size_limit=size_limit, time_limit=time_limit)
- real_members = group.get('member')
- if isinstance(real_members, basestring):
- real_members = [real_members]
- if real_members is None:
- real_members = []
+ real_members = group.get('member', [])
entries = []
for e in results:
- if unicode(e[0]) not in real_members and unicode(e[0]) not in entries:
+ if e[0] not in real_members and e[0] not in entries:
if membertype == MEMBERS_INDIRECT:
entries.append(e[0])
else:
if membertype == MEMBERS_DIRECT:
entries.append(e[0])
+ self.debug("get_members: result=%s", entries)
return entries
def get_memberof(self, entry_dn, memberof, time_limit=None, size_limit=None, normalize=True):
@@ -1192,12 +1568,15 @@ class ldap2(CrudBackend, Encoder):
Returns two memberof lists: (direct, indirect)
"""
+ assert isinstance(entry_dn, DN)
+
+ self.debug("get_memberof: entry_dn=%s memberof=%s", entry_dn, memberof)
if not type(memberof) in (list, tuple):
return ([], [])
if len(memberof) == 0:
return ([], [])
- search_entry_dn = _ldap_filter.escape_filter_chars(entry_dn)
+ search_entry_dn = _ldap_filter.escape_filter_chars(str(entry_dn))
attr_list = ["dn", "memberof"]
searchfilter = "(|(member=%s)(memberhost=%s)(memberuser=%s))" % (
search_entry_dn, search_entry_dn, search_entry_dn)
@@ -1207,6 +1586,7 @@ class ldap2(CrudBackend, Encoder):
results = []
for group in memberof:
+ assert isinstance(group, DN)
try:
(result, truncated) = self.find_entries(searchfilter, attr_list,
group, time_limit=time_limit,size_limit=size_limit,
@@ -1219,20 +1599,24 @@ class ldap2(CrudBackend, Encoder):
# If there is an exception here, it is likely due to a failure in
# referential integrity. All members should have corresponding
# memberOf entries.
- indirect = [ m.lower() for m in memberof ]
+ indirect = list(memberof)
for r in results:
direct.append(r[0])
try:
- indirect.remove(r[0].lower())
+ indirect.remove(r[0])
except ValueError, e:
- root_logger.info('Failed to remove indirect entry %s from %s' % r[0], entry_dn)
+ self.info('Failed to remove indirect entry %s from %s' % r[0], entry_dn)
raise e
+ self.debug("get_memberof: result direct=%s indirect=%s", direct, indirect)
return (direct, indirect)
def set_entry_active(self, dn, active):
"""Mark entry active/inactive."""
+
+ assert isinstance(dn, DN)
assert isinstance(active, bool)
+
# get the entry in question
(dn, entry_attrs) = self.get_entry(dn, ['nsaccountlock'])
@@ -1255,15 +1639,20 @@ class ldap2(CrudBackend, Encoder):
def activate_entry(self, dn):
"""Mark entry active."""
+
+ assert isinstance(dn, DN)
self.set_entry_active(dn, True)
def deactivate_entry(self, dn):
"""Mark entry inactive."""
+
+ assert isinstance(dn, DN)
self.set_entry_active(dn, False)
def remove_principal_key(self, dn):
"""Remove a kerberos principal key."""
+ assert isinstance(dn, DN)
dn = self.normalize_dn(dn)
# We need to do this directly using the LDAP library because we
@@ -1275,11 +1664,14 @@ class ldap2(CrudBackend, Encoder):
try:
self.conn.modify_s(dn, mod)
except _ldap.LDAPError, e:
- _handle_errors(e)
+ self.handle_errors(e)
# CrudBackend methods
def _get_normalized_entry_for_crud(self, dn, attrs_list=None):
+
+ assert isinstance(dn, DN)
+
(dn, entry_attrs) = self.get_entry(dn, attrs_list)
entry_attrs['dn'] = dn
return entry_attrs
@@ -1292,6 +1684,7 @@ class ldap2(CrudBackend, Encoder):
"""
assert 'dn' in kw
dn = kw['dn']
+ assert isinstance(dn, DN)
del kw['dn']
self.add_entry(dn, kw)
return self._get_normalized_entry_for_crud(dn)
@@ -1337,7 +1730,8 @@ class ldap2(CrudBackend, Encoder):
# get keyword arguments
filter = kw.pop('filter', None)
attrs_list = kw.pop('attrs_list', None)
- base_dn = kw.pop('base_dn', '')
+ base_dn = kw.pop('base_dn', DN())
+ assert isinstance(base_dn, DN)
scope = kw.pop('scope', self.SCOPE_SUBTREE)
# generate filter
@@ -1363,4 +1757,3 @@ class ldap2(CrudBackend, Encoder):
return (len(output), output)
api.register(ldap2)
-
diff --git a/ipaserver/plugins/selfsign.py b/ipaserver/plugins/selfsign.py
index bbf8fa78a..09ed04f49 100644
--- a/ipaserver/plugins/selfsign.py
+++ b/ipaserver/plugins/selfsign.py
@@ -39,6 +39,7 @@ from ipalib import Backend
from ipalib import errors
from ipalib import x509
from ipalib import pkcs10
+from ipapython.dn import DN, EditableDN, RDN
from ipapython.certdb import get_ca_nickname
import subprocess
import os
@@ -86,16 +87,14 @@ class ra(rabase.rabase):
"""
try:
config = api.Command['config_show']()['result']
- subject_base = config.get('ipacertificatesubjectbase')[0]
+ subject_base = EditableDN(config.get('ipacertificatesubjectbase')[0])
hostname = get_csr_hostname(csr)
- base = re.split(',\s*(?=\w+=)', subject_base)
- base.insert(0,'CN=%s' % hostname)
- subject_base = ",".join(base)
+ subject_base.insert(0, RDN(('CN', hostname)))
request = pkcs10.load_certificate_request(csr)
# python-nss normalizes the request subject
- request_subject = str(pkcs10.get_subject(request))
+ request_subject = DN(pkcs10.get_subject(request))
- if str(subject_base).lower() != request_subject.lower():
+ if subject_base != request_subject:
raise errors.CertificateOperationError(error=_('Request subject "%(request_subject)s" does not match the form "%(subject_base)s"') % \
{'request_subject' : request_subject, 'subject_base' : subject_base})
except errors.CertificateOperationError, e:
diff --git a/ipaserver/rpcserver.py b/ipaserver/rpcserver.py
index c770290f1..f7b71b32f 100644
--- a/ipaserver/rpcserver.py
+++ b/ipaserver/rpcserver.py
@@ -32,7 +32,7 @@ from ipalib.errors import PublicError, InternalError, CommandError, JSONError, C
from ipalib.request import context, Connection, destroy_context
from ipalib.rpc import xml_dumps, xml_loads
from ipalib.util import parse_time_duration
-from ipalib.dn import DN
+from ipapython.dn import DN
from ipaserver.plugins.ldap2 import ldap2
from ipapython.compat import json
from ipalib.session import session_mgr, AuthManager, get_ipa_ccache_name, load_ccache_data, bind_ipa_ccache, release_ipa_ccache, fmt_time, default_max_session_duration
@@ -418,29 +418,17 @@ def json_encode_binary(val):
if isinstance(val, dict):
new_dict = {}
for k,v in val.items():
- if isinstance(v, str):
- new_dict[k] = {'__base64__' : base64.b64encode(v)}
- else:
- new_dict[k] = json_encode_binary(v)
- del val
+ new_dict[k] = json_encode_binary(v)
return new_dict
elif isinstance(val, (list, tuple)):
- new_list = []
- n = len(val)
- i = 0
- while i < n:
- v = val[i]
- if isinstance(v, str):
- new_list.append({'__base64__' : base64.b64encode(v)})
- else:
- new_list.append(json_encode_binary(v))
- i += 1
- del val
+ new_list = [json_encode_binary(v) for v in val]
return new_list
elif isinstance(val, str):
return {'__base64__' : base64.b64encode(val)}
elif isinstance(val, Decimal):
return {'__base64__' : base64.b64encode(str(val))}
+ elif isinstance(val, DN):
+ return str(val)
else:
return val
@@ -474,7 +462,6 @@ def json_decode_binary(val):
new_dict[k] = base64.b64decode(v['__base64__'])
else:
new_dict[k] = json_decode_binary(v)
- del val
return new_dict
elif isinstance(val, list):
new_list = []
@@ -488,7 +475,6 @@ def json_decode_binary(val):
else:
new_list.append(json_decode_binary(v))
i += 1
- del val
return new_list
else:
if isinstance(val, basestring):
@@ -963,9 +949,9 @@ class login_password(Backend, KerberosSession, HTTP_Status):
# Ok, now why is this bad. Is the password simply bad or is the
# password expired?
try:
- dn = str(DN(('uid', user),
- self.api.env.container_user,
- self.api.env.basedn))
+ dn = DN(('uid', user),
+ self.api.env.container_user,
+ self.api.env.basedn)
conn = ldap2(shared_instance=False,
ldap_uri=self.api.env.ldap_uri)
conn.connect(bind_dn=dn, bind_pw=password)
@@ -1059,8 +1045,8 @@ class change_password(Backend, HTTP_Status):
result = 'error'
policy_error = None
- bind_dn = str(DN((self.api.Object.user.primary_key.name, data['user']),
- self.api.env.container_user, self.api.env.basedn))
+ bind_dn = DN((self.api.Object.user.primary_key.name, data['user']),
+ self.api.env.container_user, self.api.env.basedn)
try:
conn = ldap2(shared_instance=False,
diff --git a/make-lint b/make-lint
index 05a1bb14f..29ce758ed 100755
--- a/make-lint
+++ b/make-lint
@@ -65,6 +65,10 @@ class IPATypeChecker(TypeChecker):
'ipalib.parameters.Enum': ['values'],
'ipalib.parameters.File': ['stdin_if_missing'],
'urlparse.SplitResult': ['netloc'],
+ 'ipaserver.install.ldapupdate.LDAPUpdate' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
+ 'ipaserver.plugins.ldap2.SchemaCache' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
+ 'ipaserver.plugins.ldap2.IPASimpleLDAPObject' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
+ 'ipaserver.plugins.ldap2.ldap2' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipaserver.rpcserver.KerberosSession' : ['api', 'log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipaserver.rpcserver.HTTP_Status' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
'ipalib.krb_utils.KRB5_CCache' : ['log', 'debug', 'info', 'warning', 'error', 'critical', 'exception'],
diff --git a/make-testcert b/make-testcert
index f5a2fa775..a5814e1de 100755
--- a/make-testcert
+++ b/make-testcert
@@ -31,6 +31,7 @@ import nss.nss as nss
from ipalib import api, x509, backend, errors
from ipaserver.plugins import rabase
from ipapython import ipautil
+from ipapython.dn import DN
CERTPATH = 'tests/test_xmlrpc/service.crt'
@@ -101,9 +102,9 @@ def makecert(reqdir):
subject_base = res['result']['ipacertificatesubjectbase'][0]
cert = None
- subject = 'CN=%s,%s' % (api.env.host, subject_base)
+ subject = DN(('CN', api.env.host), subject_base)
princ = 'unittest/%s@%s' % (api.env.host, api.env.realm)
- csr = unicode(generateCSR(reqdir, pwname, subject))
+ csr = unicode(generateCSR(reqdir, pwname, str(subject)))
try:
res = api.Backend.client.run('cert_request', csr, principal=princ,
diff --git a/tests/test_cmdline/test_ipagetkeytab.py b/tests/test_cmdline/test_ipagetkeytab.py
index 0437c80bb..b01fdee9f 100644
--- a/tests/test_cmdline/test_ipagetkeytab.py
+++ b/tests/test_cmdline/test_ipagetkeytab.py
@@ -31,7 +31,7 @@ import nose
import tempfile
import krbV
from ipaserver.plugins.ldap2 import ldap2
-from ipalib.dn import *
+from ipapython.dn import DN
def use_keytab(principal, keytab):
try:
diff --git a/tests/test_install/0_reset.update b/tests/test_install/0_reset.update
index ba2af5e06..bd6ee636d 100644
--- a/tests/test_install/0_reset.update
+++ b/tests/test_install/0_reset.update
@@ -1,5 +1,5 @@
dn: uid=tuser, cn=test, cn=accounts, $SUFFIX
-deleteentry: reset: nada
+deleteentry:
dn: cn=test, cn=accounts, $SUFFIX
deleteentry: reset: nada
diff --git a/tests/test_install/test_updates.py b/tests/test_install/test_updates.py
index 8b9ac28eb..711af3db4 100644
--- a/tests/test_install/test_updates.py
+++ b/tests/test_install/test_updates.py
@@ -20,19 +20,18 @@
Test the `ipaserver/install/ldapupdate.py` module.
"""
+import unittest
import os
import sys
import ldap
import nose
-from nose.tools import raises
-from tests.util import PluginTester
-from tests.data import unicode_str
from ipalib import api
from ipalib import errors
from ipaserver.install.ldapupdate import LDAPUpdate, BadSyntax, UPDATES_DIR
from ipaserver.install import installutils
from ipaserver import ipaldap
from ipapython import ipautil
+from ipapython.dn import DN
"""
The updater works through files only so this is just a thin-wrapper controlling
@@ -46,7 +45,7 @@ have occurred as expected.
The DM password needs to be set in ~/.ipa/.dmpw
"""
-class test_update(object):
+class test_update(unittest.TestCase):
"""
Test the LDAP updater.
"""
@@ -70,13 +69,16 @@ class test_update(object):
else:
raise nose.SkipTest("Unable to find test update files")
+ self.container_dn = DN(self.updater._template_str('cn=test, cn=accounts, $SUFFIX'))
+ self.user_dn = DN(self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX'))
+
def tearDown(self):
if self.ld:
self.ld.unbind()
def test_0_reset(self):
"""
- Reset the updater test data to a known initial state
+ Reset the updater test data to a known initial state (test_0_reset)
"""
try:
modified = self.updater.update([self.testdir + "0_reset.update"])
@@ -84,96 +86,121 @@ class test_update(object):
# Just means the entry doesn't exist yet
modified = True
- assert(modified == True)
+ self.assertTrue(modified)
+
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.container_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
def test_1_add(self):
"""
- Test the updater with an add directive
+ Test the updater with an add directive (test_1_add)
"""
modified = self.updater.update([self.testdir + "1_add.update"])
- assert(modified == True)
+ self.assertTrue(modified)
+
+ entries = self.ld.getList(self.container_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+
+ objectclasses = entry.getValues('objectclass')
+ for item in ('top', 'nsContainer'):
+ self.assertTrue(item in objectclasses)
+
+ self.assertEqual(entry.getValue('cn'), 'test')
+
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+
+ objectclasses = entry.getValues('objectclass')
+ for item in ('top', 'person', 'posixaccount', 'krbprincipalaux', 'inetuser'):
+ self.assertTrue(item in objectclasses)
+
+ self.assertEqual(entry.getValue('loginshell'), '/bin/bash')
+ self.assertEqual(entry.getValue('sn'), 'User')
+ self.assertEqual(entry.getValue('uid'), 'tuser')
+ self.assertEqual(entry.getValue('cn'), 'Test User')
+
def test_2_update(self):
"""
- Test the updater when adding an attribute to an existing entry
+ Test the updater when adding an attribute to an existing entry (test_2_update)
"""
modified = self.updater.update([self.testdir + "2_update.update"])
- assert(modified == True)
+ self.assertTrue(modified)
- # The update passed, lets look at the record and see if it is
- # really updated
- dn = self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX')
- entry = self.ld.getList(dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
- assert (len(entry) == 1)
- assert(entry[0].gecos == 'Test User')
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+ self.assertEqual(entry.getValue('gecos'), 'Test User')
def test_3_update(self):
"""
- Test the updater forcing an attribute to a given value
+ Test the updater forcing an attribute to a given value (test_3_update)
"""
modified = self.updater.update([self.testdir + "3_update.update"])
- assert(modified == True)
+ self.assertTrue(modified)
- # The update passed, lets look at the record and see if it is
- # really updated
- dn = self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX')
- entry = self.ld.getList(dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
- assert (len(entry) == 1)
- assert(entry[0].gecos == 'Test User New')
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+ self.assertEqual(entry.getValue('gecos'), 'Test User New')
def test_4_update(self):
"""
- Test the updater adding a new value to a single-valued attribute
+ Test the updater adding a new value to a single-valued attribute (test_4_update)
"""
modified = self.updater.update([self.testdir + "4_update.update"])
- assert(modified == True)
+ self.assertTrue(modified)
+
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+ self.assertEqual(entry.getValue('gecos'), 'Test User New2')
def test_5_update(self):
"""
- Test the updater adding a new value to a multi-valued attribute
+ Test the updater adding a new value to a multi-valued attribute (test_5_update)
"""
modified = self.updater.update([self.testdir + "5_update.update"])
- assert(modified == True)
+ self.assertTrue(modified)
- # The update passed, lets look at the record and see if it is
- # really updated
- dn = self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX')
- entry = self.ld.getList(dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
- assert (len(entry) == 1)
- assert(entry[0].getValues('cn') == ['Test User', 'Test User New'])
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+ self.assertEqual(sorted(entry.getValues('cn')), sorted(['Test User', 'Test User New']))
def test_6_update(self):
"""
- Test the updater removing a value from a multi-valued attribute
+ Test the updater removing a value from a multi-valued attribute (test_6_update)
"""
modified = self.updater.update([self.testdir + "6_update.update"])
- assert(modified == True)
+ self.assertTrue(modified)
- # The update passed, lets look at the record and see if it is
- # really updated
- dn = self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX')
- entry = self.ld.getList(dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
- assert (len(entry) == 1)
- assert(entry[0].cn == 'Test User')
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+ self.assertEqual(sorted(entry.getValues('cn')), sorted(['Test User']))
def test_6_update_1(self):
"""
- Test the updater removing a non-existent value from a multi-valued attribute
+ Test the updater removing a non-existent value from a multi-valued attribute (test_6_update_1)
"""
modified = self.updater.update([self.testdir + "6_update.update"])
- assert(modified == False)
+ self.assertFalse(modified)
- # The update passed, lets look at the record and see if it is
- # really updated
- dn = self.updater._template_str('uid=tuser, cn=test, cn=accounts, $SUFFIX')
- entry = self.ld.getList(dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
- assert (len(entry) == 1)
- assert(entry[0].cn == 'Test User')
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+ self.assertEqual(sorted(entry.getValues('cn')), sorted(['Test User']))
def test_7_cleanup(self):
"""
- Reset the test data to a known initial state
+ Reset the test data to a known initial state (test_7_cleanup)
"""
try:
modified = self.updater.update([self.testdir + "0_reset.update"])
@@ -181,18 +208,113 @@ class test_update(object):
# Just means the entry doesn't exist yet
modified = True
- assert(modified == True)
+ self.assertTrue(modified)
+
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.container_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
- @raises(BadSyntax)
def test_8_badsyntax(self):
"""
- Test the updater with an unknown keyword
+ Test the updater with an unknown keyword (test_8_badsyntax)
"""
- modified = self.updater.update([self.testdir + "8_badsyntax.update"])
+ with self.assertRaises(BadSyntax):
+ modified = self.updater.update([self.testdir + "8_badsyntax.update"])
- @raises(BadSyntax)
def test_9_badsyntax(self):
"""
- Test the updater with an incomplete line
+ Test the updater with an incomplete line (test_9_badsyntax)
+ """
+ with self.assertRaises(BadSyntax):
+ modified = self.updater.update([self.testdir + "9_badsyntax.update"])
+
+ def test_from_dict(self):
+ """
+ Test updating from a dict.
+
+ This replicates what was done in test 1.
"""
- modified = self.updater.update([self.testdir + "9_badsyntax.update"])
+
+ # First make sure we're clean
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.container_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+
+
+ update = {
+ self.container_dn:
+ {'dn': self.container_dn,
+ 'updates': ['add:objectClass: top',
+ 'add:objectClass: nsContainer',
+ 'add:cn: test'
+ ],
+ },
+ self.user_dn:
+ {'dn': self.user_dn,
+ 'updates': ['add:objectclass: top',
+ 'add:objectclass: person',
+ 'add:objectclass: posixaccount',
+ 'add:objectclass: krbprincipalaux',
+ 'add:objectclass: inetuser',
+ 'add:homedirectory: /home/tuser',
+ 'add:loginshell: /bin/bash',
+ 'add:sn: User',
+ 'add:uid: tuser',
+ 'add:uidnumber: 999',
+ 'add:gidnumber: 999',
+ 'add:cn: Test User',
+ ],
+ },
+ }
+
+ modified = self.updater.update_from_dict(update)
+ self.assertTrue(modified)
+
+ entries = self.ld.getList(self.container_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+
+ objectclasses = entry.getValues('objectclass')
+ for item in ('top', 'nsContainer'):
+ self.assertTrue(item in objectclasses)
+
+ self.assertEqual(entry.getValue('cn'), 'test')
+
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+ self.assertEqual(len(entries), 1)
+ entry = entries[0]
+
+ objectclasses = entry.getValues('objectclass')
+ for item in ('top', 'person', 'posixaccount', 'krbprincipalaux', 'inetuser'):
+ self.assertTrue(item in objectclasses)
+
+ self.assertEqual(entry.getValue('loginshell'), '/bin/bash')
+ self.assertEqual(entry.getValue('sn'), 'User')
+ self.assertEqual(entry.getValue('uid'), 'tuser')
+ self.assertEqual(entry.getValue('cn'), 'Test User')
+
+ # Now delete
+
+ update = {
+ self.container_dn:
+ {'dn': self.container_dn,
+ 'deleteentry': None,
+ },
+ self.user_dn:
+ {'dn': self.user_dn,
+ 'deleteentry': 'deleteentry: reset: nada',
+ },
+ }
+
+ modified = self.updater.update_from_dict(update)
+ self.assertTrue(modified)
+
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.container_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
+
+ with self.assertRaises(errors.NotFound):
+ entries = self.ld.getList(self.user_dn, ldap.SCOPE_BASE, 'objectclass=*', ['*'])
diff --git a/tests/test_ipalib/test_dn.py b/tests/test_ipalib/test_dn.py
deleted file mode 100644
index 04e442f3f..000000000
--- a/tests/test_ipalib/test_dn.py
+++ /dev/null
@@ -1,1085 +0,0 @@
-#!/usr/bin/python
-
-import unittest
-from ipalib.dn import AVA, RDN, DN
-
-def default_rdn_attr_arg(i):
- return 'a%d' % i
-
-def default_rdn_value_arg(i):
- return str(i)
-
-def alt_rdn_attr_arg(i):
- return 'b%d' % i
-
-def alt_rdn_value_arg(i):
- return str(i*10)
-
-def make_rdn_args(low, high, kind, attr=None, value=None):
- result=[]
- for i in range(low, high):
- if attr is None:
- new_attr = default_rdn_attr_arg(i)
- elif callable(attr):
- new_attr = attr(i)
- else:
- new_attr = attr
-
- if value is None:
- new_value = default_rdn_value_arg(i)
- elif callable(value):
- new_value = value(i)
- else:
- new_value = value
-
- if kind == 'tuple':
- result.append((new_attr, new_value))
- elif kind == 'list':
- result.append([new_attr, new_value])
- elif kind == 'RDN':
- result.append(RDN((new_attr, new_value)))
- else:
- raise ValueError("Unknown kind = %s" % kind)
-
- return result
-
-class TestAVA(unittest.TestCase):
- def setUp(self):
- self.attr1 = 'cn'
- self.value1 = 'Bob'
- self.str_ava1 = '%s=%s' % (self.attr1, self.value1)
- self.ava1 = AVA(self.attr1, self.value1)
-
- def test_create(self):
- # Create with attr,value pair
- ava1 = AVA(self.attr1, self.value1)
- self.assertEqual(ava1, self.ava1)
-
- # Create with "attr=value" string
- ava1 = AVA(self.str_ava1)
- self.assertEqual(ava1, self.ava1)
-
- # Create with tuple (attr, value)
- ava1 = AVA((self.attr1, self.value1))
- self.assertEqual(ava1, self.ava1)
-
- # Create with list [attr, value]
- ava1 = AVA([self.attr1, self.value1])
- self.assertEqual(ava1, self.ava1)
-
- # Create with no args should fail
- with self.assertRaises(TypeError):
- AVA()
-
- # Create with more than 2 args should fail
- with self.assertRaises(TypeError):
- AVA(self.attr1, self.value1, self.attr1)
-
- # Create with 1 arg which is not string should fail
- with self.assertRaises(TypeError):
- AVA(1)
-
- # Create with malformed AVA string should fail
- with self.assertRaises(ValueError):
- AVA("cn")
-
- # Create with non-string parameters, should fail
- with self.assertRaises(TypeError):
- AVA(1, self.value1)
-
- with self.assertRaises(TypeError):
- AVA(self.attr1, 1)
-
- with self.assertRaises(TypeError):
- AVA((1, self.value1))
-
- with self.assertRaises(TypeError):
- AVA((self.attr1, 1))
-
- def test_encoding(self):
- # Create with attr,value pair
- ava1 = AVA(self.attr1, self.value1)
- self.assertEqual(ava1, self.ava1)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
-
- ava1 = AVA(unicode(self.attr1), self.value1)
- self.assertEqual(ava1, self.ava1)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
-
- ava1 = AVA(self.attr1, unicode(self.value1))
- self.assertEqual(ava1, self.ava1)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
-
- # Create with "attr=value" string
- ava1 = AVA(self.str_ava1)
- self.assertEqual(ava1, self.ava1)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
-
- ava1 = AVA(unicode(self.ava1))
- self.assertEqual(ava1, self.ava1)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
-
- # Create with tuple (attr, value)
- ava1 = AVA((unicode(self.attr1), self.value1))
- self.assertEqual(ava1, self.ava1)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
-
- ava1 = AVA((self.attr1, unicode(self.value1)))
- self.assertEqual(ava1, self.ava1)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
-
- def test_indexing(self):
- self.assertEqual(self.ava1[self.attr1], self.value1)
-
- with self.assertRaises(KeyError):
- self.ava1['foo']
-
- with self.assertRaises(TypeError):
- self.ava1[0]
-
- def test_properties(self):
- self.assertEqual(self.ava1.attr, self.attr1)
- self.assertEqual(self.ava1.value, self.value1)
-
- def test_str(self):
- self.assertEqual(str(self.ava1), self.str_ava1)
- self.assertIsInstance(str(self.ava1), str)
-
- def test_cmp(self):
- # Equality
- ava1 = AVA(self.attr1, self.value1)
-
- self.assertTrue(ava1 == self.ava1)
- self.assertFalse(ava1 != self.ava1)
-
- result = cmp(ava1, self.ava1)
- self.assertEqual(result, 0)
-
- # Upper case attr should still be equal
- ava1 = AVA(self.attr1.upper(), self.value1)
-
- self.assertFalse(ava1.attr == self.attr1)
- self.assertTrue(ava1.value == self.value1)
- self.assertTrue(ava1 == self.ava1)
- self.assertFalse(ava1 != self.ava1)
-
- result = cmp(ava1, self.ava1)
- self.assertEqual(result, 0)
-
- # Upper case value should still be equal
- ava1 = AVA(self.attr1, self.value1.upper())
-
- self.assertTrue(ava1.attr == self.attr1)
- self.assertFalse(ava1.value == self.value1)
- self.assertTrue(ava1 == self.ava1)
- self.assertFalse(ava1 != self.ava1)
-
- result = cmp(ava1, self.ava1)
- self.assertEqual(result, 0)
-
- # Make ava1's attr greater
- ava1.attr = self.attr1 + "1"
-
- self.assertFalse(ava1 == self.ava1)
- self.assertTrue(ava1 != self.ava1)
-
- result = cmp(ava1, self.ava1)
- self.assertEqual(result, 1)
-
- result = cmp(self.ava1, ava1)
- self.assertEqual(result, -1)
-
- # Reset ava1's attr, should be equal again
- ava1.attr = self.attr1
-
- result = cmp(ava1, self.ava1)
- self.assertEqual(result, 0)
-
- # Make ava1's value greater
- # attr will be equal, this tests secondary comparision component
- ava1.value = self.value1 + "1"
-
- result = cmp(ava1, self.ava1)
- self.assertEqual(result, 1)
-
- result = cmp(self.ava1, ava1)
- self.assertEqual(result, -1)
-
-class TestRDN(unittest.TestCase):
- def setUp(self):
- # ava1 must sort before ava2
- self.attr1 = 'cn'
- self.value1 = 'Bob'
- self.str_ava1 = '%s=%s' % (self.attr1, self.value1)
- self.ava1 = AVA(self.attr1, self.value1)
-
- self.str_rdn1 = '%s=%s' % (self.attr1, self.value1)
- self.rdn1 = RDN((self.attr1, self.value1))
-
- self.attr2 = 'ou'
- self.value2 = 'people'
- self.str_ava2 = '%s=%s' % (self.attr2, self.value2)
- self.ava2 = AVA(self.attr2, self.value2)
-
- self.str_rdn2 = '%s=%s' % (self.attr2, self.value2)
- self.rdn2 = RDN((self.attr2, self.value2))
-
- self.str_ava3 = '%s=%s+%s=%s' % (self.attr1, self.value1, self.attr2, self.value2)
-
- self.str_rdn3 = '%s=%s+%s=%s' % (self.attr1, self.value1, self.attr2, self.value2)
- self.rdn3 = RDN(self.ava1, self.ava2)
-
- def test_create(self):
- # Create with single attr,value pair
- rdn1 = RDN((self.attr1, self.value1))
- self.assertEqual(len(rdn1), 1)
- self.assertEqual(rdn1, self.rdn1)
- self.assertIsInstance(rdn1[0], AVA)
- self.assertEqual(rdn1[0], self.ava1)
-
- # Create with multiple attr,value pairs
- rdn3 = RDN((self.attr1, self.value1), (self.attr2, self.value2))
- self.assertEqual(len(rdn3), 2)
- self.assertEqual(rdn3, self.rdn3)
- self.assertIsInstance(rdn3[0], AVA)
- self.assertEqual(rdn3[0], self.ava1)
- self.assertIsInstance(rdn3[1], AVA)
- self.assertEqual(rdn3[1], self.ava2)
-
- # Create with multiple attr,value pairs passed as lists
- rdn3 = RDN([self.attr1, self.value1], [self.attr2, self.value2])
- self.assertEqual(len(rdn3), 2)
- self.assertEqual(rdn3, self.rdn3)
- self.assertIsInstance(rdn3[0], AVA)
- self.assertEqual(rdn3[0], self.ava1)
- self.assertIsInstance(rdn3[1], AVA)
- self.assertEqual(rdn3[1], self.ava2)
-
- # Create with multiple attr,value pairs but reverse
- # constructor parameter ordering. RDN canonical ordering
- # should remain the same
- rdn3 = RDN((self.attr2, self.value2), (self.attr1, self.value1))
- self.assertEqual(len(rdn3), 2)
- self.assertEqual(rdn3, self.rdn3)
- self.assertIsInstance(rdn3[0], AVA)
- self.assertEqual(rdn3[0], self.ava1)
- self.assertIsInstance(rdn3[1], AVA)
- self.assertEqual(rdn3[1], self.ava2)
-
- # Create with single AVA object
- rdn1 = RDN(self.ava1)
- self.assertEqual(len(rdn1), 1)
- self.assertEqual(rdn1, self.rdn1)
- self.assertIsInstance(rdn1[0], AVA)
- self.assertEqual(rdn1[0], self.ava1)
-
- # Create with multiple AVA objects
- rdn3 = RDN(self.ava1, self.ava2)
- self.assertEqual(len(rdn3), 2)
- self.assertEqual(rdn3, self.rdn3)
- self.assertIsInstance(rdn3[0], AVA)
- self.assertEqual(rdn3[0], self.ava1)
- self.assertIsInstance(rdn3[1], AVA)
- self.assertEqual(rdn3[1], self.ava2)
-
-
- # Create with multiple AVA objects but reverse constructor
- # parameter ordering. RDN canonical ordering should remain
- # the same
- rdn3 = RDN(self.ava2, self.ava1)
- self.assertEqual(len(rdn3), 2)
- self.assertEqual(rdn3, self.rdn3)
- self.assertIsInstance(rdn3[0], AVA)
- self.assertEqual(rdn3[0], self.ava1)
- self.assertIsInstance(rdn3[1], AVA)
- self.assertEqual(rdn3[1], self.ava2)
-
- # Create with single string with 1 AVA
- rdn1 = RDN(self.str_rdn1)
- self.assertEqual(len(rdn1), 1)
- self.assertEqual(rdn1, self.rdn1)
- self.assertIsInstance(rdn1[0], AVA)
- self.assertEqual(rdn1[0], self.ava1)
-
- # Create with single string with 2 AVA's
- rdn3 = RDN(self.str_rdn3)
- self.assertEqual(len(rdn3), 2)
- self.assertEqual(rdn3, self.rdn3)
- self.assertIsInstance(rdn3[0], AVA)
- self.assertEqual(rdn3[0], self.ava1)
- self.assertIsInstance(rdn3[1], AVA)
- self.assertEqual(rdn3[1], self.ava2)
-
- def test_properties(self):
- self.assertEqual(self.rdn1.attr, self.attr1)
- self.assertIsInstance(self.rdn1.attr, unicode)
-
- self.assertEqual(self.rdn1.value, self.value1)
- self.assertIsInstance(self.rdn1.value, unicode)
-
- self.assertEqual(self.rdn2.attr, self.attr2)
- self.assertIsInstance(self.rdn2.attr, unicode)
-
- self.assertEqual(self.rdn2.value, self.value2)
- self.assertIsInstance(self.rdn2.value, unicode)
-
- self.assertEqual(self.rdn3.attr, self.attr1)
- self.assertIsInstance(self.rdn3.attr, unicode)
-
- self.assertEqual(self.rdn3.value, self.value1)
- self.assertIsInstance(self.rdn3.value, unicode)
-
- def test_str(self):
- self.assertEqual(str(self.rdn1), self.str_rdn1)
- self.assertIsInstance(str(self.rdn1), str)
-
- self.assertEqual(str(self.rdn2), self.str_rdn2)
- self.assertIsInstance(str(self.rdn2), str)
-
- self.assertEqual(str(self.rdn3), self.str_rdn3)
- self.assertIsInstance(str(self.rdn3), str)
-
- def test_cmp(self):
- # Equality
- rdn1 = RDN((self.attr1, self.value1))
-
- self.assertTrue(rdn1 == self.rdn1)
- self.assertFalse(rdn1 != self.rdn1)
-
- result = cmp(rdn1, self.rdn1)
- self.assertEqual(result, 0)
-
- # Make rdn1's attr greater
- rdn1.attr = self.attr1 + "1"
-
- self.assertFalse(rdn1 == self.rdn1)
- self.assertTrue(rdn1 != self.rdn1)
-
- result = cmp(rdn1, self.rdn1)
- self.assertEqual(result, 1)
-
- result = cmp(self.rdn1, rdn1)
- self.assertEqual(result, -1)
-
- # Reset rdn1's attr, should be equal again
- rdn1.attr = self.attr1
-
- result = cmp(rdn1, self.rdn1)
- self.assertEqual(result, 0)
-
- # Make rdn1's value greater
- # attr will be equal, this tests secondary comparision component
- rdn1.value = self.value1 + "1"
-
- result = cmp(rdn1, self.rdn1)
- self.assertEqual(result, 1)
-
- result = cmp(self.rdn1, rdn1)
- self.assertEqual(result, -1)
-
- # Make sure rdn's with more ava's are greater
- result = cmp(self.rdn1, self.rdn3)
- self.assertEqual(result, -1)
- result = cmp(self.rdn3, self.rdn1)
- self.assertEqual(result, 1)
-
- def test_indexing(self):
- self.assertEqual(self.rdn1[0], self.ava1)
- self.assertEqual(self.rdn1[self.ava1.attr], self.ava1.value)
- with self.assertRaises(KeyError):
- self.rdn1['foo']
-
- self.assertEqual(self.rdn2[0], self.ava2)
- self.assertEqual(self.rdn2[self.ava2.attr], self.ava2.value)
- with self.assertRaises(KeyError):
- self.rdn2['foo']
-
- self.assertEqual(self.rdn3[0], self.ava1)
- self.assertEqual(self.rdn3[self.ava1.attr], self.ava1.value)
- self.assertEqual(self.rdn3[1], self.ava2)
- self.assertEqual(self.rdn3[self.ava2.attr], self.ava2.value)
- with self.assertRaises(KeyError):
- self.rdn3['foo']
-
- self.assertEqual(self.rdn1.attr, self.attr1)
- self.assertEqual(self.rdn1.value, self.value1)
-
- with self.assertRaises(TypeError):
- self.rdn3[1.0]
-
- # Slices
- self.assertEqual(self.rdn3[0:1], [self.ava1])
- self.assertEqual(self.rdn3[:], [self.ava1, self.ava2])
-
- def test_assignments(self):
- rdn = RDN((self.attr1, self.value1))
- rdn[0] = self.ava2
- self.assertEqual(rdn, self.rdn2)
-
- rdn = RDN((self.attr1, self.value1))
- rdn[0] = (self.attr2, self.value2)
- self.assertEqual(rdn, self.rdn2)
-
- rdn = RDN((self.attr1, self.value1))
- rdn[self.attr1] = self.str_ava2
- self.assertEqual(rdn[0], self.ava2)
-
- # Can't assign multiples to single entry
- rdn = RDN((self.attr1, self.value1))
- with self.assertRaises(TypeError):
- rdn[self.attr1] = self.str_ava3
-
- rdn = RDN((self.attr1, self.value1))
- with self.assertRaises(TypeError):
- rdn[self.attr1] = (self.attr1, self.value1, self.attr2, self.value2)
-
- rdn = RDN((self.attr1, self.value1))
- with self.assertRaises(TypeError):
- rdn[self.attr1] = [(self.attr1, self.value1), (self.attr2, self.value2)]
-
- # Slices
- rdn = RDN((self.attr1, self.value1))
- self.assertEqual(rdn, self.rdn1)
- rdn[0:1] = [self.ava2]
- self.assertEqual(rdn, self.rdn2)
-
- rdn = RDN((self.attr1, self.value1))
- self.assertEqual(rdn, self.rdn1)
- rdn[:] = [(self.attr2, self.value2)]
- self.assertEqual(rdn, self.rdn2)
-
- rdn = RDN((self.attr1, self.value1))
- self.assertEqual(rdn, self.rdn1)
- rdn[:] = [(self.attr1, self.value1),(self.attr2, self.value2)]
- self.assertEqual(rdn, self.rdn3)
-
- rdn = RDN((self.attr1, self.value1))
- self.assertEqual(rdn, self.rdn1)
- rdn[0:1] = [(self.attr1, self.value1), (self.attr2, self.value2)]
- self.assertEqual(rdn, self.rdn3)
-
-
- def test_iter(self):
- self.assertEqual(len(self.rdn1), 1)
- self.assertEqual(self.rdn1[:], [self.ava1])
- for i, ava in enumerate(self.rdn1):
- if i == 0:
- self.assertEqual(ava, self.ava1)
- else:
- self.fail("got iteration index %d, but len=%d" % (i, len(self.rdn1)))
-
- self.assertEqual(len(self.rdn2), 1)
- self.assertEqual(self.rdn2[:], [self.ava2])
- for i, ava in enumerate(self.rdn2):
- if i == 0:
- self.assertEqual(ava, self.ava2)
- else:
- self.fail("got iteration index %d, but len=%d" % (i, len(self.rdn2)))
-
- self.assertEqual(len(self.rdn3), 2)
- self.assertEqual(self.rdn3[:], [self.ava1, self.ava2])
- for i, ava in enumerate(self.rdn3):
- if i == 0:
- self.assertEqual(ava, self.ava1)
- elif i == 1:
- self.assertEqual(ava, self.ava2)
- else:
- self.fail("got iteration index %d, but len=%d" % (i, len(self.rdn3)))
-
-
- def test_concat(self):
- rdn1 = RDN((self.attr1, self.value1))
- rdn2 = RDN((self.attr2, self.value2))
-
- # in-place addtion
- rdn1 += rdn2
- self.assertEqual(rdn1, self.rdn3)
-
- rdn1 = RDN((self.attr1, self.value1))
- rdn1 += self.ava2
- self.assertEqual(rdn1, self.rdn3)
-
- rdn1 = RDN((self.attr1, self.value1))
- rdn1 += self.str_ava2
- self.assertEqual(rdn1, self.rdn3)
-
- # concatenation
- rdn1 = RDN((self.attr1, self.value1))
- rdn3 = rdn1 + rdn2
- self.assertEqual(rdn3, self.rdn3)
-
- rdn3 = rdn1 + self.ava2
- self.assertEqual(rdn3, self.rdn3)
-
- rdn3 = rdn1 + self.str_ava2
- self.assertEqual(rdn3, self.rdn3)
-
-
-class TestDN(unittest.TestCase):
- def setUp(self):
- # ava1 must sort before ava2
- self.attr1 = 'cn'
- self.value1 = 'Bob'
- self.str_ava1 = '%s=%s' % (self.attr1, self.value1)
- self.ava1 = AVA(self.attr1, self.value1)
-
- self.str_rdn1 = '%s=%s' % (self.attr1, self.value1)
- self.rdn1 = RDN((self.attr1, self.value1))
-
- self.attr2 = 'ou'
- self.value2 = 'people'
- self.str_ava2 = '%s=%s' % (self.attr2, self.value2)
- self.ava2 = AVA(self.attr2, self.value2)
-
- self.str_rdn2 = '%s=%s' % (self.attr2, self.value2)
- self.rdn2 = RDN((self.attr2, self.value2))
-
- self.str_dn1 = self.str_rdn1
- self.dn1 = DN(self.rdn1)
-
- self.str_dn2 = self.str_rdn2
- self.dn2 = DN(self.rdn2)
-
- self.str_dn3 = '%s,%s' % (self.str_rdn1, self.str_rdn2)
- self.dn3 = DN(self.rdn1, self.rdn2)
-
- self.base_rdn1 = RDN(('dc', 'redhat'))
- self.base_rdn2 = RDN(('dc', 'com'))
- self.base_dn = DN(self.base_rdn1, self.base_rdn2)
-
- self.container_rdn1 = RDN(('cn', 'sudorules'))
- self.container_rdn2 = RDN(('cn', 'sudo'))
- self.container_dn = DN(self.container_rdn1, self.container_rdn2)
-
- self.base_container_dn = DN((self.attr1, self.value1),
- self.container_dn, self.base_dn)
-
-
- def test_create(self):
- # Create with single attr,value pair
- dn1 = DN((self.attr1, self.value1))
- self.assertEqual(len(dn1), 1)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
-
- # Create with single attr,value pair passed as a tuple
- dn1 = DN((self.attr1, self.value1))
- self.assertEqual(len(dn1), 1)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
-
- # Creation with multiple attr,value string pairs should fail
- with self.assertRaises(ValueError):
- dn1 = DN(self.attr1, self.value1, self.attr2, self.value2)
-
- # Create with multiple attr,value pairs passed as tuples & lists
- dn1 = DN((self.attr1, self.value1), [self.attr2, self.value2])
- self.assertEqual(len(dn1), 2)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
- self.assertIsInstance(dn1[1], RDN)
- self.assertIsInstance(dn1[1].attr, unicode)
- self.assertIsInstance(dn1[1].value, unicode)
- self.assertEqual(dn1[1], self.rdn2)
-
- # Create with multiple attr,value pairs passed as tuple and RDN
- dn1 = DN((self.attr1, self.value1), RDN((self.attr2, self.value2)))
- self.assertEqual(len(dn1), 2)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
- self.assertIsInstance(dn1[1], RDN)
- self.assertIsInstance(dn1[1].attr, unicode)
- self.assertIsInstance(dn1[1].value, unicode)
- self.assertEqual(dn1[1], self.rdn2)
-
- # Create with multiple attr,value pairs but reverse
- # constructor parameter ordering. RDN ordering should also be
- # reversed because DN's are a ordered sequence of RDN's
- dn1 = DN((self.attr2, self.value2), (self.attr1, self.value1))
- self.assertEqual(len(dn1), 2)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn2)
- self.assertIsInstance(dn1[1], RDN)
- self.assertIsInstance(dn1[1].attr, unicode)
- self.assertIsInstance(dn1[1].value, unicode)
- self.assertEqual(dn1[1], self.rdn1)
-
- # Create with single RDN object
- dn1 = DN(self.rdn1)
- self.assertEqual(len(dn1), 1)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
-
- # Create with multiple RDN objects, assure ordering is preserved.
- dn1 = DN(self.rdn1, self.rdn2)
- self.assertEqual(len(dn1), 2)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
- self.assertIsInstance(dn1[1], RDN)
- self.assertIsInstance(dn1[1].attr, unicode)
- self.assertIsInstance(dn1[1].value, unicode)
- self.assertEqual(dn1[1], self.rdn2)
-
- # Create with multiple RDN objects in different order, assure
- # ordering is preserved.
- dn1 = DN(self.rdn2, self.rdn1)
- self.assertEqual(len(dn1), 2)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn2)
- self.assertIsInstance(dn1[1], RDN)
- self.assertIsInstance(dn1[1].attr, unicode)
- self.assertIsInstance(dn1[1].value, unicode)
- self.assertEqual(dn1[1], self.rdn1)
-
- # Create with single string with 1 RDN
- dn1 = DN(self.str_rdn1)
- self.assertEqual(len(dn1), 1)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
-
- # Create with single string with 2 RDN's
- dn1 = DN(self.str_dn3)
- self.assertEqual(len(dn1), 2)
- self.assertIsInstance(dn1[0], RDN)
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0], self.rdn1)
- self.assertIsInstance(dn1[1], RDN)
- self.assertIsInstance(dn1[1].attr, unicode)
- self.assertIsInstance(dn1[1].value, unicode)
- self.assertEqual(dn1[1], self.rdn2)
-
- # Create with RDN, and 2 DN's (e.g. attr + container + base)
- dn1 = DN((self.attr1, self.value1), self.container_dn, self.base_dn)
- self.assertEqual(len(dn1), 5)
- dn_str = ','.join([str(self.rdn1),
- str(self.container_rdn1), str(self.container_rdn2),
- str(self.base_rdn1), str(self.base_rdn2)])
- self.assertEqual(str(dn1), dn_str)
-
- def test_str(self):
- self.assertEqual(str(self.dn1), self.str_dn1)
- self.assertIsInstance(str(self.dn1), str)
-
- self.assertEqual(str(self.dn2), self.str_dn2)
- self.assertIsInstance(str(self.dn2), str)
-
- self.assertEqual(str(self.dn3), self.str_dn3)
- self.assertIsInstance(str(self.dn3), str)
-
- def test_cmp(self):
- # Equality
- dn1 = DN((self.attr1, self.value1))
-
- self.assertTrue(dn1 == self.dn1)
- self.assertFalse(dn1 != self.dn1)
-
- result = cmp(dn1, self.dn1)
- self.assertEqual(result, 0)
-
- # Make dn1's attr greater
- dn1[0].attr = self.attr1 + "1"
-
- self.assertFalse(dn1 == self.dn1)
- self.assertTrue(dn1 != self.dn1)
-
- result = cmp(dn1, self.dn1)
- self.assertEqual(result, 1)
-
- result = cmp(self.dn1, dn1)
- self.assertEqual(result, -1)
-
- # Reset dn1's attr, should be equal again
- dn1[0].attr = self.attr1
-
- result = cmp(dn1, self.dn1)
- self.assertEqual(result, 0)
-
- # Make dn1's value greater
- # attr will be equal, this tests secondary comparision component
- dn1[0].value = self.value1 + "1"
-
- result = cmp(dn1, self.dn1)
- self.assertEqual(result, 1)
-
- result = cmp(self.dn1, dn1)
- self.assertEqual(result, -1)
-
- # Make sure dn's with more rdn's are greater
- result = cmp(self.dn1, self.dn3)
- self.assertEqual(result, -1)
- result = cmp(self.dn3, self.dn1)
- self.assertEqual(result, 1)
-
- # Test startswith, endswith
- self.assertTrue(self.base_container_dn.startswith(self.rdn1))
- self.assertTrue(self.base_container_dn.startswith(self.dn1))
- self.assertTrue(self.base_container_dn.startswith(self.dn1 + self.container_dn))
- self.assertFalse(self.base_container_dn.startswith(self.dn2))
- self.assertFalse(self.base_container_dn.startswith(self.rdn2))
- self.assertTrue(self.base_container_dn.startswith((self.dn1)))
- self.assertTrue(self.base_container_dn.startswith((self.rdn1)))
- self.assertFalse(self.base_container_dn.startswith((self.rdn2)))
- self.assertTrue(self.base_container_dn.startswith((self.rdn2, self.rdn1)))
- self.assertTrue(self.base_container_dn.startswith((self.dn1, self.dn2)))
-
- self.assertTrue(self.base_container_dn.endswith(self.base_dn))
- self.assertTrue(self.base_container_dn.endswith(self.container_dn + self.base_dn))
- self.assertFalse(self.base_container_dn.endswith(DN(self.base_rdn1)))
- self.assertTrue(self.base_container_dn.endswith(DN(self.base_rdn2)))
- self.assertTrue(self.base_container_dn.endswith((DN(self.base_rdn1), DN(self.base_rdn2))))
-
- # Test "in" membership
- self.assertTrue(self.container_rdn1 in self.container_dn)
- self.assertTrue(self.container_dn in self.container_dn)
- self.assertFalse(self.base_rdn1 in self.container_dn)
-
- self.assertTrue(self.container_rdn1 in self.base_container_dn)
- self.assertTrue(self.container_dn in self.base_container_dn)
- self.assertTrue(self.container_dn + self.base_dn in
- self.base_container_dn)
- self.assertTrue(self.dn1 + self.container_dn + self.base_dn in
- self.base_container_dn)
- self.assertTrue(self.dn1 + self.container_dn + self.base_dn ==
- self.base_container_dn)
-
- self.assertFalse(self.container_rdn1 in self.base_dn)
-
- def test_indexing(self):
- self.assertEqual(self.dn1[0], self.rdn1)
- self.assertEqual(self.dn1[self.rdn1.attr], self.rdn1.value)
- with self.assertRaises(KeyError):
- self.dn1['foo']
-
- self.assertEqual(self.dn2[0], self.rdn2)
- self.assertEqual(self.dn2[self.rdn2.attr], self.rdn2.value)
- with self.assertRaises(KeyError):
- self.dn2['foo']
-
- self.assertEqual(self.dn3[0], self.rdn1)
- self.assertEqual(self.dn3[self.rdn1.attr], self.rdn1.value)
- self.assertEqual(self.dn3[1], self.rdn2)
- self.assertEqual(self.dn3[self.rdn2.attr], self.rdn2.value)
- with self.assertRaises(KeyError):
- self.dn3['foo']
-
- with self.assertRaises(TypeError):
- self.dn3[1.0]
-
- def test_assignments(self):
- dn_low = 0
- dn_high = 6
-
- rdn_args = make_rdn_args(dn_low, dn_high, 'tuple',
- default_rdn_attr_arg, default_rdn_value_arg)
- dn1 = DN(*rdn_args)
-
- rdn_args = make_rdn_args(dn_low, dn_high, 'list',
- default_rdn_attr_arg, default_rdn_value_arg)
- dn2 = DN(*rdn_args)
-
- rdn_args = make_rdn_args(dn_low, dn_high, 'RDN',
- default_rdn_attr_arg, default_rdn_value_arg)
- dn3 = DN(*rdn_args)
-
- self.assertEqual(dn1, dn2)
- self.assertEqual(dn1, dn3)
-
- for i in range(dn_low, dn_high):
- attr = default_rdn_attr_arg(i)
- value = default_rdn_value_arg(i)
- self.assertEqual(dn1[i].attr, attr)
- self.assertEqual(dn1[i].value, value)
- self.assertEqual(dn1[attr], value)
-
- for i in range(dn_low, dn_high):
- if i % 2:
- orig_attr = default_rdn_attr_arg(i)
- attr = alt_rdn_attr_arg(i)
- value = alt_rdn_value_arg(i)
- dn1[i] = attr, value
- dn2[orig_attr] = (attr, value)
- dn3[i] = RDN((attr, value))
-
- self.assertEqual(dn1, dn2)
- self.assertEqual(dn1, dn3)
-
- for i in range(dn_low, dn_high):
- if i % 2:
- attr = alt_rdn_attr_arg(i)
- value = alt_rdn_value_arg(i)
- else:
- attr = default_rdn_attr_arg(i)
- value = default_rdn_value_arg(i)
- self.assertEqual(dn1[i].value, dn1[i].value)
- self.assertEqual(dn1[attr], value)
-
- # Slices
- slice_low = 2
- slice_high = 4
- interval = range(slice_low, slice_high)
-
- # Slices
- # Assign via tuple
- rdn_args = make_rdn_args(dn_low, dn_high, 'tuple',
- default_rdn_attr_arg, default_rdn_value_arg)
- dn1 = DN(*rdn_args)
-
- dn_slice = make_rdn_args(slice_low, slice_high, 'tuple',
- alt_rdn_attr_arg, alt_rdn_value_arg)
-
- dn1[slice_low:slice_high] = dn_slice
-
- for i in range(dn_low, dn_high):
- if i in interval:
- attr = alt_rdn_attr_arg(i)
- value = alt_rdn_value_arg(i)
- else:
- attr = default_rdn_attr_arg(i)
- value = default_rdn_value_arg(i)
- self.assertEqual(dn1[i].value, dn1[i].value)
- self.assertEqual(dn1[attr], value)
-
- query_slice = dn1[slice_low:slice_high]
- for i, query_rdn in enumerate(query_slice):
- slice_rdn = RDN(dn_slice[i])
- self.assertEqual(slice_rdn, query_rdn)
-
- # insert
- dn = DN(self.rdn2)
- dn.insert(0, self.rdn1)
- self.assertEqual(dn, self.dn3)
-
- dn = DN(self.rdn1)
- dn.insert(1, (self.attr2, self.value2))
- self.assertEqual(dn, self.dn3)
-
- # Slices
- # Assign via RDN
- rdn_args = make_rdn_args(dn_low, dn_high, 'tuple',
- default_rdn_attr_arg, default_rdn_value_arg)
- dn1 = DN(*rdn_args)
-
- dn_slice = make_rdn_args(slice_low, slice_high, 'RDN',
- alt_rdn_attr_arg, alt_rdn_value_arg)
-
- dn1[slice_low:slice_high] = dn_slice
-
- for i in range(dn_low, dn_high):
- if i in interval:
- attr = alt_rdn_attr_arg(i)
- value = alt_rdn_value_arg(i)
- else:
- attr = default_rdn_attr_arg(i)
- value = default_rdn_value_arg(i)
- self.assertEqual(dn1[i].value, dn1[i].value)
- self.assertEqual(dn1[attr], value)
-
- query_slice = dn1[slice_low:slice_high]
- for i, query_rdn in enumerate(query_slice):
- slice_rdn = dn_slice[i]
- self.assertEqual(slice_rdn, query_rdn)
-
-
- def test_iter(self):
- self.assertEqual(len(self.dn1), 1)
- self.assertEqual(self.dn1[:], [self.rdn1])
- for i, ava in enumerate(self.dn1):
- if i == 0:
- self.assertEqual(ava, self.rdn1)
- else:
- self.fail("got iteration index %d, but len=%d" % (i, len(self.rdn1)))
-
- self.assertEqual(len(self.dn2), 1)
- self.assertEqual(self.dn2[:], [self.rdn2])
- for i, ava in enumerate(self.dn2):
- if i == 0:
- self.assertEqual(ava, self.rdn2)
- else:
- self.fail("got iteration index %d, but len=%d" % (i, len(self.rdn2)))
-
- self.assertEqual(len(self.dn3), 2)
- self.assertEqual(self.dn3[:], [self.rdn1, self.rdn2])
- for i, ava in enumerate(self.dn3):
- if i == 0:
- self.assertEqual(ava, self.rdn1)
- elif i == 1:
- self.assertEqual(ava, self.rdn2)
- else:
- self.fail("got iteration index %d, but len=%d" % (i, len(self.dn3)))
-
-
- def test_concat(self):
- dn1 = DN((self.attr1, self.value1))
- dn2 = DN([self.attr2, self.value2])
-
- # in-place addtion
- dn1 += dn2
- self.assertEqual(dn1, self.dn3)
-
- dn1 = DN((self.attr1, self.value1))
- dn1 += self.rdn2
- self.assertEqual(dn1, self.dn3)
-
- dn1 = DN((self.attr1, self.value1))
- dn1 += self.dn2
- self.assertEqual(dn1, self.dn3)
-
- dn1 = DN((self.attr1, self.value1))
- dn1 += self.str_dn2
- self.assertEqual(dn1, self.dn3)
-
- # concatenation
- dn1 = DN((self.attr1, self.value1))
- dn3 = dn1 + dn2
- self.assertEqual(dn3, self.dn3)
-
- dn1 = DN((self.attr1, self.value1))
- dn3 = dn1 + self.rdn2
- self.assertEqual(dn3, self.dn3)
-
- dn3 = dn1 + self.str_rdn2
- self.assertEqual(dn3, self.dn3)
-
- dn3 = dn1 + self.str_dn2
- self.assertEqual(dn3, self.dn3)
-
- dn3 = dn1 + self.dn2
- self.assertEqual(dn3, self.dn3)
-
-class TestEscapes(unittest.TestCase):
- def setUp(self):
- self.privilege = 'R,W privilege'
- self.dn_str_hex_escape = 'cn=R\\2cW privilege,cn=privileges,cn=pbac,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com'
- self.dn_str_backslash_escape = 'cn=R\\,W privilege,cn=privileges,cn=pbac,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com'
-
- def test_escape(self):
- dn = DN(self.dn_str_hex_escape)
- self.assertEqual(dn['cn'], self.privilege)
- self.assertEqual(dn[0].value, self.privilege)
-
- dn = DN(self.dn_str_backslash_escape)
- self.assertEqual(dn['cn'], self.privilege)
- self.assertEqual(dn[0].value, self.privilege)
-
-class TestInternationalization(unittest.TestCase):
- def setUp(self):
- # Hello in Arabic
- self.arabic_hello_utf8 = '\xd9\x85\xd9\x83\xd9\x8a\xd9\x84' + \
- '\xd8\xb9\x20\xd9\x85\xd8\xa7\xd9' + \
- '\x84\xd9\x91\xd8\xb3\xd9\x84\xd8\xa7'
-
- self.arabic_hello_unicode = self.arabic_hello_utf8.decode('utf-8')
-
- def test_i18n(self):
- self.assertEqual(self.arabic_hello_utf8,
- self.arabic_hello_unicode.encode('utf-8'))
-
- # AVA's
- # test attr i18n
- ava1 = AVA(self.arabic_hello_unicode, 'foo')
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
- self.assertEqual(ava1.attr, self.arabic_hello_unicode)
- self.assertEqual(str(ava1), self.arabic_hello_utf8+'=foo')
-
- ava1 = AVA(self.arabic_hello_utf8, 'foo')
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
- self.assertEqual(ava1.attr, self.arabic_hello_unicode)
- self.assertEqual(str(ava1), self.arabic_hello_utf8+'=foo')
-
- # test value i18n
- ava1 = AVA('cn', self.arabic_hello_unicode)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
- self.assertEqual(ava1.value, self.arabic_hello_unicode)
- self.assertEqual(str(ava1), 'cn='+self.arabic_hello_utf8)
-
- ava1 = AVA('cn', self.arabic_hello_utf8)
- self.assertIsInstance(ava1.attr, unicode)
- self.assertIsInstance(ava1.value, unicode)
- self.assertEqual(ava1.value, self.arabic_hello_unicode)
- self.assertEqual(str(ava1), 'cn='+self.arabic_hello_utf8)
-
- # RDN's
- # test attr i18n
- rdn1 = RDN((self.arabic_hello_unicode, 'foo'))
- self.assertIsInstance(rdn1.attr, unicode)
- self.assertIsInstance(rdn1.value, unicode)
- self.assertEqual(rdn1.attr, self.arabic_hello_unicode)
- self.assertEqual(str(rdn1), self.arabic_hello_utf8+'=foo')
-
- rdn1 = RDN((self.arabic_hello_utf8, 'foo'))
- self.assertIsInstance(rdn1.attr, unicode)
- self.assertIsInstance(rdn1.value, unicode)
- self.assertEqual(rdn1.attr, self.arabic_hello_unicode)
- self.assertEqual(str(rdn1), self.arabic_hello_utf8+'=foo')
-
- # test value i18n
- rdn1 = RDN(('cn', self.arabic_hello_unicode))
- self.assertIsInstance(rdn1.attr, unicode)
- self.assertIsInstance(rdn1.value, unicode)
- self.assertEqual(rdn1.value, self.arabic_hello_unicode)
- self.assertEqual(str(rdn1), 'cn='+self.arabic_hello_utf8)
-
- rdn1 = RDN(('cn', self.arabic_hello_utf8))
- self.assertIsInstance(rdn1.attr, unicode)
- self.assertIsInstance(rdn1.value, unicode)
- self.assertEqual(rdn1.value, self.arabic_hello_unicode)
- self.assertEqual(str(rdn1), 'cn='+self.arabic_hello_utf8)
-
- # DN's
- # test attr i18n
- dn1 = DN((self.arabic_hello_unicode, 'foo'))
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0].attr, self.arabic_hello_unicode)
- self.assertEqual(str(dn1), self.arabic_hello_utf8+'=foo')
-
- dn1 = DN((self.arabic_hello_utf8, 'foo'))
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0].attr, self.arabic_hello_unicode)
- self.assertEqual(str(dn1), self.arabic_hello_utf8+'=foo')
-
- # test value i18n
- dn1 = DN(('cn', self.arabic_hello_unicode))
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0].value, self.arabic_hello_unicode)
- self.assertEqual(str(dn1), 'cn='+self.arabic_hello_utf8)
-
- dn1 = DN(('cn', self.arabic_hello_utf8))
- self.assertIsInstance(dn1[0].attr, unicode)
- self.assertIsInstance(dn1[0].value, unicode)
- self.assertEqual(dn1[0].value, self.arabic_hello_unicode)
- self.assertEqual(str(dn1), 'cn='+self.arabic_hello_utf8)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/tests/test_ipalib/test_encoder.py b/tests/test_ipalib/test_encoder.py
deleted file mode 100644
index 430eda047..000000000
--- a/tests/test_ipalib/test_encoder.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# encoding: utf-8
-# Authors:
-# Pavel Zuna <pzuna@redhat.com>
-#
-# Copyright (C) 2009 Red Hat
-# see file 'COPYING' for use and warranty information
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-"""
-Test the `ipalib.encoder` module.
-"""
-
-import string
-
-from tests.util import ClassChecker, assert_equal
-from ipalib.encoder import Encoder, EncoderSettings, encode_args, decode_retval
-
-_encoder_settings = EncoderSettings()
-
-_test_str_d = u'ěščřžýáíé'
-_test_str_e = u'ěščřžýáíé'.encode(_encoder_settings.encode_to)
-
-
-class test_Encoder(ClassChecker):
- """
- Test the `ipalib.encoder.Encoder` class.
- """
- _cls = Encoder
-
- def test_encode(self):
- """
- Test the `ipalib.encoder.Encoder.encode` method.
- """
- o = self.cls()
- encode_to = o.encoder_settings.encode_to
- o.encoder_settings.encode_postprocessor = lambda x: x
- # strings
- assert_equal(o.encode('ahoj'), 'ahoj'.encode(encode_to))
- assert_equal(o.encode(_test_str_d), _test_str_e)
- # bool, float, int, long
- assert_equal(o.encode(True), 'TRUE'.encode(encode_to))
- assert_equal(o.encode(1.01), str(1.01).encode(encode_to))
- assert_equal(o.encode(1000), str(1000).encode(encode_to))
- assert_equal(o.encode(long(1)), str(long(1)).encode(encode_to))
- # lists
- expected = [_test_str_e, '1']
- assert_equal(o.encode([_test_str_d, 1]), expected)
- expected = ['1', ['1', '2', '3']]
- assert_equal(o.encode([1, [1, 2, 3]]), expected)
- # tuples
- expected = (_test_str_e, '1')
- assert_equal(o.encode((_test_str_d, 1)), expected)
- expected = ('1', ('1', '2', '3'))
- assert_equal(o.encode((1, (1, 2, 3))), expected)
- # dicts: only values, no postprocessing
- o.encoder_settings.encode_dict_keys = False
- o.encoder_settings.encode_dict_keys_postprocess = False
- o.encoder_settings.encode_dict_vals = True
- o.encoder_settings.encode_dict_vals_postprocess = False
- expected = {_test_str_d: _test_str_e}
- assert_equal(o.encode({_test_str_d: _test_str_d}), expected)
- # dicts: only keys, no postprocessing
- o.encoder_settings.encode_dict_keys = True
- o.encoder_settings.encode_dict_vals = False
- expected = {_test_str_e: _test_str_d}
- assert_equal(o.encode({_test_str_d: _test_str_d}), expected)
- # dicts: both keys and values, no postprocessing
- o.encoder_settings.encode_dict_vals = True
- expected = {_test_str_e: _test_str_e}
- assert_equal(o.encode({_test_str_d: _test_str_d}), expected)
- # dicts: both keys and values, postprocessing on keys only
- o.encoder_settings.encode_dict_keys = True
- o.encoder_settings.encode_dict_keys_postprocess = True
- o.encoder_settings.encode_postprocessor = string.upper
- expected = {_test_str_e.upper(): _test_str_e}
- assert_equal(o.encode({u'ěščřžýáíé': u'ěščřžýáíé'}), expected)
- # None
- o.encoder_settings.encode_postprocessor = lambda x: x
- o.encoder_settings.encode_none = False
- assert_equal(o.encode(None), None)
- o.encoder_settings.encode_none = True
- assert_equal(o.encode(None), str(None).encode(encode_to))
-
- def test_decode(self):
- """
- Test the `ipalib.encoder.Encoder.decode` method.
- """
- o = self.cls()
- decode_from = o.encoder_settings.decode_from
- o.encoder_settings.decode_postprocessor = lambda x: x
- # strings
- assert_equal(o.decode('ahoj'), 'ahoj'.decode(decode_from))
- assert_equal(o.decode(_test_str_e), _test_str_d)
- # bool, float, int, long
- assert_equal(o.decode('True'), str(True).decode(decode_from))
- assert_equal(o.decode('1.01'), str(1.01).decode(decode_from))
- assert_equal(o.decode('1000'), str(1000).decode(decode_from))
- assert_equal(o.decode('1'), str(long(1)).decode(decode_from))
- # lists
- expected = [_test_str_d, '1']
- assert_equal(o.decode([_test_str_e, '1']), expected)
- expected = [u'1', [u'1', u'2', u'3']]
- assert_equal(o.decode(['1', ['1', '2', '3']]), expected)
- # tuples
- expected = (_test_str_d, 1)
- assert_equal(o.decode((_test_str_e, 1)), expected)
- expected = (u'1', (u'1', u'2', u'3'))
- assert_equal(o.decode(('1', ('1', '2', '3'))), expected)
- # dicts: only values, no postprocessing
- o.encoder_settings.decode_dict_keys = False
- o.encoder_settings.decode_dict_keys_postprocess = False
- o.encoder_settings.decode_dict_vals = True
- o.encoder_settings.decode_dict_vals_postprocess = False
- expected = {_test_str_e: _test_str_d}
- assert_equal(o.decode({_test_str_e: _test_str_e}), expected)
- # dicts: only keys, no postprocessing
- o.encoder_settings.decode_dict_keys = True
- o.encoder_settings.decode_dict_vals = False
- expected = {_test_str_d: _test_str_e}
- assert_equal(o.decode({_test_str_e: _test_str_e}), expected)
- # dicts: both keys and values, no postprocessing
- o.encoder_settings.decode_dict_vals = True
- expected = {_test_str_d: _test_str_d}
- assert_equal(o.decode({_test_str_e: _test_str_e}), expected)
- # dicts: both keys and values, postprocessing on keys only
- o.encoder_settings.decode_dict_keys = True
- o.encoder_settings.decode_dict_keys_postprocess = True
- o.encoder_settings.decode_postprocessor = string.upper
- expected = {_test_str_d.upper(): _test_str_d}
- assert_equal(o.decode({_test_str_e: _test_str_e}), expected)
- # TODO: dict decoding using a table
- # None
- o.encoder_settings.decode_postprocessor = lambda x: x
- o.encoder_settings.decode_none = False
- assert_equal(o.decode(None), None)
- o.encoder_settings.decode_none = True
- assert_equal(o.decode(None), str(None).decode(decode_from))
-
diff --git a/tests/test_ipalib/test_x509.py b/tests/test_ipalib/test_x509.py
index a2e9b2265..cf076313e 100644
--- a/tests/test_ipalib/test_x509.py
+++ b/tests/test_ipalib/test_x509.py
@@ -32,7 +32,7 @@ from ipalib.constants import NAME_REGEX, NAME_ERROR
import base64
from ipalib import x509
from nss.error import NSPRError
-from ipalib.dn import *
+from ipapython.dn import DN
# certutil -
diff --git a/tests/test_ipapython/test_dn.py b/tests/test_ipapython/test_dn.py
new file mode 100644
index 000000000..441affa4f
--- /dev/null
+++ b/tests/test_ipapython/test_dn.py
@@ -0,0 +1,1937 @@
+#!/usr/bin/python
+
+import unittest
+from ipapython.dn import *
+
+def default_rdn_attr_arg(i):
+ return 'a%d' % i
+
+def default_rdn_value_arg(i):
+ return str(i)
+
+def alt_rdn_attr_arg(i):
+ return 'b%d' % i
+
+def alt_rdn_value_arg(i):
+ return str(i*10)
+
+def make_rdn_args(low, high, kind, attr=None, value=None):
+ result=[]
+ for i in range(low, high):
+ if attr is None:
+ new_attr = default_rdn_attr_arg(i)
+ elif callable(attr):
+ new_attr = attr(i)
+ else:
+ new_attr = attr
+
+ if value is None:
+ new_value = default_rdn_value_arg(i)
+ elif callable(value):
+ new_value = value(i)
+ else:
+ new_value = value
+
+ if kind == 'tuple':
+ result.append((new_attr, new_value))
+ elif kind == 'list':
+ result.append([new_attr, new_value])
+ elif kind == 'RDN':
+ result.append(RDN((new_attr, new_value)))
+ else:
+ raise ValueError("Unknown kind = %s" % kind)
+
+ return result
+
+def expected_class(klass, component):
+ if klass is AVA:
+ if component == 'self':
+ return AVA
+
+ elif klass is EditableAVA:
+ if component == 'self':
+ return EditableAVA
+
+ elif klass is RDN:
+ if component == 'self':
+ return RDN
+ elif component == 'AVA':
+ return AVA
+
+ elif klass is EditableRDN:
+ if component == 'self':
+ return EditableRDN
+ elif component == 'AVA':
+ return EditableAVA
+
+ elif klass is DN:
+ if component == 'self':
+ return DN
+ elif component == 'AVA':
+ return AVA
+ elif component == 'RDN':
+ return RDN
+
+ elif klass is EditableDN:
+ if component == 'self':
+ return EditableDN
+ elif component == 'AVA':
+ return EditableAVA
+ elif component == 'RDN':
+ return EditableRDN
+
+ raise ValueError("class %s with component '%s' unknown" % (klass.__name__, component))
+
+
+class TestAVA(unittest.TestCase):
+ def setUp(self):
+ self.attr1 = 'cn'
+ self.value1 = 'Bob'
+ self.str_ava1 = '%s=%s' % (self.attr1, self.value1)
+ self.ava1 = AVA(self.attr1, self.value1)
+
+ self.attr2 = 'ou'
+ self.value2 = 'People'
+ self.str_ava2 = '%s=%s' % (self.attr2, self.value2)
+ self.ava2 = AVA(self.attr2, self.value2)
+
+ self.attr3 = 'c'
+ self.value3 = 'US'
+ self.str_ava3 = '%s=%s' % (self.attr3, self.value3)
+ self.ava3 = AVA(self.attr3, self.value3)
+
+ def assertExpectedClass(self, klass, obj, component):
+ self.assertIs(obj.__class__, expected_class(klass, component))
+
+ def test_create(self):
+ for AVA_class in (AVA, EditableAVA):
+ # Create with attr,value pair
+ ava1 = AVA_class(self.attr1, self.value1)
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1, self.ava1)
+
+ # Create with "attr=value" string
+ ava1 = AVA_class(self.str_ava1)
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1, self.ava1)
+
+ # Create with tuple (attr, value)
+ ava1 = AVA_class((self.attr1, self.value1))
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1, self.ava1)
+
+ # Create with list [attr, value]
+ ava1 = AVA_class([self.attr1, self.value1])
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1, self.ava1)
+
+ # Create with no args should fail
+ with self.assertRaises(TypeError):
+ AVA_class()
+
+ # Create with more than 2 args should fail
+ with self.assertRaises(TypeError):
+ AVA_class(self.attr1, self.value1, self.attr1)
+
+ # Create with 1 arg which is not string should fail
+ with self.assertRaises(TypeError):
+ AVA_class(1)
+
+ # Create with malformed AVA_class string should fail
+ with self.assertRaises(ValueError):
+ AVA_class("cn")
+
+ # Create with non-string parameters, should convert
+ ava1 = AVA_class(1, self.value1)
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1.attr, u'1')
+
+ ava1 = AVA_class((1, self.value1))
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1.attr, u'1')
+
+ ava1 = AVA_class(self.attr1, 1)
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1.value, u'1')
+
+ ava1 = AVA_class((self.attr1, 1))
+ self.assertExpectedClass(AVA_class, ava1, 'self')
+ self.assertEqual(ava1.value, u'1')
+
+ def test_indexing(self):
+ for AVA_class in (AVA, EditableAVA):
+ ava1 = AVA_class(self.ava1)
+
+ self.assertEqual(ava1[self.attr1], self.value1)
+
+ with self.assertRaises(KeyError):
+ ava1['foo']
+
+ with self.assertRaises(TypeError):
+ ava1[0]
+
+ def test_properties(self):
+ for AVA_class in (AVA, EditableAVA):
+ ava1 = AVA_class(self.ava1)
+
+ self.assertEqual(ava1.attr, self.attr1)
+ self.assertIsInstance(ava1.attr, unicode)
+
+ self.assertEqual(ava1.value, self.value1)
+ self.assertIsInstance(ava1.value, unicode)
+
+ def test_str(self):
+ for AVA_class in (AVA, EditableAVA):
+ ava1 = AVA_class(self.ava1)
+
+ self.assertEqual(str(ava1), self.str_ava1)
+ self.assertIsInstance(str(ava1), str)
+
+ def test_cmp(self):
+ for AVA_class in (AVA, EditableAVA):
+ # Equality
+ ava1 = AVA_class(self.attr1, self.value1)
+
+ self.assertTrue(ava1 == self.ava1)
+ self.assertFalse(ava1 != self.ava1)
+
+ self.assertTrue(ava1 == self.str_ava1)
+ self.assertFalse(ava1 != self.str_ava1)
+
+ result = cmp(ava1, self.ava1)
+ self.assertEqual(result, 0)
+
+ # Upper case attr should still be equal
+ ava1 = AVA_class(self.attr1.upper(), self.value1)
+
+ self.assertFalse(ava1.attr == self.attr1)
+ self.assertTrue(ava1.value == self.value1)
+ self.assertTrue(ava1 == self.ava1)
+ self.assertFalse(ava1 != self.ava1)
+
+ result = cmp(ava1, self.ava1)
+ self.assertEqual(result, 0)
+
+ # Upper case value should still be equal
+ ava1 = AVA_class(self.attr1, self.value1.upper())
+
+ self.assertTrue(ava1.attr == self.attr1)
+ self.assertFalse(ava1.value == self.value1)
+ self.assertTrue(ava1 == self.ava1)
+ self.assertFalse(ava1 != self.ava1)
+
+ result = cmp(ava1, self.ava1)
+ self.assertEqual(result, 0)
+
+ # Make ava1's attr greater
+ if AVA_class.is_mutable:
+ ava1.attr = self.attr1 + "1"
+ else:
+ with self.assertRaises(AttributeError):
+ ava1.attr = self.attr1 + "1"
+ ava1 = AVA_class(self.attr1 + "1", self.value1.upper())
+
+ self.assertFalse(ava1 == self.ava1)
+ self.assertTrue(ava1 != self.ava1)
+
+ result = cmp(ava1, self.ava1)
+ self.assertEqual(result, 1)
+
+ result = cmp(self.ava1, ava1)
+ self.assertEqual(result, -1)
+
+ # Reset ava1's attr, should be equal again
+ if AVA_class.is_mutable:
+ ava1.attr = self.attr1
+ else:
+ with self.assertRaises(AttributeError):
+ ava1.attr = self.attr1
+ ava1 = AVA_class(self.attr1, self.value1.upper())
+
+ result = cmp(ava1, self.ava1)
+ self.assertEqual(result, 0)
+
+ # Make ava1's value greater
+ # attr will be equal, this tests secondary comparision component
+ if AVA_class.is_mutable:
+ ava1.value = self.value1 + "1"
+ else:
+ with self.assertRaises(AttributeError):
+ ava1.value = self.value1 + "1"
+ ava1 = AVA_class(self.attr1, self.value1 + "1")
+
+ result = cmp(ava1, self.ava1)
+ self.assertEqual(result, 1)
+
+ result = cmp(self.ava1, ava1)
+ self.assertEqual(result, -1)
+
+ def test_hashing(self):
+ # create AVA's that have the same value
+ immutable_ava1 = AVA((self.attr1, self.value1))
+ immutable_ava2 = AVA((self.attr1, self.value1))
+
+ mutable_ava1 = EditableAVA((self.attr1, self.value1))
+ mutable_ava2 = EditableAVA((self.attr1, self.value1))
+
+ # Immutable AVA's that are equal should hash to the same value.
+ # Mutable AVA's should not be hashable.
+
+ self.assertEqual(immutable_ava1, immutable_ava2)
+ self.assertEqual(immutable_ava1, mutable_ava1)
+ self.assertEqual(immutable_ava1, mutable_ava2)
+ self.assertEqual(mutable_ava1, immutable_ava2)
+
+ # Good, everyone's equal, now verify their hash values
+
+ self.assertEqual(hash(immutable_ava1), hash(immutable_ava2))
+ with self.assertRaises(TypeError):
+ hash(mutable_ava1)
+ with self.assertRaises(TypeError):
+ hash(mutable_ava2)
+
+ # Different immutable AVA objects with the same value should
+ # map to 1 common key and 1 member in a set. The key and
+ # member are based on the object's value.
+ #
+ # Mutable AVA objects should be unhashable.
+
+ for AVA_class in (AVA, EditableAVA):
+ ava1_a = AVA_class(self.ava1)
+ ava1_b = AVA_class(self.ava1)
+
+ ava2_a = AVA_class(self.ava2)
+ ava2_b = AVA_class(self.ava2)
+
+ ava3_a = AVA_class(self.ava3)
+ ava3_b = AVA_class(self.ava3)
+
+ self.assertEqual(ava1_a, ava1_b)
+ self.assertEqual(ava2_a, ava2_b)
+ self.assertEqual(ava3_a, ava3_b)
+
+ d = dict()
+ s = set()
+
+ if AVA_class.is_mutable:
+ with self.assertRaises(TypeError):
+ d[ava1_a] = str(ava1_a)
+ with self.assertRaises(TypeError):
+ d[ava1_b] = str(ava1_b)
+ with self.assertRaises(TypeError):
+ d[ava2_a] = str(ava2_a)
+ with self.assertRaises(TypeError):
+ d[ava2_b] = str(ava2_b)
+
+ with self.assertRaises(TypeError):
+ s.add(ava1_a)
+ with self.assertRaises(TypeError):
+ s.add(ava1_b)
+ with self.assertRaises(TypeError):
+ s.add(ava2_a)
+ with self.assertRaises(TypeError):
+ s.add(ava2_b)
+ else:
+ d[ava1_a] = str(ava1_a)
+ d[ava1_b] = str(ava1_b)
+ d[ava2_a] = str(ava2_a)
+ d[ava2_b] = str(ava2_b)
+
+ s.add(ava1_a)
+ s.add(ava1_b)
+ s.add(ava2_a)
+ s.add(ava2_b)
+
+ self.assertEqual(len(d), 2)
+ self.assertEqual(len(s), 2)
+ self.assertEqual(sorted(d.keys()), sorted([ava1_a, ava2_a]))
+ self.assertEqual(sorted(s), sorted([ava1_a, ava2_a]))
+
+ self.assertTrue(ava1_a in d)
+ self.assertTrue(ava1_b in d)
+ self.assertTrue(ava2_a in d)
+ self.assertTrue(ava2_b in d)
+ self.assertFalse(ava3_a in d)
+ self.assertFalse(ava3_b in d)
+
+ self.assertTrue(d.has_key(ava1_a))
+ self.assertTrue(d.has_key(ava1_b))
+ self.assertTrue(d.has_key(ava2_a))
+ self.assertTrue(d.has_key(ava2_b))
+ self.assertFalse(d.has_key(ava3_a))
+ self.assertFalse(d.has_key(ava3_b))
+
+ self.assertTrue(ava1_a in s)
+ self.assertTrue(ava1_b in s)
+ self.assertTrue(ava2_a in s)
+ self.assertTrue(ava2_b in s)
+ self.assertFalse(ava3_a in s)
+ self.assertFalse(ava3_b in s)
+
+ def test_coerce(self):
+ # Coerce an immutable to a mutable
+ immutable_ava1 = AVA(self.ava1)
+ mutable_ava1 = EditableAVA(immutable_ava1)
+ self.assertEqual(mutable_ava1, self.ava1)
+ self.assertEqual(mutable_ava1, immutable_ava1)
+
+ # Coerce a mutable to an immutable
+ mutable_ava1 = EditableAVA(self.ava1)
+ immutable_ava1 = AVA(mutable_ava1)
+ self.assertEqual(immutable_ava1, self.ava1)
+ self.assertEqual(immutable_ava1, mutable_ava1)
+
+class TestRDN(unittest.TestCase):
+ def setUp(self):
+ # ava1 must sort before ava2
+ self.attr1 = 'cn'
+ self.value1 = 'Bob'
+ self.str_ava1 = '%s=%s' % (self.attr1, self.value1)
+ self.ava1 = AVA(self.attr1, self.value1)
+
+ self.str_rdn1 = '%s=%s' % (self.attr1, self.value1)
+ self.rdn1 = RDN((self.attr1, self.value1))
+
+ self.attr2 = 'ou'
+ self.value2 = 'people'
+ self.str_ava2 = '%s=%s' % (self.attr2, self.value2)
+ self.ava2 = AVA(self.attr2, self.value2)
+
+ self.str_rdn2 = '%s=%s' % (self.attr2, self.value2)
+ self.rdn2 = RDN((self.attr2, self.value2))
+
+ self.str_ava3 = '%s=%s+%s=%s' % (self.attr1, self.value1, self.attr2, self.value2)
+
+ self.str_rdn3 = '%s=%s+%s=%s' % (self.attr1, self.value1, self.attr2, self.value2)
+ self.rdn3 = RDN(self.ava1, self.ava2)
+
+ def assertExpectedClass(self, klass, obj, component):
+ self.assertIs(obj.__class__, expected_class(klass, component))
+
+ def test_create(self):
+ for RDN_class in (RDN, EditableRDN):
+ # Create with single attr,value pair
+ rdn1 = RDN_class((self.attr1, self.value1))
+
+
+ self.assertEqual(len(rdn1), 1)
+ self.assertEqual(rdn1, self.rdn1)
+ self.assertExpectedClass(RDN_class, rdn1, 'self')
+ for i in range(0, len(rdn1)):
+ self.assertExpectedClass(RDN_class, rdn1[i], 'AVA')
+ self.assertEqual(rdn1[0], self.ava1)
+
+ # Create with multiple attr,value pairs
+ rdn3 = RDN_class((self.attr1, self.value1), (self.attr2, self.value2))
+ self.assertEqual(len(rdn3), 2)
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+ self.assertEqual(rdn3[0], self.ava1)
+ self.assertEqual(rdn3[1], self.ava2)
+
+ # Create with multiple attr,value pairs passed as lists
+ rdn3 = RDN_class([self.attr1, self.value1], [self.attr2, self.value2])
+ self.assertEqual(len(rdn3), 2)
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+ self.assertEqual(rdn3[0], self.ava1)
+ self.assertEqual(rdn3[1], self.ava2)
+
+ # Create with multiple attr,value pairs but reverse
+ # constructor parameter ordering. RDN canonical ordering
+ # should remain the same
+ rdn3 = RDN_class((self.attr2, self.value2), (self.attr1, self.value1))
+ self.assertEqual(len(rdn3), 2)
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+ self.assertEqual(rdn3[0], self.ava1)
+ self.assertEqual(rdn3[1], self.ava2)
+
+ # Create with single AVA object
+ rdn1 = RDN_class(self.ava1)
+ self.assertEqual(len(rdn1), 1)
+ self.assertEqual(rdn1, self.rdn1)
+ self.assertExpectedClass(RDN_class, rdn1, 'self')
+ for i in range(0, len(rdn1)):
+ self.assertExpectedClass(RDN_class, rdn1[i], 'AVA')
+ self.assertEqual(rdn1[0], self.ava1)
+
+ # Create with multiple AVA objects
+ rdn3 = RDN_class(self.ava1, self.ava2)
+ self.assertEqual(len(rdn3), 2)
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+ self.assertEqual(rdn3[0], self.ava1)
+ self.assertEqual(rdn3[1], self.ava2)
+
+
+ # Create with multiple AVA objects but reverse constructor
+ # parameter ordering. RDN canonical ordering should remain
+ # the same
+ rdn3 = RDN_class(self.ava2, self.ava1)
+ self.assertEqual(len(rdn3), 2)
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+ self.assertEqual(rdn3[0], self.ava1)
+ self.assertEqual(rdn3[1], self.ava2)
+
+ # Create with single string with 1 AVA
+ rdn1 = RDN_class(self.str_rdn1)
+ self.assertEqual(len(rdn1), 1)
+ self.assertEqual(rdn1, self.rdn1)
+ self.assertExpectedClass(RDN_class, rdn1, 'self')
+ for i in range(0, len(rdn1)):
+ self.assertExpectedClass(RDN_class, rdn1[i], 'AVA')
+ self.assertEqual(rdn1[0], self.ava1)
+
+ # Create with single string with 2 AVA's
+ rdn3 = RDN_class(self.str_rdn3)
+ self.assertEqual(len(rdn3), 2)
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+ self.assertEqual(rdn3[0], self.ava1)
+ self.assertEqual(rdn3[1], self.ava2)
+
+ def test_properties(self):
+ for RDN_class in (RDN, EditableRDN):
+ rdn1 = RDN_class(self.rdn1)
+ rdn2 = RDN_class(self.rdn2)
+ rdn3 = RDN_class(self.rdn3)
+
+ self.assertEqual(rdn1.attr, self.attr1)
+ self.assertIsInstance(rdn1.attr, unicode)
+
+ self.assertEqual(rdn1.value, self.value1)
+ self.assertIsInstance(rdn1.value, unicode)
+
+ self.assertEqual(rdn2.attr, self.attr2)
+ self.assertIsInstance(rdn2.attr, unicode)
+
+ self.assertEqual(rdn2.value, self.value2)
+ self.assertIsInstance(rdn2.value, unicode)
+
+ self.assertEqual(rdn3.attr, self.attr1)
+ self.assertIsInstance(rdn3.attr, unicode)
+
+ self.assertEqual(rdn3.value, self.value1)
+ self.assertIsInstance(rdn3.value, unicode)
+
+ def test_str(self):
+ for RDN_class in (RDN, EditableRDN):
+ rdn1 = RDN_class(self.rdn1)
+ rdn2 = RDN_class(self.rdn2)
+ rdn3 = RDN_class(self.rdn3)
+
+ self.assertEqual(str(rdn1), self.str_rdn1)
+ self.assertIsInstance(str(rdn1), str)
+
+ self.assertEqual(str(rdn2), self.str_rdn2)
+ self.assertIsInstance(str(rdn2), str)
+
+ self.assertEqual(str(rdn3), self.str_rdn3)
+ self.assertIsInstance(str(rdn3), str)
+
+ def test_cmp(self):
+ for RDN_class in (RDN, EditableRDN):
+ # Equality
+ rdn1 = RDN_class((self.attr1, self.value1))
+
+ self.assertTrue(rdn1 == self.rdn1)
+ self.assertFalse(rdn1 != self.rdn1)
+
+ self.assertTrue(rdn1 == self.str_rdn1)
+ self.assertFalse(rdn1 != self.str_rdn1)
+
+ result = cmp(rdn1, self.rdn1)
+ self.assertEqual(result, 0)
+
+ # Make rdn1's attr greater
+ if RDN_class.is_mutable:
+ rdn1.attr = self.attr1 + "1"
+ else:
+ rdn1 = RDN_class((self.attr1 + "1", self.value1))
+
+ self.assertFalse(rdn1 == self.rdn1)
+ self.assertTrue(rdn1 != self.rdn1)
+
+ result = cmp(rdn1, self.rdn1)
+ self.assertEqual(result, 1)
+
+ result = cmp(self.rdn1, rdn1)
+ self.assertEqual(result, -1)
+
+ # Reset rdn1's attr, should be equal again
+ if RDN_class.is_mutable:
+ rdn1.attr = self.attr1
+ else:
+ rdn1 = RDN_class((self.attr1, self.value1))
+
+ result = cmp(rdn1, self.rdn1)
+ self.assertEqual(result, 0)
+
+ # Make rdn1's value greater
+ # attr will be equal, this tests secondary comparision component
+ if RDN_class.is_mutable:
+ rdn1.value = self.value1 + "1"
+ else:
+ rdn1 = RDN_class((self.attr1, self.value1 + "1"))
+
+ result = cmp(rdn1, self.rdn1)
+ self.assertEqual(result, 1)
+
+ result = cmp(self.rdn1, rdn1)
+ self.assertEqual(result, -1)
+
+ # Make sure rdn's with more ava's are greater
+ result = cmp(self.rdn1, self.rdn3)
+ self.assertEqual(result, -1)
+ result = cmp(self.rdn3, self.rdn1)
+ self.assertEqual(result, 1)
+
+ def test_indexing(self):
+ for RDN_class in (RDN, EditableRDN):
+ rdn1 = RDN_class(self.rdn1)
+ rdn2 = RDN_class(self.rdn2)
+ rdn3 = RDN_class(self.rdn3)
+
+ self.assertEqual(rdn1[0], self.ava1)
+ self.assertEqual(rdn1[self.ava1.attr], self.ava1.value)
+ with self.assertRaises(KeyError):
+ rdn1['foo']
+
+ self.assertEqual(rdn2[0], self.ava2)
+ self.assertEqual(rdn2[self.ava2.attr], self.ava2.value)
+ with self.assertRaises(KeyError):
+ rdn2['foo']
+
+ self.assertEqual(rdn3[0], self.ava1)
+ self.assertEqual(rdn3[self.ava1.attr], self.ava1.value)
+ self.assertEqual(rdn3[1], self.ava2)
+ self.assertEqual(rdn3[self.ava2.attr], self.ava2.value)
+ with self.assertRaises(KeyError):
+ rdn3['foo']
+
+ self.assertEqual(rdn1.attr, self.attr1)
+ self.assertEqual(rdn1.value, self.value1)
+
+ with self.assertRaises(TypeError):
+ rdn3[1.0]
+
+ # Slices
+ self.assertEqual(rdn3[0:1], [self.ava1])
+ self.assertEqual(rdn3[:], [self.ava1, self.ava2])
+
+ def test_assignments(self):
+ for RDN_class in (RDN, EditableRDN):
+ rdn = RDN_class((self.attr1, self.value1))
+ if RDN_class.is_mutable:
+ rdn[0] = self.ava2
+ self.assertEqual(rdn, self.rdn2)
+ else:
+ with self.assertRaises(TypeError):
+ rdn[0] = self.ava2
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ rdn = RDN_class((self.attr1, self.value1))
+ if RDN_class.is_mutable:
+ rdn[0] = (self.attr2, self.value2)
+ self.assertEqual(rdn, self.rdn2)
+ else:
+ with self.assertRaises(TypeError):
+ rdn[0] = (self.attr2, self.value2)
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ rdn = RDN_class((self.attr1, self.value1))
+ if RDN_class.is_mutable:
+ rdn[self.attr1] = self.str_ava2
+ self.assertEqual(rdn[0], self.ava2)
+ else:
+ with self.assertRaises(TypeError):
+ rdn[self.attr1] = self.str_ava2
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ # Can't assign multiples to single entry
+ rdn = RDN_class((self.attr1, self.value1))
+ with self.assertRaises(TypeError):
+ rdn[self.attr1] = self.str_ava3
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ rdn = RDN_class((self.attr1, self.value1))
+ with self.assertRaises(TypeError):
+ rdn[self.attr1] = (self.attr1, self.value1, self.attr2, self.value2)
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ rdn = RDN_class((self.attr1, self.value1))
+ with self.assertRaises(TypeError):
+ rdn[self.attr1] = [(self.attr1, self.value1), (self.attr2, self.value2)]
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ # Slices
+ rdn = RDN_class((self.attr1, self.value1))
+ self.assertEqual(rdn, self.rdn1)
+ if RDN_class.is_mutable:
+ rdn[0:1] = [self.ava2]
+ self.assertEqual(rdn, self.rdn2)
+ else:
+ with self.assertRaises(TypeError):
+ rdn[0:1] = [self.ava2]
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ rdn = RDN_class((self.attr1, self.value1))
+ self.assertEqual(rdn, self.rdn1)
+ if RDN_class.is_mutable:
+ rdn[:] = [(self.attr2, self.value2)]
+ self.assertEqual(rdn, self.rdn2)
+ else:
+ with self.assertRaises(TypeError):
+ rdn[:] = [(self.attr2, self.value2)]
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ rdn = RDN_class((self.attr1, self.value1))
+ self.assertEqual(rdn, self.rdn1)
+ if RDN_class.is_mutable:
+ rdn[:] = [(self.attr1, self.value1),(self.attr2, self.value2)]
+ self.assertEqual(rdn, self.rdn3)
+ else:
+ with self.assertRaises(TypeError):
+ rdn[:] = [(self.attr1, self.value1),(self.attr2, self.value2)]
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+ rdn = RDN_class((self.attr1, self.value1))
+ self.assertEqual(rdn, self.rdn1)
+ if RDN_class.is_mutable:
+ rdn[0:1] = [(self.attr1, self.value1), (self.attr2, self.value2)]
+ self.assertEqual(rdn, self.rdn3)
+ else:
+ with self.assertRaises(TypeError):
+ rdn[0:1] = [(self.attr1, self.value1), (self.attr2, self.value2)]
+ self.assertExpectedClass(RDN_class, rdn, 'self')
+ for i in range(0, len(rdn)):
+ self.assertExpectedClass(RDN_class, rdn[i], 'AVA')
+
+
+ def test_iter(self):
+ for RDN_class in (RDN, EditableRDN):
+ rdn1 = RDN_class(self.rdn1)
+ rdn2 = RDN_class(self.rdn2)
+ rdn3 = RDN_class(self.rdn3)
+
+ self.assertEqual(len(rdn1), 1)
+ self.assertEqual(rdn1[:], [self.ava1])
+ for i, ava in enumerate(rdn1):
+ if i == 0:
+ self.assertEqual(ava, self.ava1)
+ else:
+ self.fail("got iteration index %d, but len=%d" % (i, len(rdn1)))
+
+ self.assertEqual(len(rdn2), 1)
+ self.assertEqual(rdn2[:], [self.ava2])
+ for i, ava in enumerate(rdn2):
+ if i == 0:
+ self.assertEqual(ava, self.ava2)
+ else:
+ self.fail("got iteration index %d, but len=%d" % (i, len(rdn2)))
+
+ self.assertEqual(len(rdn3), 2)
+ self.assertEqual(rdn3[:], [self.ava1, self.ava2])
+ for i, ava in enumerate(rdn3):
+ if i == 0:
+ self.assertEqual(ava, self.ava1)
+ elif i == 1:
+ self.assertEqual(ava, self.ava2)
+ else:
+ self.fail("got iteration index %d, but len=%d" % (i, len(rdn3)))
+
+
+ def test_concat(self):
+ for RDN_class in (RDN, EditableRDN):
+ rdn1 = RDN_class((self.attr1, self.value1))
+ rdn2 = RDN_class((self.attr2, self.value2))
+
+ # in-place addtion
+
+ # Note: If __iadd__ is not available Python will emulate += by
+ # replacing the lhs object with the result of __add__ (if available).
+ # Thus += works for both immutable and mutable RDN,DN object, the only
+ # difference is an immutable without __iadd__ will have a different object
+ # on the lhs after the operator evaluates.
+
+ rdn1 += rdn2
+ self.assertEqual(rdn1, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn1, 'self')
+ for i in range(0, len(rdn1)):
+ self.assertExpectedClass(RDN_class, rdn1[i], 'AVA')
+
+ rdn1 = RDN_class((self.attr1, self.value1))
+ rdn1 += self.ava2
+ self.assertEqual(rdn1, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn1, 'self')
+ for i in range(0, len(rdn1)):
+ self.assertExpectedClass(RDN_class, rdn1[i], 'AVA')
+
+ rdn1 = RDN_class((self.attr1, self.value1))
+ rdn1 += self.str_ava2
+ self.assertEqual(rdn1, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn1, 'self')
+ for i in range(0, len(rdn1)):
+ self.assertExpectedClass(RDN_class, rdn1[i], 'AVA')
+
+ # concatenation
+ rdn1 = RDN_class((self.attr1, self.value1))
+ rdn3 = rdn1 + rdn2
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+
+ rdn3 = rdn1 + self.ava2
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+
+ rdn3 = rdn1 + self.str_ava2
+ self.assertEqual(rdn3, self.rdn3)
+ self.assertExpectedClass(RDN_class, rdn3, 'self')
+ for i in range(0, len(rdn3)):
+ self.assertExpectedClass(RDN_class, rdn3[i], 'AVA')
+
+
+ def test_hashing(self):
+ # create RDN's that have the same value
+ immutable_rdn1 = RDN((self.attr1, self.value1))
+ immutable_rdn2 = RDN((self.attr1, self.value1))
+
+ mutable_rdn1 = EditableRDN((self.attr1, self.value1))
+ mutable_rdn2 = EditableRDN((self.attr1, self.value1))
+
+ # Immutable RDN's that are equal should hash to the same value.
+ # Mutable RDN's should not be hashable.
+
+ self.assertEqual(immutable_rdn1, immutable_rdn2)
+ self.assertEqual(immutable_rdn1, mutable_rdn1)
+ self.assertEqual(immutable_rdn1, mutable_rdn2)
+ self.assertEqual(mutable_rdn1, immutable_rdn2)
+
+ # Good, everyone's equal, now verify their hash values
+
+ self.assertEqual(hash(immutable_rdn1), hash(immutable_rdn2))
+ with self.assertRaises(TypeError):
+ hash(mutable_rdn1)
+ with self.assertRaises(TypeError):
+ hash(mutable_rdn2)
+
+ def test_coerce(self):
+ # Coerce an immutable to a mutable
+ immutable_rdn3 = RDN(self.rdn3)
+ mutable_rdn3 = EditableRDN(immutable_rdn3)
+ self.assertEqual(mutable_rdn3, self.rdn3)
+ self.assertEqual(mutable_rdn3, immutable_rdn3)
+
+ # Coerce a mutable to an immutable
+ mutable_rdn3 = EditableRDN(self.rdn3)
+ immutable_rdn3 = RDN(mutable_rdn3)
+ self.assertEqual(immutable_rdn3, self.rdn3)
+ self.assertEqual(immutable_rdn3, mutable_rdn3)
+
+class TestDN(unittest.TestCase):
+ def setUp(self):
+ # ava1 must sort before ava2
+ self.attr1 = 'cn'
+ self.value1 = 'Bob'
+ self.str_ava1 = '%s=%s' % (self.attr1, self.value1)
+ self.ava1 = AVA(self.attr1, self.value1)
+
+ self.str_rdn1 = '%s=%s' % (self.attr1, self.value1)
+ self.rdn1 = RDN((self.attr1, self.value1))
+
+ self.attr2 = 'ou'
+ self.value2 = 'people'
+ self.str_ava2 = '%s=%s' % (self.attr2, self.value2)
+ self.ava2 = AVA(self.attr2, self.value2)
+
+ self.str_rdn2 = '%s=%s' % (self.attr2, self.value2)
+ self.rdn2 = RDN((self.attr2, self.value2))
+
+ self.str_dn1 = self.str_rdn1
+ self.dn1 = DN(self.rdn1)
+
+ self.str_dn2 = self.str_rdn2
+ self.dn2 = DN(self.rdn2)
+
+ self.str_dn3 = '%s,%s' % (self.str_rdn1, self.str_rdn2)
+ self.dn3 = DN(self.rdn1, self.rdn2)
+
+ self.base_rdn1 = RDN(('dc', 'redhat'))
+ self.base_rdn2 = RDN(('dc', 'com'))
+ self.base_dn = DN(self.base_rdn1, self.base_rdn2)
+
+ self.container_rdn1 = RDN(('cn', 'sudorules'))
+ self.container_rdn2 = RDN(('cn', 'sudo'))
+ self.container_dn = DN(self.container_rdn1, self.container_rdn2)
+
+ self.base_container_dn = DN((self.attr1, self.value1),
+ self.container_dn, self.base_dn)
+
+
+ def assertExpectedClass(self, klass, obj, component):
+ self.assertIs(obj.__class__, expected_class(klass, component))
+
+ def test_create(self):
+ for DN_class in (DN, EditableDN):
+ # Create with single attr,value pair
+ dn1 = DN_class((self.attr1, self.value1))
+ self.assertEqual(len(dn1), 1)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[0].attr, unicode)
+ self.assertIsInstance(dn1[0].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+
+ # Create with single attr,value pair passed as a tuple
+ dn1 = DN_class((self.attr1, self.value1))
+ self.assertEqual(len(dn1), 1)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+
+ # Creation with multiple attr,value string pairs should fail
+ with self.assertRaises(ValueError):
+ dn1 = DN_class(self.attr1, self.value1, self.attr2, self.value2)
+
+ # Create with multiple attr,value pairs passed as tuples & lists
+ dn1 = DN_class((self.attr1, self.value1), [self.attr2, self.value2])
+ self.assertEqual(len(dn1), 2)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+ self.assertEqual(dn1[1], self.rdn2)
+
+ # Create with multiple attr,value pairs passed as tuple and RDN
+ dn1 = DN_class((self.attr1, self.value1), RDN((self.attr2, self.value2)))
+ self.assertEqual(len(dn1), 2)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+ self.assertEqual(dn1[1], self.rdn2)
+
+ # Create with multiple attr,value pairs but reverse
+ # constructor parameter ordering. RDN ordering should also be
+ # reversed because DN's are a ordered sequence of RDN's
+ dn1 = DN_class((self.attr2, self.value2), (self.attr1, self.value1))
+ self.assertEqual(len(dn1), 2)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn2)
+ self.assertEqual(dn1[1], self.rdn1)
+
+ # Create with single RDN object
+ dn1 = DN_class(self.rdn1)
+ self.assertEqual(len(dn1), 1)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+
+ # Create with multiple RDN objects, assure ordering is preserved.
+ dn1 = DN_class(self.rdn1, self.rdn2)
+ self.assertEqual(len(dn1), 2)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+ self.assertEqual(dn1[1], self.rdn2)
+
+ # Create with multiple RDN objects in different order, assure
+ # ordering is preserved.
+ dn1 = DN_class(self.rdn2, self.rdn1)
+ self.assertEqual(len(dn1), 2)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn2)
+ self.assertEqual(dn1[1], self.rdn1)
+
+ # Create with single string with 1 RDN
+ dn1 = DN_class(self.str_rdn1)
+ self.assertEqual(len(dn1), 1)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+
+ # Create with single string with 2 RDN's
+ dn1 = DN_class(self.str_dn3)
+ self.assertEqual(len(dn1), 2)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+ self.assertIsInstance(dn1[i].attr, unicode)
+ self.assertIsInstance(dn1[i].value, unicode)
+ self.assertEqual(dn1[0], self.rdn1)
+ self.assertEqual(dn1[1], self.rdn2)
+
+ # Create with RDN, and 2 DN's (e.g. attr + container + base)
+ dn1 = DN_class((self.attr1, self.value1), self.container_dn, self.base_dn)
+ self.assertEqual(len(dn1), 5)
+ dn_str = ','.join([str(self.rdn1),
+ str(self.container_rdn1), str(self.container_rdn2),
+ str(self.base_rdn1), str(self.base_rdn2)])
+ self.assertEqual(str(dn1), dn_str)
+
+ def test_str(self):
+ for DN_class in (DN, EditableDN):
+ dn1 = DN_class(self.dn1)
+ dn2 = DN_class(self.dn2)
+ dn3 = DN_class(self.dn3)
+
+ self.assertEqual(str(dn1), self.str_dn1)
+ self.assertIsInstance(str(dn1), str)
+
+ self.assertEqual(str(dn2), self.str_dn2)
+ self.assertIsInstance(str(dn2), str)
+
+ self.assertEqual(str(dn3), self.str_dn3)
+ self.assertIsInstance(str(dn3), str)
+
+ def test_cmp(self):
+ for DN_class in (DN, EditableDN):
+ # Equality
+ dn1 = DN_class((self.attr1, self.value1))
+
+ self.assertTrue(dn1 == self.dn1)
+ self.assertFalse(dn1 != self.dn1)
+
+ self.assertTrue(dn1 == self.str_dn1)
+ self.assertFalse(dn1 != self.str_dn1)
+
+ result = cmp(dn1, self.dn1)
+ self.assertEqual(result, 0)
+
+ # Make dn1's attr greater
+ if DN_class.is_mutable:
+ dn1[0].attr = self.attr1 + "1"
+ else:
+ with self.assertRaises(AttributeError):
+ dn1[0].attr = self.attr1 + "1"
+ dn1 = DN_class((self.attr1 + "1", self.value1))
+
+ self.assertFalse(dn1 == self.dn1)
+ self.assertTrue(dn1 != self.dn1)
+
+ result = cmp(dn1, self.dn1)
+ self.assertEqual(result, 1)
+
+ result = cmp(self.dn1, dn1)
+ self.assertEqual(result, -1)
+
+ # Reset dn1's attr, should be equal again
+ if DN_class.is_mutable:
+ dn1[0].attr = self.attr1
+ else:
+ with self.assertRaises(AttributeError):
+ dn1[0].attr = self.attr1
+ dn1 = DN_class((self.attr1, self.value1))
+
+ result = cmp(dn1, self.dn1)
+ self.assertEqual(result, 0)
+
+ # Make dn1's value greater
+ # attr will be equal, this tests secondary comparision component
+ if DN_class.is_mutable:
+ dn1[0].value = self.value1 + "1"
+ else:
+ with self.assertRaises(AttributeError):
+ dn1[0].value = self.value1 + "1"
+ dn1 = DN_class((self.attr1, self.value1 + "1"))
+
+ result = cmp(dn1, self.dn1)
+ self.assertEqual(result, 1)
+
+ result = cmp(self.dn1, dn1)
+ self.assertEqual(result, -1)
+
+ # Make sure dn's with more rdn's are greater
+ result = cmp(self.dn1, self.dn3)
+ self.assertEqual(result, -1)
+ result = cmp(self.dn3, self.dn1)
+ self.assertEqual(result, 1)
+
+
+ # Test startswith, endswith
+ container_dn = DN_class(self.container_dn)
+ base_container_dn = DN_class(self.base_container_dn)
+
+ self.assertTrue(base_container_dn.startswith(self.rdn1))
+ self.assertTrue(base_container_dn.startswith(self.dn1))
+ self.assertTrue(base_container_dn.startswith(self.dn1 + container_dn))
+ self.assertFalse(base_container_dn.startswith(self.dn2))
+ self.assertFalse(base_container_dn.startswith(self.rdn2))
+ self.assertTrue(base_container_dn.startswith((self.dn1)))
+ self.assertTrue(base_container_dn.startswith((self.rdn1)))
+ self.assertFalse(base_container_dn.startswith((self.rdn2)))
+ self.assertTrue(base_container_dn.startswith((self.rdn2, self.rdn1)))
+ self.assertTrue(base_container_dn.startswith((self.dn1, self.dn2)))
+
+ self.assertTrue(base_container_dn.endswith(self.base_dn))
+ self.assertTrue(base_container_dn.endswith(container_dn + self.base_dn))
+ self.assertFalse(base_container_dn.endswith(DN(self.base_rdn1)))
+ self.assertTrue(base_container_dn.endswith(DN(self.base_rdn2)))
+ self.assertTrue(base_container_dn.endswith((DN(self.base_rdn1), DN(self.base_rdn2))))
+
+ # Test "in" membership
+ self.assertTrue(self.container_rdn1 in container_dn)
+ self.assertTrue(container_dn in container_dn)
+ self.assertFalse(self.base_rdn1 in container_dn)
+
+ self.assertTrue(self.container_rdn1 in base_container_dn)
+ self.assertTrue(container_dn in base_container_dn)
+ self.assertTrue(container_dn + self.base_dn in
+ base_container_dn)
+ self.assertTrue(self.dn1 + container_dn + self.base_dn in
+ base_container_dn)
+ self.assertTrue(self.dn1 + container_dn + self.base_dn ==
+ base_container_dn)
+
+ self.assertFalse(self.container_rdn1 in self.base_dn)
+
+ def test_indexing(self):
+ for DN_class in (DN, EditableDN):
+ dn1 = DN_class(self.dn1)
+ dn2 = DN_class(self.dn2)
+ dn3 = DN_class(self.dn3)
+
+ self.assertEqual(dn1[0], self.rdn1)
+ self.assertEqual(dn1[self.rdn1.attr], self.rdn1.value)
+ with self.assertRaises(KeyError):
+ dn1['foo']
+
+ self.assertEqual(dn2[0], self.rdn2)
+ self.assertEqual(dn2[self.rdn2.attr], self.rdn2.value)
+ with self.assertRaises(KeyError):
+ dn2['foo']
+
+ self.assertEqual(dn3[0], self.rdn1)
+ self.assertEqual(dn3[self.rdn1.attr], self.rdn1.value)
+ self.assertEqual(dn3[1], self.rdn2)
+ self.assertEqual(dn3[self.rdn2.attr], self.rdn2.value)
+ with self.assertRaises(KeyError):
+ dn3['foo']
+
+ with self.assertRaises(TypeError):
+ dn3[1.0]
+
+ def test_assignments(self):
+ for DN_class in (DN, EditableDN):
+ dn_low = 0
+ dn_high = 6
+
+ rdn_args = make_rdn_args(dn_low, dn_high, 'tuple',
+ default_rdn_attr_arg, default_rdn_value_arg)
+ dn1 = DN_class(*rdn_args)
+
+ rdn_args = make_rdn_args(dn_low, dn_high, 'list',
+ default_rdn_attr_arg, default_rdn_value_arg)
+ dn2 = DN_class(*rdn_args)
+
+ rdn_args = make_rdn_args(dn_low, dn_high, 'RDN',
+ default_rdn_attr_arg, default_rdn_value_arg)
+ dn3 = DN_class(*rdn_args)
+
+ self.assertEqual(dn1, dn2)
+ self.assertEqual(dn1, dn3)
+
+ for i in range(dn_low, dn_high):
+ attr = default_rdn_attr_arg(i)
+ value = default_rdn_value_arg(i)
+
+ self.assertEqual(dn1[i].attr, attr)
+ self.assertEqual(dn1[i].value, value)
+ self.assertEqual(dn1[attr], value)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+
+ self.assertEqual(dn2[i].attr, attr)
+ self.assertEqual(dn2[i].value, value)
+ self.assertEqual(dn2[attr], value)
+ self.assertExpectedClass(DN_class, dn2, 'self')
+ self.assertExpectedClass(DN_class, dn2[i], 'RDN')
+ for j in range(0, len(dn2[i])):
+ self.assertExpectedClass(DN_class, dn2[i][j], 'AVA')
+
+ self.assertEqual(dn3[i].attr, attr)
+ self.assertEqual(dn3[i].value, value)
+ self.assertEqual(dn3[attr], value)
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ self.assertExpectedClass(DN_class, dn3[i], 'RDN')
+ for j in range(0, len(dn3[i])):
+ self.assertExpectedClass(DN_class, dn3[i][j], 'AVA')
+
+
+ for i in range(dn_low, dn_high):
+ if i % 2:
+ orig_attr = default_rdn_attr_arg(i)
+ attr = alt_rdn_attr_arg(i)
+ value = alt_rdn_value_arg(i)
+
+ if DN_class.is_mutable:
+ dn1[i] = attr, value
+ else:
+ with self.assertRaises(TypeError):
+ dn1[i] = attr, value
+
+ if DN_class.is_mutable:
+ dn2[orig_attr] = (attr, value)
+ else:
+ with self.assertRaises(TypeError):
+ dn2[orig_attr] = (attr, value)
+
+ if DN_class.is_mutable:
+ dn3[i] = RDN((attr, value))
+ else:
+ with self.assertRaises(TypeError):
+ dn3[i] = RDN((attr, value))
+
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+
+ self.assertExpectedClass(DN_class, dn2, 'self')
+ for i in range(0, len(dn2)):
+ self.assertExpectedClass(DN_class, dn2[i], 'RDN')
+ for j in range(0, len(dn2[i])):
+ self.assertExpectedClass(DN_class, dn2[i][j], 'AVA')
+
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ for i in range(0, len(dn3)):
+ self.assertExpectedClass(DN_class, dn3[i], 'RDN')
+ for j in range(0, len(dn3[i])):
+ self.assertExpectedClass(DN_class, dn3[i][j], 'AVA')
+
+
+ if DN_class.is_mutable:
+ self.assertEqual(dn1, dn2)
+ self.assertEqual(dn1, dn3)
+
+ for i in range(dn_low, dn_high):
+ if i % 2:
+ attr = alt_rdn_attr_arg(i)
+ value = alt_rdn_value_arg(i)
+ else:
+ attr = default_rdn_attr_arg(i)
+ value = default_rdn_value_arg(i)
+ self.assertEqual(dn1[i].attr, attr)
+ self.assertEqual(dn1[i].value, value)
+ self.assertEqual(dn1[attr], value)
+
+ # Slices
+ slice_low = 2
+ slice_high = 4
+ slice_interval = range(slice_low, slice_high)
+
+ # Slices
+ # Assign via tuple
+ rdn_args = make_rdn_args(dn_low, dn_high, 'tuple',
+ default_rdn_attr_arg, default_rdn_value_arg)
+ dn = DN_class(*rdn_args)
+
+ dn_slice = make_rdn_args(slice_low, slice_high, 'tuple',
+ alt_rdn_attr_arg, alt_rdn_value_arg)
+
+ if DN_class.is_mutable:
+ dn[slice_low:slice_high] = dn_slice
+ for i in range(dn_low, dn_high):
+ if i in slice_interval:
+ attr = alt_rdn_attr_arg(i)
+ value = alt_rdn_value_arg(i)
+ else:
+ attr = default_rdn_attr_arg(i)
+ value = default_rdn_value_arg(i)
+ self.assertEqual(dn[i].attr, attr)
+ self.assertEqual(dn[i].value, value)
+ self.assertEqual(dn[attr], value)
+
+ query_slice = dn[slice_low:slice_high]
+ for i, query_rdn in enumerate(query_slice):
+ slice_rdn = RDN(dn_slice[i])
+ self.assertEqual(slice_rdn, query_rdn)
+ else:
+ with self.assertRaises(TypeError):
+ dn[slice_low:slice_high] = dn_slice
+
+
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ # insert
+ dn = DN_class(self.rdn2)
+
+ if DN_class.is_mutable:
+ dn.insert(0, self.rdn1)
+ self.assertEqual(dn, self.dn3)
+ else:
+ with self.assertRaises(AttributeError):
+ dn.insert(0, self.rdn1)
+
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+ dn = DN_class(self.rdn1)
+
+ if DN_class.is_mutable:
+ dn.insert(1, (self.attr2, self.value2))
+ self.assertEqual(dn, self.dn3)
+ else:
+ with self.assertRaises(AttributeError):
+ dn.insert(1, (self.attr2, self.value2))
+
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ # Slices
+ # Assign via RDN
+ rdn_args = make_rdn_args(dn_low, dn_high, 'tuple',
+ default_rdn_attr_arg, default_rdn_value_arg)
+ dn = DN_class(*rdn_args)
+
+ dn_slice = make_rdn_args(slice_low, slice_high, 'RDN',
+ alt_rdn_attr_arg, alt_rdn_value_arg)
+
+ if DN_class.is_mutable:
+ dn[slice_low:slice_high] = dn_slice
+ for i in range(dn_low, dn_high):
+ if i in slice_interval:
+ attr = alt_rdn_attr_arg(i)
+ value = alt_rdn_value_arg(i)
+ else:
+ attr = default_rdn_attr_arg(i)
+ value = default_rdn_value_arg(i)
+ self.assertEqual(dn[i].value, value)
+ self.assertEqual(dn[attr], value)
+
+ query_slice = dn[slice_low:slice_high]
+ for i, query_rdn in enumerate(query_slice):
+ slice_rdn = dn_slice[i]
+ self.assertEqual(slice_rdn, query_rdn)
+ else:
+ with self.assertRaises(TypeError):
+ dn[slice_low:slice_high] = dn_slice
+
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ def test_iter(self):
+ for DN_class in (DN, EditableDN):
+ dn1 = DN_class(self.dn1)
+ dn2 = DN_class(self.dn2)
+ dn3 = DN_class(self.dn3)
+
+ self.assertEqual(len(dn1), 1)
+ self.assertEqual(dn1[:], [self.rdn1])
+ for i, ava in enumerate(dn1):
+ if i == 0:
+ self.assertEqual(ava, self.rdn1)
+ else:
+ self.fail("got iteration index %d, but len=%d" % (i, len(self.rdn1)))
+
+ self.assertEqual(len(dn2), 1)
+ self.assertEqual(dn2[:], [self.rdn2])
+ for i, ava in enumerate(dn2):
+ if i == 0:
+ self.assertEqual(ava, self.rdn2)
+ else:
+ self.fail("got iteration index %d, but len=%d" % (i, len(self.rdn2)))
+
+ self.assertEqual(len(dn3), 2)
+ self.assertEqual(dn3[:], [self.rdn1, self.rdn2])
+ for i, ava in enumerate(dn3):
+ if i == 0:
+ self.assertEqual(ava, self.rdn1)
+ elif i == 1:
+ self.assertEqual(ava, self.rdn2)
+ else:
+ self.fail("got iteration index %d, but len=%d" % (i, len(dn3)))
+
+
+ def test_concat(self):
+ for DN_class in (DN, EditableDN):
+ dn1 = DN_class((self.attr1, self.value1))
+ dn2 = DN_class([self.attr2, self.value2])
+
+ # in-place addtion
+
+ # Note: If __iadd__ is not available Python will emulate += by
+ # replacing the lhs object with the result of __add__ (if available).
+ # Thus += works for both immutable and mutable RDN,DN object, the only
+ # difference is an immutable without __iadd__ will have a different object
+ # on the lhs after the operator evaluates.
+
+ dn1 += dn2
+ self.assertEqual(dn1, self.dn3)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+
+
+ dn1 = DN_class((self.attr1, self.value1))
+ dn1 += self.rdn2
+ self.assertEqual(dn1, self.dn3)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+
+
+ dn1 = DN_class((self.attr1, self.value1))
+ dn1 += self.dn2
+ self.assertEqual(dn1, self.dn3)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+
+
+ dn1 = DN_class((self.attr1, self.value1))
+ dn1 += self.str_dn2
+ self.assertEqual(dn1, self.dn3)
+ self.assertExpectedClass(DN_class, dn1, 'self')
+ for i in range(0, len(dn1)):
+ self.assertExpectedClass(DN_class, dn1[i], 'RDN')
+ for j in range(0, len(dn1[i])):
+ self.assertExpectedClass(DN_class, dn1[i][j], 'AVA')
+
+
+ # concatenation
+ dn1 = DN_class((self.attr1, self.value1))
+ dn3 = dn1 + dn2
+ self.assertEqual(dn3, self.dn3)
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ for i in range(0, len(dn3)):
+ self.assertExpectedClass(DN_class, dn3[i], 'RDN')
+ for j in range(0, len(dn3[i])):
+ self.assertExpectedClass(DN_class, dn3[i][j], 'AVA')
+
+
+ dn1 = DN_class((self.attr1, self.value1))
+ dn3 = dn1 + self.rdn2
+ self.assertEqual(dn3, self.dn3)
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ for i in range(0, len(dn3)):
+ self.assertExpectedClass(DN_class, dn3[i], 'RDN')
+ for j in range(0, len(dn3[i])):
+ self.assertExpectedClass(DN_class, dn3[i][j], 'AVA')
+
+ dn3 = dn1 + self.str_rdn2
+ self.assertEqual(dn3, self.dn3)
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ for i in range(0, len(dn3)):
+ self.assertExpectedClass(DN_class, dn3[i], 'RDN')
+ self.assertExpectedClass(DN_class, dn3[i][0], 'AVA')
+
+ dn3 = dn1 + self.str_dn2
+ self.assertEqual(dn3, self.dn3)
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ for i in range(0, len(dn3)):
+ self.assertExpectedClass(DN_class, dn3[i], 'RDN')
+ for j in range(0, len(dn3[i])):
+ self.assertExpectedClass(DN_class, dn3[i][j], 'AVA')
+
+ dn3 = dn1 + self.dn2
+ self.assertEqual(dn3, self.dn3)
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ self.assertExpectedClass(DN_class, dn3, 'self')
+ for i in range(0, len(dn3)):
+ self.assertExpectedClass(DN_class, dn3[i], 'RDN')
+ for j in range(0, len(dn3[i])):
+ self.assertExpectedClass(DN_class, dn3[i][j], 'AVA')
+
+ def test_find(self):
+ for DN_class in (DN, EditableDN):
+ # -10 -9 -8 -7 -6 -5 -4 -3 -2 -1
+ dn = DN_class('t=0,t=1,cn=bob,t=3,t=4,t=5,cn=bob,t=7,t=8,t=9')
+ pat = DN_class('cn=bob')
+
+ # forward
+ self.assertEqual(dn.find(pat), 2)
+ self.assertEqual(dn.find(pat, 1), 2)
+ self.assertEqual(dn.find(pat, 1, 3), 2)
+ self.assertEqual(dn.find(pat, 2, 3), 2)
+ self.assertEqual(dn.find(pat, 6), 6)
+
+ self.assertEqual(dn.find(pat, 7), -1)
+ self.assertEqual(dn.find(pat, 1, 2), -1)
+
+ with self.assertRaises(ValueError):
+ self.assertEqual(dn.index(pat, 7), -1)
+ with self.assertRaises(ValueError):
+ self.assertEqual(dn.index(pat, 1, 2), -1)
+
+ # reverse
+ self.assertEqual(dn.rfind(pat), 6)
+ self.assertEqual(dn.rfind(pat, -4), 6)
+ self.assertEqual(dn.rfind(pat, 6), 6)
+ self.assertEqual(dn.rfind(pat, 6, 8), 6)
+ self.assertEqual(dn.rfind(pat, 6, 8), 6)
+ self.assertEqual(dn.rfind(pat, -8), 6)
+ self.assertEqual(dn.rfind(pat, -8, -4), 6)
+ self.assertEqual(dn.rfind(pat, -8, -5), 2)
+
+ self.assertEqual(dn.rfind(pat, 7), -1)
+ self.assertEqual(dn.rfind(pat, -3), -1)
+
+ with self.assertRaises(ValueError):
+ self.assertEqual(dn.rindex(pat, 7), -1)
+ with self.assertRaises(ValueError):
+ self.assertEqual(dn.rindex(pat, -3), -1)
+
+
+ def test_replace(self):
+ for DN_class in (DN, EditableDN):
+ dn = DN_class('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=8,t=9')
+ pat = DN('cn=bob')
+ replacement = DN('cn=bob')
+
+ if DN_class.is_mutable:
+ n_replaced = dn.replace(pat, replacement)
+ self.assertEqual(n_replaced, 0)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ pat = DN('t=2')
+ if DN_class.is_mutable:
+ expected_dn = DN('t=0,t=1,cn=bob,t=3,t=4,t=5,t=6,t=7,t=8,t=9')
+ n_replaced = dn.replace(pat, replacement)
+ self.assertEqual(n_replaced, 1)
+ self.assertEqual(dn, expected_dn)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ dn = DN_class('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=2,t=9')
+ if DN_class.is_mutable:
+ expected_dn = DN('t=0,t=1,cn=bob,t=3,t=4,t=5,t=6,t=7,t=2,t=9')
+ n_replaced = dn.replace(pat, replacement, 1)
+ self.assertEqual(n_replaced, 1)
+ self.assertEqual(dn, expected_dn)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement, 1)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ dn = DN_class('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=2,t=9')
+ if DN_class.is_mutable:
+ expected_dn = DN('t=0,t=1,cn=bob,t=3,t=4,t=5,t=6,t=7,t=2,t=9')
+ n_replaced = dn.replace(pat, replacement, 1)
+ self.assertEqual(n_replaced, 1)
+ self.assertEqual(dn, expected_dn)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement, 1)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ replacement = DN('cn=bob,ou=people')
+
+ dn = DN_class('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=2,t=9')
+ if DN_class.is_mutable:
+ expected_dn = DN('t=0,t=1,cn=bob,ou=people,t=3,t=4,t=5,t=6,t=7,t=2,t=9')
+ n_replaced = dn.replace(pat, replacement, 1)
+ self.assertEqual(n_replaced, 1)
+ self.assertEqual(dn, expected_dn)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement, 1)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ dn = DN_class('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=2,t=9')
+ if DN_class.is_mutable:
+ expected_dn = DN('t=0,t=1,cn=bob,ou=people,t=3,t=4,t=5,t=6,t=7,cn=bob,ou=people,t=9')
+ n_replaced = dn.replace(pat, replacement)
+ self.assertEqual(n_replaced, 2)
+ self.assertEqual(dn, expected_dn)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ pat = DN('t=3,t=4')
+ replacement = DN('cn=bob')
+ dn = DN_class('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=8,t=9')
+ if DN_class.is_mutable:
+ expected_dn = DN('t=0,t=1,t=2,cn=bob,t=5,t=6,t=7,t=8,t=9')
+ n_replaced = dn.replace(pat, replacement)
+ self.assertEqual(n_replaced, 1)
+ self.assertEqual(dn, expected_dn)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ pat = DN('t=3,t=4')
+ replacement = DN('cn=bob,ou=people')
+ dn = DN_class('t=0,t=1,t=2,t=3,t=4,t=5,t=6,t=7,t=8,t=9')
+ if DN_class.is_mutable:
+ expected_dn = DN('t=0,t=1,t=2,cn=bob,ou=people,t=5,t=6,t=7,t=8,t=9')
+ n_replaced = dn.replace(pat, replacement)
+ self.assertEqual(n_replaced, 1)
+ self.assertEqual(dn, expected_dn)
+ else:
+ with self.assertRaises(AttributeError):
+ n_replaced = dn.replace(pat, replacement)
+ self.assertExpectedClass(DN_class, dn, 'self')
+ for i in range(0, len(dn)):
+ self.assertExpectedClass(DN_class, dn[i], 'RDN')
+ for j in range(0, len(dn[i])):
+ self.assertExpectedClass(DN_class, dn[i][j], 'AVA')
+
+ def test_hashing(self):
+ # create DN's that have the same value
+ immutable_dn1 = DN((self.attr1, self.value1))
+ immutable_dn2 = DN((self.attr1, self.value1))
+
+ mutable_dn1 = EditableDN((self.attr1, self.value1))
+ mutable_dn2 = EditableDN((self.attr1, self.value1))
+
+ # Immutable DN's that are equal should hash to the same value.
+ # Mutable DN's should not be hashable.
+
+ self.assertEqual(immutable_dn1, immutable_dn2)
+ self.assertEqual(immutable_dn1, mutable_dn1)
+ self.assertEqual(immutable_dn1, mutable_dn2)
+ self.assertEqual(mutable_dn1, immutable_dn2)
+
+ # Good, everyone's equal, now verify their hash values
+
+ self.assertEqual(hash(immutable_dn1), hash(immutable_dn2))
+ with self.assertRaises(TypeError):
+ hash(mutable_dn1)
+ with self.assertRaises(TypeError):
+ hash(mutable_dn2)
+
+ # Different immutable DN objects with the same value should
+ # map to 1 common key and 1 member in a set. The key and
+ # member are based on the object's value.
+ #
+ # Mutable DN objects should be unhashable.
+
+ for DN_class in (DN, EditableDN):
+ dn1_a = DN_class(self.dn1)
+ dn1_b = DN_class(self.dn1)
+
+ dn2_a = DN_class(self.dn2)
+ dn2_b = DN_class(self.dn2)
+
+ dn3_a = DN_class(self.dn3)
+ dn3_b = DN_class(self.dn3)
+
+ self.assertEqual(dn1_a, dn1_b)
+ self.assertEqual(dn2_a, dn2_b)
+ self.assertEqual(dn3_a, dn3_b)
+
+ d = dict()
+ s = set()
+
+ if DN_class.is_mutable:
+ with self.assertRaises(TypeError):
+ d[dn1_a] = str(dn1_a)
+ with self.assertRaises(TypeError):
+ d[dn1_b] = str(dn1_b)
+ with self.assertRaises(TypeError):
+ d[dn2_a] = str(dn2_a)
+ with self.assertRaises(TypeError):
+ d[dn2_b] = str(dn2_b)
+
+ with self.assertRaises(TypeError):
+ s.add(dn1_a)
+ with self.assertRaises(TypeError):
+ s.add(dn1_b)
+ with self.assertRaises(TypeError):
+ s.add(dn2_a)
+ with self.assertRaises(TypeError):
+ s.add(dn2_b)
+ else:
+ d[dn1_a] = str(dn1_a)
+ d[dn1_b] = str(dn1_b)
+ d[dn2_a] = str(dn2_a)
+ d[dn2_b] = str(dn2_b)
+
+ s.add(dn1_a)
+ s.add(dn1_b)
+ s.add(dn2_a)
+ s.add(dn2_b)
+
+ self.assertEqual(len(d), 2)
+ self.assertEqual(len(s), 2)
+ self.assertEqual(sorted(d.keys()), sorted([dn1_a, dn2_a]))
+ self.assertEqual(sorted(s), sorted([dn1_a, dn2_a]))
+
+ self.assertTrue(dn1_a in d)
+ self.assertTrue(dn1_b in d)
+ self.assertTrue(dn2_a in d)
+ self.assertTrue(dn2_b in d)
+ self.assertFalse(dn3_a in d)
+ self.assertFalse(dn3_b in d)
+
+ self.assertTrue(d.has_key(dn1_a))
+ self.assertTrue(d.has_key(dn1_b))
+ self.assertTrue(d.has_key(dn2_a))
+ self.assertTrue(d.has_key(dn2_b))
+ self.assertFalse(d.has_key(dn3_a))
+ self.assertFalse(d.has_key(dn3_b))
+
+ self.assertTrue(dn1_a in s)
+ self.assertTrue(dn1_b in s)
+ self.assertTrue(dn2_a in s)
+ self.assertTrue(dn2_b in s)
+ self.assertFalse(dn3_a in s)
+ self.assertFalse(dn3_b in s)
+
+ def test_coerce(self):
+ # Coerce an immutable to a mutable
+ immutable_dn3 = DN(self.dn3)
+ mutable_dn3 = EditableDN(immutable_dn3)
+ self.assertEqual(mutable_dn3, self.dn3)
+ self.assertEqual(mutable_dn3, immutable_dn3)
+
+ # Coerce a mutable to an immutable
+ mutable_dn3 = EditableDN(self.dn3)
+ immutable_dn3 = DN(mutable_dn3)
+ self.assertEqual(immutable_dn3, self.dn3)
+ self.assertEqual(immutable_dn3, mutable_dn3)
+
+class TestEscapes(unittest.TestCase):
+ def setUp(self):
+ self.privilege = 'R,W privilege'
+ self.dn_str_hex_escape = 'cn=R\\2cW privilege,cn=privileges,cn=pbac,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com'
+ self.dn_str_backslash_escape = 'cn=R\\,W privilege,cn=privileges,cn=pbac,dc=idm,dc=lab,dc=bos,dc=redhat,dc=com'
+
+ def test_escape(self):
+ for DN_class in (DN, EditableDN):
+ dn = DN_class(self.dn_str_hex_escape)
+ self.assertEqual(dn['cn'], self.privilege)
+ self.assertEqual(dn[0].value, self.privilege)
+
+ dn = DN_class(self.dn_str_backslash_escape)
+ self.assertEqual(dn['cn'], self.privilege)
+ self.assertEqual(dn[0].value, self.privilege)
+
+class TestInternationalization(unittest.TestCase):
+ def setUp(self):
+ # Hello in Arabic
+ self.arabic_hello_utf8 = '\xd9\x85\xd9\x83\xd9\x8a\xd9\x84' + \
+ '\xd8\xb9\x20\xd9\x85\xd8\xa7\xd9' + \
+ '\x84\xd9\x91\xd8\xb3\xd9\x84\xd8\xa7'
+
+ self.arabic_hello_unicode = self.arabic_hello_utf8.decode('utf-8')
+
+ def test_i18n(self):
+ self.assertEqual(self.arabic_hello_utf8,
+ self.arabic_hello_unicode.encode('utf-8'))
+
+ # AVA's
+ # test attr i18n
+ for AVA_class in (AVA, EditableAVA):
+ ava1 = AVA_class(self.arabic_hello_unicode, 'foo')
+ self.assertIsInstance(ava1.attr, unicode)
+ self.assertIsInstance(ava1.value, unicode)
+ self.assertEqual(ava1.attr, self.arabic_hello_unicode)
+ self.assertEqual(str(ava1), self.arabic_hello_utf8+'=foo')
+
+ ava1 = AVA_class(self.arabic_hello_utf8, 'foo')
+ self.assertIsInstance(ava1.attr, unicode)
+ self.assertIsInstance(ava1.value, unicode)
+ self.assertEqual(ava1.attr, self.arabic_hello_unicode)
+ self.assertEqual(str(ava1), self.arabic_hello_utf8+'=foo')
+
+ # test value i18n
+ ava1 = AVA_class('cn', self.arabic_hello_unicode)
+ self.assertIsInstance(ava1.attr, unicode)
+ self.assertIsInstance(ava1.value, unicode)
+ self.assertEqual(ava1.value, self.arabic_hello_unicode)
+ self.assertEqual(str(ava1), 'cn='+self.arabic_hello_utf8)
+
+ ava1 = AVA_class('cn', self.arabic_hello_utf8)
+ self.assertIsInstance(ava1.attr, unicode)
+ self.assertIsInstance(ava1.value, unicode)
+ self.assertEqual(ava1.value, self.arabic_hello_unicode)
+ self.assertEqual(str(ava1), 'cn='+self.arabic_hello_utf8)
+
+ # RDN's
+ # test attr i18n
+ for RDN_class in (RDN, EditableRDN):
+ rdn1 = RDN_class((self.arabic_hello_unicode, 'foo'))
+ self.assertIsInstance(rdn1.attr, unicode)
+ self.assertIsInstance(rdn1.value, unicode)
+ self.assertEqual(rdn1.attr, self.arabic_hello_unicode)
+ self.assertEqual(str(rdn1), self.arabic_hello_utf8+'=foo')
+
+ rdn1 = RDN_class((self.arabic_hello_utf8, 'foo'))
+ self.assertIsInstance(rdn1.attr, unicode)
+ self.assertIsInstance(rdn1.value, unicode)
+ self.assertEqual(rdn1.attr, self.arabic_hello_unicode)
+ self.assertEqual(str(rdn1), self.arabic_hello_utf8+'=foo')
+
+ # test value i18n
+ rdn1 = RDN_class(('cn', self.arabic_hello_unicode))
+ self.assertIsInstance(rdn1.attr, unicode)
+ self.assertIsInstance(rdn1.value, unicode)
+ self.assertEqual(rdn1.value, self.arabic_hello_unicode)
+ self.assertEqual(str(rdn1), 'cn='+self.arabic_hello_utf8)
+
+ rdn1 = RDN_class(('cn', self.arabic_hello_utf8))
+ self.assertIsInstance(rdn1.attr, unicode)
+ self.assertIsInstance(rdn1.value, unicode)
+ self.assertEqual(rdn1.value, self.arabic_hello_unicode)
+ self.assertEqual(str(rdn1), 'cn='+self.arabic_hello_utf8)
+
+ # DN's
+ # test attr i18n
+ for DN_class in (DN, EditableDN):
+ dn1 = DN_class((self.arabic_hello_unicode, 'foo'))
+ self.assertIsInstance(dn1[0].attr, unicode)
+ self.assertIsInstance(dn1[0].value, unicode)
+ self.assertEqual(dn1[0].attr, self.arabic_hello_unicode)
+ self.assertEqual(str(dn1), self.arabic_hello_utf8+'=foo')
+
+ dn1 = DN_class((self.arabic_hello_utf8, 'foo'))
+ self.assertIsInstance(dn1[0].attr, unicode)
+ self.assertIsInstance(dn1[0].value, unicode)
+ self.assertEqual(dn1[0].attr, self.arabic_hello_unicode)
+ self.assertEqual(str(dn1), self.arabic_hello_utf8+'=foo')
+
+ # test value i18n
+ dn1 = DN_class(('cn', self.arabic_hello_unicode))
+ self.assertIsInstance(dn1[0].attr, unicode)
+ self.assertIsInstance(dn1[0].value, unicode)
+ self.assertEqual(dn1[0].value, self.arabic_hello_unicode)
+ self.assertEqual(str(dn1), 'cn='+self.arabic_hello_utf8)
+
+ dn1 = DN_class(('cn', self.arabic_hello_utf8))
+ self.assertIsInstance(dn1[0].attr, unicode)
+ self.assertIsInstance(dn1[0].value, unicode)
+ self.assertEqual(dn1[0].value, self.arabic_hello_unicode)
+ self.assertEqual(str(dn1), 'cn='+self.arabic_hello_utf8)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/test_ipaserver/test_changepw.py b/tests/test_ipaserver/test_changepw.py
index 035766855..4491e0b6e 100644
--- a/tests/test_ipaserver/test_changepw.py
+++ b/tests/test_ipaserver/test_changepw.py
@@ -23,7 +23,7 @@ from httptest import Unauthorized_HTTP_test
from tests.test_xmlrpc.xmlrpc_test import XMLRPC_test
from tests.util import assert_equal, assert_not_equal
from ipalib import api, errors
-from ipalib.dn import DN
+from ipapython.dn import DN
import ldap
testuser = u'tuser'
@@ -57,9 +57,7 @@ class test_changepw(XMLRPC_test, Unauthorized_HTTP_test):
)
def _checkpw(self, user, password):
- dn = str(DN(('uid', user),
- api.env.container_user,
- api.env.basedn))
+ dn = str(DN(('uid', user), api.env.container_user, api.env.basedn))
conn = ldap.initialize(api.env.ldap_uri)
try:
conn.simple_bind_s(dn, password)
diff --git a/tests/test_ipaserver/test_ldap.py b/tests/test_ipaserver/test_ldap.py
index 1bbd94fb5..cd3ba3cd5 100644
--- a/tests/test_ipaserver/test_ldap.py
+++ b/tests/test_ipaserver/test_ldap.py
@@ -33,7 +33,7 @@ from ipalib.plugins.host import host
import nss.nss as nss
from ipalib import api, x509, create_api, errors
from ipapython import ipautil
-from ipalib.dn import *
+from ipapython.dn import DN
class test_ldap(object):
"""
@@ -45,8 +45,8 @@ class test_ldap(object):
self.ldapuri = 'ldap://%s' % ipautil.format_netloc(api.env.host)
self.ccache = '/tmp/krb5cc_%d' % os.getuid()
nss.nss_init_nodb()
- self.dn = str(DN(('krbprincipalname','ldap/%s@%s' % (api.env.host, api.env.realm)),
- ('cn','services'),('cn','accounts'),api.env.basedn))
+ self.dn = DN(('krbprincipalname','ldap/%s@%s' % (api.env.host, api.env.realm)),
+ ('cn','services'),('cn','accounts'),api.env.basedn)
def tearDown(self):
if self.conn and self.conn.isconnected():
@@ -90,7 +90,7 @@ class test_ldap(object):
else:
raise nose.SkipTest("No directory manager password in %s" % pwfile)
self.conn = ldap2(shared_instance=False, ldap_uri=self.ldapuri)
- self.conn.connect(bind_dn='cn=directory manager', bind_pw=dm_password)
+ self.conn.connect(bind_dn=DN(('cn', 'directory manager')), bind_pw=dm_password)
(dn, entry_attrs) = self.conn.get_entry(self.dn, ['usercertificate'])
cert = entry_attrs.get('usercertificate')
cert = cert[0]
@@ -120,7 +120,7 @@ class test_ldap(object):
fp.close()
else:
raise nose.SkipTest("No directory manager password in %s" % pwfile)
- myapi.Backend.ldap2.connect(bind_dn="cn=Directory Manager", bind_pw=dm_password)
+ myapi.Backend.ldap2.connect(bind_dn=DN(('cn', 'Directory Manager')), bind_pw=dm_password)
result = myapi.Command['service_show']('ldap/%s@%s' % (api.env.host, api.env.realm,))
entry_attrs = result['result']
@@ -145,4 +145,3 @@ class test_ldap(object):
cert = cert[0]
serial = unicode(x509.get_serial_number(cert, x509.DER))
assert serial is not None
-
diff --git a/tests/test_xmlrpc/test_attr.py b/tests/test_xmlrpc/test_attr.py
index f5003c403..799c77939 100644
--- a/tests/test_xmlrpc/test_attr.py
+++ b/tests/test_xmlrpc/test_attr.py
@@ -21,29 +21,17 @@
Test --setattr and --addattr and other attribute-specific issues
"""
-from ipalib import api, errors, x509
+from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
-from xmlrpc_test import (Declarative, fuzzy_digits, fuzzy_uuid, fuzzy_date,
- fuzzy_hex, fuzzy_hash, fuzzy_issuer)
-from ipalib.dn import *
-import base64
-
-user1 = u'tuser1'
-fqdn1 = u'testhost1.%s' % api.env.domain
-
-# We can use the same cert we generated for the service tests
-fd = open('tests/test_xmlrpc/service.crt', 'r')
-servercert = fd.readlines()
-servercert = u''.join(servercert)
-servercert = x509.strip_header(servercert)
-servercert = servercert.replace('\n', '')
-fd.close()
+from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
+from ipapython.dn import DN
+
+user1=u'tuser1'
class test_attr(Declarative):
cleanup_commands = [
('user_del', [user1], {}),
- ('host_del', [fqdn1], {}),
]
tests = [
@@ -72,16 +60,13 @@ class test_attr(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
has_keytab=False,
has_password=False,
),
@@ -563,71 +548,4 @@ class test_attr(Declarative):
desc='Server is unwilling to perform', info=''),
),
- dict(
- desc='Try to create %r with description and --addattr description' % fqdn1,
- command=('host_add', [fqdn1],
- dict(
- description=u'Test host 1',
- addattr=u'description=Test host 2',
- force=True,
- ),
- ),
- expected=errors.OnlyOneValueAllowed(attr='description'),
- ),
-
- dict(
- desc='Create %r with a certificate' % fqdn1,
- command=('host_add', [fqdn1],
- dict(
- usercertificate=servercert,
- force=True,
- ),
- ),
- expected=dict(
- value=fqdn1,
- summary=u'Added host "%s"' % fqdn1,
- result=dict(
- dn=lambda x: DN(x) == DN(('fqdn',fqdn1),('cn','computers'),
- ('cn','accounts'),api.env.basedn),
- fqdn=[fqdn1],
- krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
- objectclass=objectclasses.host,
- ipauniqueid=[fuzzy_uuid],
- managedby_host=[fqdn1],
- usercertificate=[base64.b64decode(servercert)],
- valid_not_before=fuzzy_date,
- valid_not_after=fuzzy_date,
- subject=lambda x: DN(x) == \
- DN(('CN',api.env.host),x509.subject_base()),
- serial_number=fuzzy_digits,
- serial_number_hex=fuzzy_hex,
- md5_fingerprint=fuzzy_hash,
- sha1_fingerprint=fuzzy_hash,
- issuer=fuzzy_issuer,
- has_keytab=False,
- has_password=False,
- ),
- ),
- ),
-
- dict(
- desc='Remove %r certificate using --delattr' % fqdn1,
- command=('host_mod', [fqdn1],
- dict(
- delattr=u'usercertificate=%s' % servercert,
- ),
- ),
- expected=dict(
- value=fqdn1,
- summary=u'Modified host "%s"' % fqdn1,
- result=dict(
- fqdn=[fqdn1],
- krbprincipalname=[u'host/%s@%s' % (fqdn1, api.env.realm)],
- managedby_host=[fqdn1],
- has_keytab=False,
- has_password=False,
- ),
- ),
- ),
-
]
diff --git a/tests/test_xmlrpc/test_automember_plugin.py b/tests/test_xmlrpc/test_automember_plugin.py
index ceae8c3ff..36a510939 100644
--- a/tests/test_xmlrpc/test_automember_plugin.py
+++ b/tests/test_xmlrpc/test_automember_plugin.py
@@ -22,6 +22,7 @@ Test the `ipalib/plugins/automember.py` module.
"""
from ipalib import api, errors
+from ipapython.dn import DN
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
@@ -132,7 +133,7 @@ class test_automember(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn),
+ dn=DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn),
),
),
),
@@ -151,8 +152,8 @@ class test_automember(Declarative):
description=[u'Test desc'],
objectclass=objectclasses.hostgroup,
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup1, api.env.basedn)],
- dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn),
+ mepmanagedentry=[DN(('cn', hostgroup1), ('cn', 'ng'), ('cn', 'alt'), api.env.basedn)],
+ dn=DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
),
),
),
@@ -171,8 +172,8 @@ class test_automember(Declarative):
description=[u'Test desc'],
objectclass=objectclasses.hostgroup,
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup2, api.env.basedn)],
- dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn),
+ mepmanagedentry=[DN(('cn', hostgroup2), ('cn', 'ng'), ('cn', 'alt'), api.env.basedn)],
+ dn=DN(('cn', hostgroup2), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
),
),
),
@@ -191,8 +192,8 @@ class test_automember(Declarative):
description=[u'Test desc'],
objectclass=objectclasses.hostgroup,
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup3, api.env.basedn)],
- dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn),
+ mepmanagedentry=[DN(('cn', hostgroup3), ('cn', 'ng'), ('cn', 'alt'), api.env.basedn)],
+ dn=DN(('cn', hostgroup3), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
),
),
),
@@ -211,8 +212,8 @@ class test_automember(Declarative):
description=[u'Test desc'],
objectclass=objectclasses.hostgroup,
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (hostgroup4, api.env.basedn)],
- dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn),
+ mepmanagedentry=[DN(('cn', hostgroup4), ('cn', 'ng'), ('cn', 'alt'), api.env.basedn)],
+ dn=DN(('cn', hostgroup4), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
),
),
),
@@ -232,7 +233,7 @@ class test_automember(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=u'cn=%s,cn=groups,cn=accounts,%s' % (defaultgroup1, api.env.basedn),
+ dn=DN(('cn', defaultgroup1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn),
),
),
),
@@ -251,8 +252,8 @@ class test_automember(Declarative):
description=[u'Default test desc'],
objectclass=objectclasses.hostgroup,
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=['cn=%s,cn=ng,cn=alt,%s' % (defaulthostgroup1, api.env.basedn)],
- dn=u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn),
+ mepmanagedentry=[DN(('cn', defaulthostgroup1), ('cn', 'ng'), ('cn', 'alt'), api.env.basedn)],
+ dn=DN(('cn', defaulthostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
),
),
),
@@ -269,9 +270,9 @@ class test_automember(Declarative):
result=dict(
cn=[group1],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)],
objectclass=objectclasses.automember,
- dn=u'cn=%s,cn=group,cn=automember,cn=etc,%s' % (group1, api.env.basedn),
+ dn=DN(('cn', group1), ('cn', 'group'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
),
),
@@ -299,7 +300,7 @@ class test_automember(Declarative):
cn=[group1],
description=[u'Test desc'],
automemberinclusiveregex=[u'manager=%s' % group_include_regex],
- automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)],
),
),
),
@@ -318,9 +319,9 @@ class test_automember(Declarative):
result=dict(
cn=[hostgroup1],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
objectclass=objectclasses.automember,
- dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup1, api.env.basedn),
+ dn=DN(('cn', hostgroup1), ('cn', 'hostgroup'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
),
),
@@ -348,7 +349,7 @@ class test_automember(Declarative):
cn=[hostgroup1],
description=[u'Test desc'],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
),
),
),
@@ -401,7 +402,7 @@ class test_automember(Declarative):
result=dict(
cn=[hostgroup1],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
u'fqdn=%s' % hostgroup_include_regex3,
u'fqdn=%s' % hostgroup_include_regex2,
@@ -428,9 +429,9 @@ class test_automember(Declarative):
result=dict(
cn=[hostgroup2],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup2), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
objectclass=objectclasses.automember,
- dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup2, api.env.basedn),
+ dn=DN(('cn', hostgroup2), ('cn', 'hostgroup'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
),
),
@@ -458,7 +459,7 @@ class test_automember(Declarative):
cn=[hostgroup2],
description=[u'Test desc'],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup2), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
),
),
),
@@ -477,9 +478,9 @@ class test_automember(Declarative):
result=dict(
cn=[hostgroup3],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup3), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
objectclass=objectclasses.automember,
- dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup3, api.env.basedn),
+ dn=DN(('cn', hostgroup3), ('cn', 'hostgroup'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
),
),
@@ -507,7 +508,7 @@ class test_automember(Declarative):
cn=[hostgroup3],
description=[u'Test desc'],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex2],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup3), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
),
),
),
@@ -526,9 +527,9 @@ class test_automember(Declarative):
result=dict(
cn=[hostgroup4],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup4), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
objectclass=objectclasses.automember,
- dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup4, api.env.basedn),
+ dn=DN(('cn', hostgroup4), ('cn', 'hostgroup'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
),
),
@@ -556,7 +557,7 @@ class test_automember(Declarative):
cn=[hostgroup4],
description=[u'Test desc'],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_exclude_regex3],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup4), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
),
),
),
@@ -574,8 +575,8 @@ class test_automember(Declarative):
cn=[group1],
description=[u'Test desc'],
automemberinclusiveregex=[u'manager=%s' % group_include_regex],
- automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
- dn=u'cn=%s,cn=group,cn=automember,cn=etc,%s' % (group1, api.env.basedn),
+ automembertargetgroup=[DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)],
+ dn=DN(('cn', group1), ('cn', 'group'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
summary=None,
),
@@ -596,8 +597,8 @@ class test_automember(Declarative):
cn=[group1],
description=[u'Test desc'],
automemberinclusiveregex=[u'manager=%s' % group_include_regex],
- automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
- dn=u'cn=%s,cn=group,cn=automember,cn=etc,%s' % (group1, api.env.basedn),
+ automembertargetgroup=[DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)],
+ dn=DN(('cn', group1), ('cn', 'group'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
],
summary=u'1 rules matched',
@@ -618,7 +619,7 @@ class test_automember(Declarative):
cn=[group1],
description=[u'New desc 1'],
automemberinclusiveregex=[u'manager=%s' % group_include_regex],
- automembertargetgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (group1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', group1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)],
),
summary=u'Modified automember rule "%s"' % group1,
value=group1,
@@ -637,7 +638,7 @@ class test_automember(Declarative):
result=dict(
cn=[hostgroup1],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
u'fqdn=%s' % hostgroup_include_regex3,
u'fqdn=%s' % hostgroup_include_regex2,
@@ -646,7 +647,7 @@ class test_automember(Declarative):
u'fqdn=%s' % hostgroup_exclude_regex3,
u'fqdn=%s' % hostgroup_exclude_regex,
],
- dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup1, api.env.basedn),
+ dn=DN(('cn', hostgroup1), ('cn', 'hostgroup'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
summary=None,
),
@@ -666,7 +667,7 @@ class test_automember(Declarative):
dict(
cn=[hostgroup1],
description=[u'Test desc'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
u'fqdn=%s' % hostgroup_include_regex3,
u'fqdn=%s' % hostgroup_include_regex2,
@@ -675,7 +676,7 @@ class test_automember(Declarative):
u'fqdn=%s' % hostgroup_exclude_regex3,
u'fqdn=%s' % hostgroup_exclude_regex,
],
- dn=u'cn=%s,cn=hostgroup,cn=automember,cn=etc,%s' % (hostgroup1, api.env.basedn),
+ dn=DN(('cn', hostgroup1), ('cn', 'hostgroup'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
),
],
summary=u'1 rules matched',
@@ -695,7 +696,7 @@ class test_automember(Declarative):
result=dict(
cn=[hostgroup1],
description=[u'New desc 1'],
- automembertargetgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn)],
+ automembertargetgroup=[DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
automemberinclusiveregex=[u'fqdn=%s' % hostgroup_include_regex,
u'fqdn=%s' % hostgroup_include_regex3,
u'fqdn=%s' % hostgroup_include_regex2,
@@ -722,7 +723,7 @@ class test_automember(Declarative):
expected=dict(
result=dict(
cn=[u'Group'],
- automemberdefaultgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (defaultgroup1, api.env.basedn)],
+ automemberdefaultgroup=[DN(('cn', defaultgroup1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)],
),
value=u'group',
summary=u'Set default (fallback) group for automember "group"',
@@ -737,9 +738,9 @@ class test_automember(Declarative):
),
expected=dict(
result=dict(
- dn=u'cn=group,cn=automember,cn=etc,%s' % (api.env.basedn),
+ dn=DN(('cn', 'group'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
cn=[u'Group'],
- automemberdefaultgroup=[u'cn=%s,cn=groups,cn=accounts,%s' % (defaultgroup1, api.env.basedn)],
+ automemberdefaultgroup=[DN(('cn', defaultgroup1), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)],
),
value=u'group',
summary=None,
@@ -758,7 +759,7 @@ class test_automember(Declarative):
expected=dict(
result=dict(
cn=[u'Hostgroup'],
- automemberdefaultgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn)],
+ automemberdefaultgroup=[DN(('cn', defaulthostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
),
value=u'hostgroup',
summary=u'Set default (fallback) group for automember "hostgroup"',
@@ -775,9 +776,9 @@ class test_automember(Declarative):
),
expected=dict(
result=dict(
- dn=u'cn=hostgroup,cn=automember,cn=etc,%s' % (api.env.basedn),
+ dn=DN(('cn', 'hostgroup'), ('cn', 'automember'), ('cn', 'etc'), api.env.basedn),
cn=[u'Hostgroup'],
- automemberdefaultgroup=[u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn)],
+ automemberdefaultgroup=[DN(('cn', defaulthostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn)],
),
value=u'hostgroup',
summary=None,
@@ -810,10 +811,13 @@ class test_automember(Declarative):
cn=[u'Michael Scott'],
initials=[u'MS'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=[u'cn=global_policy,cn=%s,cn=kerberos,%s' % (api.env.realm, api.env.basedn)],
- mepmanagedentry=[u'cn=%s,cn=groups,cn=accounts,%s' % (manager1, api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'),
+ api.env.basedn)],
+ mepmanagedentry=[DN(('cn', manager1), ('cn', 'groups'), ('cn', 'accounts'),
+ api.env.basedn)],
memberof_group=[u'defaultgroup1', u'ipausers'],
- dn=u'uid=mscott,cn=users,cn=accounts,' + api.env.basedn,
+ dn=DN(('uid', 'mscott'), ('cn', 'users'), ('cn', 'accounts'),
+ api.env.basedn),
),
),
),
@@ -840,15 +844,18 @@ class test_automember(Declarative):
uid=[user1],
uidnumber=[fuzzy_digits],
gidnumber=[fuzzy_digits],
- manager=[u'uid=mscott,cn=users,cn=accounts,%s' % api.env.basedn],
+ manager=[DN(('uid', 'mscott'), ('cn', 'users'), ('cn', 'accounts'), api.env.basedn)],
displayname=[u'Test User1'],
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=[u'cn=global_policy,cn=%s,cn=kerberos,%s' % (api.env.realm, api.env.basedn)],
- mepmanagedentry=[u'cn=%s,cn=groups,cn=accounts,%s' % (user1, api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn', 'global_policy'), ('cn', api.env.realm), ('cn', 'kerberos'),
+ api.env.basedn)],
+ mepmanagedentry=[DN(('cn', user1), ('cn', 'groups'), ('cn', 'accounts'),
+ api.env.basedn)],
memberof_group=[u'group1', u'ipausers'],
- dn=u'uid=tuser1,cn=users,cn=accounts,' + api.env.basedn,
+ dn=DN(('uid', 'tuser1'), ('cn', 'users'), ('cn', 'accounts'),
+ api.env.basedn),
),
),
),
@@ -867,7 +874,7 @@ class test_automember(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
- dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn1, api.env.basedn),
+ dn=DN(('fqdn', fqdn1), ('cn', 'computers'), ('cn', 'accounts'), api.env.basedn),
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -895,7 +902,7 @@ class test_automember(Declarative):
value=fqdn2,
summary=u'Added host "%s"' % fqdn2,
result=dict(
- dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn2, api.env.basedn),
+ dn=DN(('fqdn', fqdn2), ('cn', 'computers'), ('cn', 'accounts'), api.env.basedn),
fqdn=[fqdn2],
description=[u'Test host 2'],
l=[u'Undisclosed location 1'],
@@ -923,7 +930,7 @@ class test_automember(Declarative):
value=fqdn3,
summary=u'Added host "%s"' % fqdn3,
result=dict(
- dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn3, api.env.basedn),
+ dn=DN(('fqdn', fqdn3), ('cn', 'computers'), ('cn', 'accounts'), api.env.basedn),
fqdn=[fqdn3],
description=[u'Test host 3'],
l=[u'Undisclosed location 1'],
@@ -951,7 +958,7 @@ class test_automember(Declarative):
value=fqdn4,
summary=u'Added host "%s"' % fqdn4,
result=dict(
- dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn4, api.env.basedn),
+ dn=DN(('fqdn', fqdn4), ('cn', 'computers'), ('cn', 'accounts'), api.env.basedn),
fqdn=[fqdn4],
description=[u'Test host 4'],
l=[u'Undisclosed location 1'],
@@ -979,7 +986,7 @@ class test_automember(Declarative):
value=fqdn5,
summary=u'Added host "%s"' % fqdn5,
result=dict(
- dn=u'fqdn=%s,cn=computers,cn=accounts,%s' % (fqdn5, api.env.basedn),
+ dn=DN(('fqdn', fqdn5), ('cn', 'computers'), ('cn', 'accounts'), api.env.basedn),
fqdn=[fqdn5],
description=[u'Test host 5'],
l=[u'Undisclosed location 1'],
@@ -1001,7 +1008,7 @@ class test_automember(Declarative):
value=hostgroup1,
summary=None,
result={
- 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup1, api.env.basedn),
+ 'dn': DN(('cn', hostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
'member_host': [u'%s' % fqdn1],
'cn': [hostgroup1],
'description': [u'Test desc'],
@@ -1017,7 +1024,7 @@ class test_automember(Declarative):
value=defaulthostgroup1,
summary=None,
result={
- 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (defaulthostgroup1, api.env.basedn),
+ 'dn': DN(('cn', defaulthostgroup1), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
'member_host': [u'%s' % fqdn2],
'cn': [defaulthostgroup1],
'description': [u'Default test desc'],
@@ -1033,7 +1040,7 @@ class test_automember(Declarative):
value=hostgroup2,
summary=None,
result={
- 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup2, api.env.basedn),
+ 'dn': DN(('cn', hostgroup2), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
'member_host': [u'%s' % fqdn3],
'cn': [hostgroup2],
'description': [u'Test desc'],
@@ -1049,7 +1056,7 @@ class test_automember(Declarative):
value=hostgroup3,
summary=None,
result={
- 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup3, api.env.basedn),
+ 'dn': DN(('cn', hostgroup3), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
'member_host': [u'%s' % fqdn4],
'cn': [hostgroup3],
'description': [u'Test desc'],
@@ -1065,7 +1072,7 @@ class test_automember(Declarative):
value=hostgroup4,
summary=None,
result={
- 'dn': u'cn=%s,cn=hostgroups,cn=accounts,%s' % (hostgroup4, api.env.basedn),
+ 'dn': DN(('cn', hostgroup4), ('cn', 'hostgroups'), ('cn', 'accounts'), api.env.basedn),
'member_host': [u'%s' % fqdn5],
'cn': [hostgroup4],
'description': [u'Test desc'],
diff --git a/tests/test_xmlrpc/test_automount_plugin.py b/tests/test_xmlrpc/test_automount_plugin.py
index d6c289979..19968a0dc 100644
--- a/tests/test_xmlrpc/test_automount_plugin.py
+++ b/tests/test_xmlrpc/test_automount_plugin.py
@@ -28,7 +28,7 @@ import shutil
from ipalib import api
from ipalib import errors
-from ipalib.dn import DN
+from ipapython.dn import DN
from nose.tools import raises, assert_raises # pylint: disable=E0611
from xmlrpc_test import XMLRPC_test, assert_attr_equal
@@ -238,40 +238,36 @@ class test_automount(AutomountTest):
result=dict(
keys={'auto.direct': ()},
orphanmaps=(dict(
- dn=lambda dn: DN(dn) == DN(
- ('automountmapname', self.mapname),
- ('cn', self.locname),
- ('cn', 'automount'), api.env.basedn),
+ dn=DN(('automountmapname', self.mapname),
+ ('cn', self.locname),
+ ('cn', 'automount'), api.env.basedn),
description=(u'description of map',),
automountmapname=(u'testmap',)),),
orphankeys=[(
dict(
- dn=lambda dn: DN(dn) == DN(
- ('description', self.keyname2),
- ('automountmapname', 'testmap'),
- ('cn', self.locname),
- ('cn', 'automount'), api.env.basedn),
+ dn=DN(('description', self.keyname2),
+ ('automountmapname', 'testmap'),
+ ('cn', self.locname),
+ ('cn', 'automount'), api.env.basedn),
automountkey=(self.keyname2,),
description=(self.keyname2,),
automountinformation=(u'ro',),
),
dict(
- dn=lambda dn: DN(dn) == DN(
- ('description', self.keyname_rename),
- ('automountmapname', 'testmap'),
- ('cn', self.locname),
- ('cn', 'automount'), api.env.basedn),
+ dn=DN(('description', self.keyname_rename),
+ ('automountmapname', 'testmap'),
+ ('cn', self.locname),
+ ('cn', 'automount'), api.env.basedn),
automountkey=(self.keyname_rename,),
description=(self.keyname_rename,),
automountinformation=(u'rw',),
))],
maps=(
dict(
- dn=lambda dn: DN(dn) == DN(
- ('description', '/- auto.direct'),
- ('automountmapname', 'auto.master'),
- ('cn', self.locname),
- ('cn', 'automount'), api.env.basedn),
+ dn=DN(('description', '/- auto.direct'),
+ ('automountmapname', 'auto.master'),
+ ('cn', self.locname),
+ ('cn', 'automount'), api.env.basedn),
automountkey=(u'/-',),
description=(u'/- auto.direct',),
automountinformation=(u'auto.direct',)
diff --git a/tests/test_xmlrpc/test_batch_plugin.py b/tests/test_xmlrpc/test_batch_plugin.py
index 19728adda..55e557050 100644
--- a/tests/test_xmlrpc/test_batch_plugin.py
+++ b/tests/test_xmlrpc/test_batch_plugin.py
@@ -25,7 +25,7 @@ from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from tests.util import assert_equal, Fuzzy, assert_deepequal
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import DN
+from ipapython.dn import DN
group1 = u'testgroup1'
@@ -96,11 +96,10 @@ class test_batch(Declarative):
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
gidnumber=[fuzzy_digits],
- dn=lambda x: DN(x) == \
- DN(('cn', 'testgroup1'),
- ('cn', 'groups'),
- ('cn', 'accounts'),
- api.env.basedn),
+ dn=DN(('cn', 'testgroup1'),
+ ('cn', 'groups'),
+ ('cn', 'accounts'),
+ api.env.basedn),
),
error=None),
dict(
@@ -159,11 +158,10 @@ class test_batch(Declarative):
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
gidnumber=[fuzzy_digits],
- dn=lambda x: DN(x) == \
- DN(('cn', 'testgroup1'),
- ('cn', 'groups'),
- ('cn', 'accounts'),
- api.env.basedn),
+ dn=DN(('cn', 'testgroup1'),
+ ('cn', 'groups'),
+ ('cn', 'accounts'),
+ api.env.basedn),
),
error=None),
),
diff --git a/tests/test_xmlrpc/test_cert.py b/tests/test_xmlrpc/test_cert.py
index 90809ab30..4f95ffe19 100644
--- a/tests/test_xmlrpc/test_cert.py
+++ b/tests/test_xmlrpc/test_cert.py
@@ -33,7 +33,7 @@ import tempfile
from ipapython import ipautil
import nose
import base64
-from ipalib.dn import *
+from ipapython.dn import DN
# So we can save the cert from issuance and compare it later
cert = None
diff --git a/tests/test_xmlrpc/test_delegation_plugin.py b/tests/test_xmlrpc/test_delegation_plugin.py
index 95aa82877..a31fed3ed 100644
--- a/tests/test_xmlrpc/test_delegation_plugin.py
+++ b/tests/test_xmlrpc/test_delegation_plugin.py
@@ -24,6 +24,7 @@ Test the `ipalib/plugins/delegation.py` module.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
+from ipapython.dn import DN
delegation1 = u'testdelegation'
member1 = u'admins'
@@ -148,8 +149,9 @@ class test_delegation(Declarative):
value=delegation1,
summary=None,
result={
- 'aci': u'(targetattr = "street || c || l || st || postalcode")(targetfilter = "(memberOf=cn=admins,cn=groups,cn=accounts,%s)")(version 3.0;acl "delegation:testdelegation";allow (write) groupdn = "ldap:///cn=editors,cn=groups,cn=accounts,%s";)' \
- % (api.env.basedn, api.env.basedn)
+ 'aci': u'(targetattr = "street || c || l || st || postalcode")(targetfilter = "(memberOf=%s)")(version 3.0;acl "delegation:testdelegation";allow (write) groupdn = "ldap:///%s";)' % \
+ (DN(('cn', 'admins'), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn),
+ DN(('cn', 'editors'), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn))
},
),
),
@@ -200,8 +202,9 @@ class test_delegation(Declarative):
summary=u'1 delegation matched',
result=[
{
- 'aci': u'(targetattr = "street || c || l || st || postalcode")(targetfilter = "(memberOf=cn=admins,cn=groups,cn=accounts,%s)")(version 3.0;acl "delegation:testdelegation";allow (write) groupdn = "ldap:///cn=editors,cn=groups,cn=accounts,%s";)' \
- % (api.env.basedn, api.env.basedn),
+ 'aci': u'(targetattr = "street || c || l || st || postalcode")(targetfilter = "(memberOf=%s)")(version 3.0;acl "delegation:testdelegation";allow (write) groupdn = "ldap:///%s";)' % \
+ (DN(('cn', 'admins'), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn),
+ DN(('cn', 'editors'), ('cn', 'groups'), ('cn', 'accounts'), api.env.basedn)),
},
],
),
diff --git a/tests/test_xmlrpc/test_dns_plugin.py b/tests/test_xmlrpc/test_dns_plugin.py
index 9c9b22392..2b6d53c0b 100644
--- a/tests/test_xmlrpc/test_dns_plugin.py
+++ b/tests/test_xmlrpc/test_dns_plugin.py
@@ -22,7 +22,7 @@ Test the `ipalib/plugins/dns.py` module.
import nose
from ipalib import api, errors
-from ipalib.dn import *
+from ipapython.dn import DN
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
@@ -139,7 +139,7 @@ class test_dns(Declarative):
'value': dnszone1,
'summary': None,
'result': {
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [dnszone1],
'idnszoneactive': [u'TRUE'],
'idnssoamname': [dnszone1_mname],
@@ -200,7 +200,7 @@ class test_dns(Declarative):
'value': dnszone2,
'summary': None,
'result': {
- 'dn': unicode(dnszone2_dn),
+ 'dn': dnszone2_dn,
'idnsname': [dnszone2],
'idnszoneactive': [u'TRUE'],
'idnssoamname': [dnszone2_mname],
@@ -240,7 +240,7 @@ class test_dns(Declarative):
'value': dnszone1,
'summary': None,
'result': {
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [dnszone1],
'idnszoneactive': [u'TRUE'],
'nsrecord': [dnszone1_mname],
@@ -295,7 +295,7 @@ class test_dns(Declarative):
'value': revdnszone1,
'summary': None,
'result': {
- 'dn': unicode(revdnszone1_dn),
+ 'dn': revdnszone1_dn,
'idnsname': [revdnszone1],
'idnszoneactive': [u'TRUE'],
'idnssoamname': [dnszone1_mname],
@@ -325,7 +325,7 @@ class test_dns(Declarative):
'count': 2,
'truncated': False,
'result': [{
- 'dn': unicode(revdnszone1_dn),
+ 'dn': revdnszone1_dn,
'idnsname': [revdnszone1],
'idnszoneactive': [u'TRUE'],
'nsrecord': [dnszone1_mname],
@@ -340,7 +340,7 @@ class test_dns(Declarative):
'idnsallowquery': [u'any;'],
},
{
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [dnszone1],
'idnszoneactive': [u'TRUE'],
'nsrecord': [dnszone1_mname],
@@ -366,7 +366,7 @@ class test_dns(Declarative):
'count': 1,
'truncated': False,
'result': [{
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [dnszone1],
'idnszoneactive': [u'TRUE'],
'nsrecord': [dnszone1_mname],
@@ -413,7 +413,7 @@ class test_dns(Declarative):
'value': dnszone1,
'summary': None,
'result': {
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [dnszone1],
'idnszoneactive': [u'FALSE'],
'nsrecord': [dnszone1_mname],
@@ -449,7 +449,7 @@ class test_dns(Declarative):
'value': dnszone1,
'summary': None,
'result': {
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [dnszone1],
'idnszoneactive': [u'TRUE'],
'nsrecord': [dnszone1_mname],
@@ -507,7 +507,7 @@ class test_dns(Declarative):
'value': dnsres1,
'summary': None,
'result': {
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'objectclass': objectclasses.dnsrecord,
'arecord': [u'127.0.0.1'],
@@ -525,17 +525,17 @@ class test_dns(Declarative):
'truncated': False,
'result': [
{
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'nsrecord': (dnszone1_mname,),
'idnsname': [u'@'],
},
{
- 'dn': unicode(dnszone1_mname_dn),
+ 'dn': dnszone1_mname_dn,
'idnsname': [u'ns1'],
'arecord': [u'1.2.3.4'],
},
{
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'arecord': [u'127.0.0.1'],
},
@@ -551,7 +551,7 @@ class test_dns(Declarative):
'value': dnsres1,
'summary': None,
'result': {
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'arecord': [u'127.0.0.1', u'10.10.0.1'],
'objectclass': objectclasses.dnsrecord,
@@ -633,7 +633,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnszone,
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [u'@'],
'mxrecord': [u"0 %s" % dnszone1_mname],
'nsrecord': [dnszone1_mname],
@@ -681,7 +681,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(DN(('idnsname', u'_foo._tcp'), dnszone1_dn)),
+ 'dn': DN(('idnsname', u'_foo._tcp'), dnszone1_dn),
'idnsname': [u'_foo._tcp'],
'srvrecord': [u"0 100 1234 %s" % dnszone1_mname],
},
@@ -738,7 +738,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnszone,
- 'dn': unicode(dnszone1_dn),
+ 'dn': dnszone1_dn,
'idnsname': [u'@'],
'mxrecord': [u"0 %s" % dnszone1_mname],
'nsrecord': [dnszone1_mname],
@@ -770,7 +770,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsrescname_dn),
+ 'dn': dnsrescname_dn,
'idnsname': [dnsrescname],
'cnamerecord': [u'foo-1.example.com.'],
},
@@ -821,7 +821,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
'kxrecord': [u'1 foo-1'],
@@ -837,7 +837,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
'kxrecord': [u'1 foo-1'],
@@ -856,7 +856,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
'kxrecord': [u'1 foo-1'],
@@ -887,7 +887,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'arecord': [u'10.10.0.1'],
'kxrecord': [u'1 foo-1'],
@@ -962,7 +962,7 @@ class test_dns(Declarative):
'value': revdnszone1,
'summary': None,
'result': {
- 'dn': unicode(revdnszone1_dn),
+ 'dn': revdnszone1_dn,
'idnsname': [revdnszone1],
'idnszoneactive': [u'TRUE'],
'idnssoamname': [dnszone1_mname],
@@ -1000,7 +1000,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsrev1_dn),
+ 'dn': dnsrev1_dn,
'idnsname': [dnsrev1],
'ptrrecord': [u'foo-1.example.com.'],
},
@@ -1015,7 +1015,7 @@ class test_dns(Declarative):
'summary': None,
'result': {
'objectclass': objectclasses.dnsrecord,
- 'dn': unicode(dnsrev1_dn),
+ 'dn': dnsrev1_dn,
'idnsname': [dnsrev1],
'ptrrecord': [u'foo-1.example.com.'],
'cnamerecord': [u'foo-1.example.com.'],
@@ -1120,7 +1120,7 @@ class test_dns(Declarative):
'value': dnsres1,
'summary': None,
'result': {
- 'dn': unicode(dnsres1_dn),
+ 'dn': dnsres1_dn,
'idnsname': [dnsres1],
'objectclass': objectclasses.dnsrecord,
'arecord': [u'80.142.15.81'],
@@ -1136,7 +1136,7 @@ class test_dns(Declarative):
'value': dnsrev2,
'summary': None,
'result': {
- 'dn': unicode(dnsrev2_dn),
+ 'dn': dnsrev2_dn,
'idnsname': [dnsrev2],
'ptrrecord': [dnsres1 + '.' + dnszone1 + '.'],
},
@@ -1183,7 +1183,7 @@ class test_dns(Declarative):
value=dnszone1_permission,
summary=None,
result={
- 'dn': lambda x: DN(x) == dnszone1_permission_dn,
+ 'dn': dnszone1_permission_dn,
'cn': [dnszone1_permission],
'ipapermissiontype': [u'SYSTEM'],
},
@@ -1232,4 +1232,3 @@ class test_dns(Declarative):
),
]
-
diff --git a/tests/test_xmlrpc/test_group_plugin.py b/tests/test_xmlrpc/test_group_plugin.py
index 08cf74185..de4635d3c 100644
--- a/tests/test_xmlrpc/test_group_plugin.py
+++ b/tests/test_xmlrpc/test_group_plugin.py
@@ -24,7 +24,7 @@ Test the `ipalib/plugins/group.py` module.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
group1 = u'testgroup1'
group2 = u'testgroup2'
@@ -48,6 +48,7 @@ class test_group(Declarative):
('group_del', [group1], {}),
('group_del', [group2], {}),
('group_del', [group3], {}),
+ ('group_del', [renamedgroup1], {}),
('user_del', [user1], {}),
]
@@ -96,7 +97,7 @@ class test_group(Declarative):
description=[u'Test desc 1'],
objectclass=objectclasses.group,
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == get_group_dn('testgroup1'),
+ dn=get_group_dn('testgroup1'),
),
),
),
@@ -121,7 +122,7 @@ class test_group(Declarative):
result=dict(
cn=[group1],
description=[u'Test desc 1'],
- dn=lambda x: DN(x) == get_group_dn('testgroup1'),
+ dn=get_group_dn('testgroup1'),
),
),
),
@@ -151,7 +152,7 @@ class test_group(Declarative):
result=dict(
cn=[group1],
description=[u'New desc 1'],
- dn=lambda x: DN(x) == get_group_dn('testgroup1'),
+ dn=get_group_dn('testgroup1'),
),
summary=None,
),
@@ -184,7 +185,7 @@ class test_group(Declarative):
result=dict(
cn=[group1],
description=(u'New desc 1',),
- dn=lambda x: DN(x) == get_group_dn('testgroup1'),
+ dn=get_group_dn('testgroup1'),
gidnumber=[fuzzy_digits],
),
summary=None,
@@ -200,7 +201,7 @@ class test_group(Declarative):
truncated=False,
result=[
dict(
- dn=lambda x: DN(x) == get_group_dn(group1),
+ dn=get_group_dn(group1),
cn=[group1],
description=[u'New desc 1'],
gidnumber=[fuzzy_digits],
@@ -249,7 +250,7 @@ class test_group(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == get_group_dn('testgroup2'),
+ dn=get_group_dn('testgroup2'),
),
),
),
@@ -275,7 +276,7 @@ class test_group(Declarative):
cn=[group2],
description=[u'Test desc 2'],
gidnumber=[fuzzy_digits],
- dn=lambda x: DN(x) == get_group_dn('testgroup2'),
+ dn=get_group_dn('testgroup2'),
),
),
),
@@ -307,7 +308,7 @@ class test_group(Declarative):
cn=[group2],
description=[u'New desc 2'],
gidnumber=[fuzzy_digits],
- dn=lambda x: DN(x) == get_group_dn('testgroup2'),
+ dn=get_group_dn('testgroup2'),
),
summary=None,
),
@@ -322,7 +323,7 @@ class test_group(Declarative):
truncated=False,
result=[
dict(
- dn=lambda x: DN(x) == get_group_dn('testgroup2'),
+ dn=get_group_dn('testgroup2'),
cn=[group2],
description=[u'New desc 2'],
gidnumber=[fuzzy_digits],
@@ -342,37 +343,37 @@ class test_group(Declarative):
truncated=False,
result=[
{
- 'dn': lambda x: DN(x) == get_group_dn('admins'),
+ 'dn': get_group_dn('admins'),
'member_user': [u'admin'],
'gidnumber': [fuzzy_digits],
'cn': [u'admins'],
'description': [u'Account administrators group'],
},
{
- 'dn': lambda x: DN(x) == get_group_dn('editors'),
+ 'dn': get_group_dn('editors'),
'gidnumber': [fuzzy_digits],
'cn': [u'editors'],
'description': [u'Limited admins who can edit other users'],
},
{
- 'dn': lambda x: DN(x) == get_group_dn('ipausers'),
+ 'dn': get_group_dn('ipausers'),
'cn': [u'ipausers'],
'description': [u'Default group for all users'],
},
dict(
- dn=lambda x: DN(x) == get_group_dn(group1),
+ dn=get_group_dn(group1),
cn=[group1],
description=[u'New desc 1'],
gidnumber=[fuzzy_digits],
),
dict(
- dn=lambda x: DN(x) == get_group_dn(group2),
+ dn=get_group_dn(group2),
cn=[group2],
description=[u'New desc 2'],
gidnumber=[fuzzy_digits],
),
{
- 'dn': lambda x: DN(x) == get_group_dn('trust admins'),
+ 'dn': get_group_dn('trust admins'),
'member_user': [u'admin'],
'cn': [u'trust admins'],
'description': [u'Trusts administrators group'],
@@ -396,7 +397,7 @@ class test_group(Declarative):
description=[u'Test desc 3'],
objectclass=objectclasses.externalgroup,
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == get_group_dn(group3),
+ dn=get_group_dn(group3),
),
),
),
@@ -456,7 +457,7 @@ class test_group(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == get_group_dn(group1),
+ 'dn': get_group_dn(group1),
'member_group': (group2,),
'gidnumber': [fuzzy_digits],
'cn': [group1],
@@ -480,7 +481,7 @@ class test_group(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == get_group_dn(group1),
+ 'dn': get_group_dn(group1),
'member_group': (group2,),
'gidnumber': [fuzzy_digits],
'cn': [group1],
@@ -503,7 +504,7 @@ class test_group(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == get_group_dn(group1),
+ 'dn': get_group_dn(group1),
'cn': [group1],
'gidnumber': [fuzzy_digits],
'description': [u'New desc 1'],
@@ -526,7 +527,7 @@ class test_group(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == get_group_dn(group1),
+ 'dn': get_group_dn(group1),
'cn': [group1],
'gidnumber': [fuzzy_digits],
'description': [u'New desc 1'],
@@ -691,15 +692,12 @@ class test_group(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [get_group_dn(user1)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[get_group_dn(user1)],
memberof_group=[u'ipausers'],
- dn=lambda x: DN(x) == \
- DN(('uid',user1),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid',user1),('cn','users'),('cn','accounts'),
+ api.env.basedn),
has_keytab=False,
has_password=False,
),
@@ -717,7 +715,7 @@ class test_group(Declarative):
cn=[user1],
description=[u'User private group for %s' % user1],
gidnumber=[fuzzy_digits],
- dn=lambda x: DN(x) == get_group_dn(user1),
+ dn=get_group_dn(user1),
),
),
),
@@ -731,7 +729,7 @@ class test_group(Declarative):
truncated=False,
result=[
dict(
- dn=lambda x: DN(x) == get_group_dn(user1),
+ dn=get_group_dn(user1),
cn=[user1],
description=[u'User private group for %s' % user1],
gidnumber=[fuzzy_digits],
@@ -810,12 +808,10 @@ class test_group(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
@@ -848,7 +844,7 @@ class test_group(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == get_group_dn('admins'),
+ 'dn': get_group_dn('admins'),
'member_user': [u'admin', user1],
'gidnumber': [fuzzy_digits],
'cn': [u'admins'],
diff --git a/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py b/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py
index 1552f46ce..591c8a966 100644
--- a/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py
+++ b/tests/test_xmlrpc/test_hbacsvcgroup_plugin.py
@@ -24,7 +24,7 @@ Test the `ipalib.plugins.hbacsvcgroup` module.
from ipalib import api, errors
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
from tests.test_xmlrpc import objectclasses
-from ipalib.dn import *
+from ipapython.dn import DN
hbacsvcgroup1 = u'testhbacsvcgroup1'
dn1 = DN(('cn',hbacsvcgroup1),('cn','hbacservicegroups'),('cn','hbac'),
@@ -79,7 +79,7 @@ class test_hbacsvcgroup(Declarative):
value=hbacsvcgroup1,
summary=u'Added HBAC service group "testhbacsvcgroup1"',
result=dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
cn=[hbacsvcgroup1],
objectclass=objectclasses.hbacsvcgroup,
description=[u'Test hbacsvcgroup 1'],
@@ -111,7 +111,7 @@ class test_hbacsvcgroup(Declarative):
value=hbacsvc1,
summary=u'Added HBAC service "%s"' % hbacsvc1,
result=dict(
- dn=lambda x: DN(x) == hbacsvc_dn1,
+ dn=hbacsvc_dn1,
cn=[hbacsvc1],
description=[u'Test service 1'],
objectclass=objectclasses.hbacsvc,
@@ -134,7 +134,7 @@ class test_hbacsvcgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'cn': [hbacsvcgroup1],
'description': [u'Test hbacsvcgroup 1'],
'member_hbacsvc': [hbacsvc1],
@@ -150,7 +150,7 @@ class test_hbacsvcgroup(Declarative):
value=hbacsvcgroup1,
summary=None,
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'member_hbacsvc': [hbacsvc1],
'cn': [hbacsvcgroup1],
'description': [u'Test hbacsvcgroup 1'],
@@ -168,7 +168,7 @@ class test_hbacsvcgroup(Declarative):
summary=u'1 HBAC service group matched',
result=[
{
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'member_hbacsvc': [hbacsvc1],
'cn': [hbacsvcgroup1],
'description': [u'Test hbacsvcgroup 1'],
@@ -202,7 +202,7 @@ class test_hbacsvcgroup(Declarative):
value=hbacsvcgroup1,
summary=None,
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'member_hbacsvc': [hbacsvc1],
'cn': [hbacsvcgroup1],
'description': [u'Updated hbacsvcgroup 1'],
@@ -224,7 +224,7 @@ class test_hbacsvcgroup(Declarative):
),
completed=1,
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'cn': [hbacsvcgroup1],
'description': [u'Updated hbacsvcgroup 1'],
},
diff --git a/tests/test_xmlrpc/test_host_plugin.py b/tests/test_xmlrpc/test_host_plugin.py
index c9ec6a2bd..27d3adb04 100644
--- a/tests/test_xmlrpc/test_host_plugin.py
+++ b/tests/test_xmlrpc/test_host_plugin.py
@@ -26,7 +26,7 @@ import os
import tempfile
from ipapython import ipautil
from ipalib import api, errors, x509
-from ipalib.dn import *
+from ipapython.dn import DN
from nose.tools import raises, assert_raises
from nose.plugins.skip import Skip, SkipTest
from tests.test_xmlrpc.xmlrpc_test import (Declarative, XMLRPC_test,
@@ -111,7 +111,7 @@ class test_host(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -147,7 +147,7 @@ class test_host(Declarative):
value=fqdn1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -167,7 +167,7 @@ class test_host(Declarative):
value=fqdn1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
cn=[fqdn1],
fqdn=[fqdn1],
description=[u'Test host 1'],
@@ -198,7 +198,7 @@ class test_host(Declarative):
summary=u'1 host matched',
result=[
dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -221,7 +221,7 @@ class test_host(Declarative):
summary=u'1 host matched',
result=[
dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
cn=[fqdn1],
fqdn=[fqdn1],
description=[u'Test host 1'],
@@ -260,8 +260,7 @@ class test_host(Declarative):
usercertificate=[base64.b64decode(servercert)],
valid_not_before=fuzzy_date,
valid_not_after=fuzzy_date,
- subject=lambda x: DN(x) == \
- DN(('CN',api.env.host),x509.subject_base()),
+ subject=DN(('CN',api.env.host),x509.subject_base()),
serial_number=fuzzy_digits,
serial_number_hex=fuzzy_hex,
md5_fingerprint=fuzzy_hash,
@@ -281,7 +280,7 @@ class test_host(Declarative):
value=fqdn1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
fqdn=[fqdn1],
description=[u'Updated host 1'],
l=[u'Undisclosed location 1'],
@@ -292,8 +291,7 @@ class test_host(Declarative):
usercertificate=[base64.b64decode(servercert)],
valid_not_before=fuzzy_date,
valid_not_after=fuzzy_date,
- subject=lambda x: DN(x) == \
- DN(('CN',api.env.host),x509.subject_base()),
+ subject=DN(('CN',api.env.host),x509.subject_base()),
serial_number=fuzzy_digits,
serial_number_hex=fuzzy_hex,
md5_fingerprint=fuzzy_hash,
@@ -316,7 +314,7 @@ class test_host(Declarative):
value=fqdn3,
summary=u'Added host "%s"' % fqdn3,
result=dict(
- dn=lambda x: DN(x) == dn3,
+ dn=dn3,
fqdn=[fqdn3],
description=[u'Test host 2'],
l=[u'Undisclosed location 2'],
@@ -344,7 +342,7 @@ class test_host(Declarative):
value=fqdn4,
summary=u'Added host "%s"' % fqdn4,
result=dict(
- dn=lambda x: DN(x) == dn4,
+ dn=dn4,
fqdn=[fqdn4],
description=[u'Test host 4'],
l=[u'Undisclosed location 4'],
@@ -374,7 +372,7 @@ class test_host(Declarative):
),
),
result=dict(
- dn=lambda x: DN(x) == dn3,
+ dn=dn3,
fqdn=[fqdn3],
description=[u'Test host 2'],
l=[u'Undisclosed location 2'],
@@ -391,7 +389,7 @@ class test_host(Declarative):
value=fqdn3,
summary=None,
result=dict(
- dn=lambda x: DN(x) == dn3,
+ dn=dn3,
fqdn=[fqdn3],
description=[u'Test host 2'],
l=[u'Undisclosed location 2'],
@@ -412,7 +410,7 @@ class test_host(Declarative):
summary=u'1 host matched',
result=[
dict(
- dn=lambda x: DN(x) == dn3,
+ dn=dn3,
fqdn=[fqdn3],
description=[u'Test host 2'],
l=[u'Undisclosed location 2'],
@@ -451,7 +449,7 @@ class test_host(Declarative):
),
),
result=dict(
- dn=lambda x: DN(x) == dn3,
+ dn=dn3,
fqdn=[fqdn3],
description=[u'Test host 2'],
l=[u'Undisclosed location 2'],
@@ -491,8 +489,7 @@ class test_host(Declarative):
usercertificate=[base64.b64decode(servercert)],
valid_not_before=fuzzy_date,
valid_not_after=fuzzy_date,
- subject=lambda x: DN(x) == \
- DN(('CN',api.env.host),x509.subject_base()),
+ subject=DN(('CN',api.env.host),x509.subject_base()),
serial_number=fuzzy_digits,
serial_number_hex=fuzzy_hex,
md5_fingerprint=fuzzy_hash,
@@ -521,8 +518,7 @@ class test_host(Declarative):
usercertificate=[base64.b64decode(servercert)],
valid_not_before=fuzzy_date,
valid_not_after=fuzzy_date,
- subject=lambda x: DN(x) == \
- DN(('CN',api.env.host),x509.subject_base()),
+ subject=DN(('CN',api.env.host),x509.subject_base()),
serial_number=fuzzy_digits,
serial_number_hex=fuzzy_hex,
md5_fingerprint=fuzzy_hash,
@@ -591,7 +587,7 @@ class test_host(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -612,7 +608,7 @@ class test_host(Declarative):
value=service1,
summary=u'Added service "%s"' % service1,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
objectclass=objectclasses.service,
managedby_host=[fqdn1],
@@ -666,7 +662,7 @@ class test_host(Declarative):
value=fqdn2,
summary=u'Added host "%s"' % fqdn2,
result=dict(
- dn=lambda x: DN(x) == dn2,
+ dn=dn2,
fqdn=[fqdn2],
description=[u'Test host 2'],
l=[u'Undisclosed location 2'],
diff --git a/tests/test_xmlrpc/test_hostgroup_plugin.py b/tests/test_xmlrpc/test_hostgroup_plugin.py
index 5642b1097..36c497ba8 100644
--- a/tests/test_xmlrpc/test_hostgroup_plugin.py
+++ b/tests/test_xmlrpc/test_hostgroup_plugin.py
@@ -23,10 +23,9 @@ Test the `ipalib.plugins.hostgroup` module.
"""
from ipalib import api, errors
-from ipalib.dn import *
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
from tests.test_xmlrpc import objectclasses
-from ipalib.dn import *
+from ipapython.dn import DN
hostgroup1 = u'testhostgroup1'
dn1 = DN(('cn',hostgroup1),('cn','hostgroups'),('cn','accounts'),
@@ -95,14 +94,13 @@ class test_hostgroup(Declarative):
value=hostgroup1,
summary=u'Added hostgroup "testhostgroup1"',
result=dict(
- dn=lambda x: DN(x) == dn1,
+ dn=dn1,
cn=[hostgroup1],
objectclass=objectclasses.hostgroup,
description=[u'Test hostgroup 1'],
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',hostgroup1),('cn','ng'),('cn','alt'),
- api.env.basedn)],
+ mepmanagedentry=[DN(('cn',hostgroup1),('cn','ng'),('cn','alt'),
+ api.env.basedn)],
),
),
),
@@ -131,7 +129,7 @@ class test_hostgroup(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
- dn=lambda x: DN(x) == host_dn1,
+ dn=host_dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -160,7 +158,7 @@ class test_hostgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'cn': [hostgroup1],
'description': [u'Test hostgroup 1'],
'member_host': [fqdn1],
@@ -176,7 +174,7 @@ class test_hostgroup(Declarative):
value=hostgroup1,
summary=None,
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'member_host': [u'testhost1.%s' % api.env.domain],
'cn': [hostgroup1],
'description': [u'Test hostgroup 1'],
@@ -194,7 +192,7 @@ class test_hostgroup(Declarative):
summary=u'1 hostgroup matched',
result=[
{
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'member_host': [u'testhost1.%s' % api.env.domain],
'cn': [hostgroup1],
'description': [u'Test hostgroup 1'],
@@ -228,7 +226,7 @@ class test_hostgroup(Declarative):
value=hostgroup1,
summary=None,
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'member_host': [u'testhost1.%s' % api.env.domain],
'cn': [hostgroup1],
'description': [u'Updated hostgroup 1'],
@@ -251,7 +249,7 @@ class test_hostgroup(Declarative):
),
completed=1,
result={
- 'dn': lambda x: DN(x) == dn1,
+ 'dn': dn1,
'cn': [hostgroup1],
'description': [u'Updated hostgroup 1'],
},
@@ -279,14 +277,13 @@ class test_hostgroup(Declarative):
value=hostgroup_single,
summary=u'Added hostgroup "a"',
result=dict(
- dn=lambda x: DN(x) == dn_single,
+ dn=dn_single,
cn=[hostgroup_single],
objectclass=objectclasses.hostgroup,
description=[u'Test hostgroup with single letter in name'],
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',hostgroup_single),('cn','ng'),('cn','alt'),
- api.env.basedn)],
+ mepmanagedentry=[DN(('cn',hostgroup_single),('cn','ng'),('cn','alt'),
+ api.env.basedn)],
),
),
),
diff --git a/tests/test_xmlrpc/test_krbtpolicy.py b/tests/test_xmlrpc/test_krbtpolicy.py
index 26ba87c47..fc2bf54cf 100644
--- a/tests/test_xmlrpc/test_krbtpolicy.py
+++ b/tests/test_xmlrpc/test_krbtpolicy.py
@@ -23,7 +23,7 @@ Test kerberos ticket policy
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
user1 = u'tuser1'
@@ -61,9 +61,8 @@ class test_krbtpolicy(Declarative):
value=u'',
summary=None,
result=dict(
- dn=lambda x: DN(x) == \
- DN(('cn',api.env.domain),('cn','kerberos'),
- api.env.basedn),
+ dn=DN(('cn',api.env.domain),('cn','kerberos'),
+ api.env.basedn),
krbmaxticketlife=[u'86400'],
krbmaxrenewableage=[u'604800'],
),
@@ -110,18 +109,14 @@ class test_krbtpolicy(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid',user1),('cn','users'),('cn','accounts'),
- api.env.basedn)
+ dn=DN(('uid',user1),('cn','users'),('cn','accounts'), api.env.basedn)
),
),
),
diff --git a/tests/test_xmlrpc/test_nesting.py b/tests/test_xmlrpc/test_nesting.py
index a855960a1..c28b7096b 100644
--- a/tests/test_xmlrpc/test_nesting.py
+++ b/tests/test_xmlrpc/test_nesting.py
@@ -23,7 +23,7 @@ Test group nexting an indirect members
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
group1 = u'testgroup1'
group2 = u'testgroup2'
@@ -80,9 +80,8 @@ class test_nesting(Declarative):
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
gidnumber=[fuzzy_digits],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup1'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup1'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -104,9 +103,8 @@ class test_nesting(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup2'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup2'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -126,9 +124,8 @@ class test_nesting(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup3'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup3'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -148,9 +145,8 @@ class test_nesting(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup4'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup4'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -179,18 +175,15 @@ class test_nesting(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid',user1),('cn','users'),('cn','accounts'),
- api.env.basedn)
+ dn=DN(('uid',user1),('cn','users'),('cn','accounts'),
+ api.env.basedn)
),
),
),
@@ -219,18 +212,15 @@ class test_nesting(Declarative):
cn=[u'Test User2'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user2),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid',user2),('cn','users'),('cn','accounts'),
- api.env.basedn)
+ dn=DN(('uid',user2),('cn','users'),('cn','accounts'),
+ api.env.basedn)
),
),
),
@@ -259,18 +249,15 @@ class test_nesting(Declarative):
cn=[u'Test User3'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user3),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user3),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid',user3),('cn','users'),('cn','accounts'),
- api.env.basedn)
+ dn=DN(('uid',user3),('cn','users'),('cn','accounts'),
+ api.env.basedn)
),
),
),
@@ -299,18 +286,15 @@ class test_nesting(Declarative):
cn=[u'Test User4'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user4),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user4),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid',user4),('cn','users'),('cn','accounts'),
- api.env.basedn)
+ dn=DN(('uid',user4),('cn','users'),('cn','accounts'),
+ api.env.basedn)
),
),
),
@@ -375,9 +359,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group1),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group1),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_group': (group2,),
'gidnumber': [fuzzy_digits],
'cn': [group1],
@@ -401,9 +384,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group1),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group1),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_group': [group2, group3,],
'gidnumber': [fuzzy_digits],
'cn': [group1],
@@ -427,9 +409,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group2),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group2),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': (u'tuser1',),
'memberof_group': (u'testgroup1',),
'gidnumber': [fuzzy_digits],
@@ -454,9 +435,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group2),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group2),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': [user1, user2],
'memberof_group': [group1],
'gidnumber': [fuzzy_digits],
@@ -481,9 +461,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group3),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group3),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': [user3],
'memberof_group': [group1],
'gidnumber': [fuzzy_digits],
@@ -508,9 +487,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group3),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group3),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': [user3],
'memberof_group': [group1],
'member_group': [group4],
@@ -536,9 +514,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group4),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group4),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': [user1],
'memberof_group': [group3],
'memberofindirect_group': [group1],
@@ -564,9 +541,8 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group4),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group4),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': [user1, user4],
'memberof_group': [group3],
'memberofindirect_group': [group1],
@@ -591,9 +567,8 @@ class test_nesting(Declarative):
memberindirect_group = [group4],
member_group = [group2, group3],
memberindirect_user = [user1, user2, user3, user4],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup1'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup1'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -611,9 +586,8 @@ class test_nesting(Declarative):
gidnumber= [fuzzy_digits],
memberof_group = [group1],
member_user = [user1, user2],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup2'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup2'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -633,9 +607,8 @@ class test_nesting(Declarative):
member_user = [user3],
member_group = [group4],
memberindirect_user = [user1, user4],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup3'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup3'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -654,9 +627,8 @@ class test_nesting(Declarative):
memberof_group = [group3],
member_user = [user1, user4],
memberofindirect_group = [group1],
- dn=lambda x: DN(x) == \
- DN(('cn','testgroup4'),('cn','groups'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('cn','testgroup4'),('cn','groups'),
+ ('cn','accounts'),api.env.basedn),
),
),
),
@@ -676,7 +648,7 @@ class test_nesting(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
- dn=lambda x: DN(x) == host_dn1,
+ dn=host_dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -700,14 +672,13 @@ class test_nesting(Declarative):
value=hostgroup1,
summary=u'Added hostgroup "testhostgroup1"',
result=dict(
- dn=lambda x: DN(x) == hgdn1,
+ dn=hgdn1,
cn=[hostgroup1],
objectclass=objectclasses.hostgroup,
description=[u'Test hostgroup 1'],
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',hostgroup1),('cn','ng'),('cn','alt'),
- api.env.basedn)],
+ mepmanagedentry=[DN(('cn',hostgroup1),('cn','ng'),('cn','alt'),
+ api.env.basedn)],
),
),
),
@@ -722,14 +693,13 @@ class test_nesting(Declarative):
value=hostgroup2,
summary=u'Added hostgroup "testhostgroup2"',
result=dict(
- dn=lambda x: DN(x) == hgdn2,
+ dn=hgdn2,
cn=[hostgroup2],
objectclass=objectclasses.hostgroup,
description=[u'Test hostgroup 2'],
ipauniqueid=[fuzzy_uuid],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',hostgroup2),('cn','ng'),('cn','alt'),
- api.env.basedn)],
+ mepmanagedentry=[DN(('cn',hostgroup2),('cn','ng'),('cn','alt'),
+ api.env.basedn)],
),
),
),
@@ -749,7 +719,7 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == hgdn2,
+ 'dn': hgdn2,
'cn': [hostgroup2],
'description': [u'Test hostgroup 2'],
'member_host': [fqdn1],
@@ -772,7 +742,7 @@ class test_nesting(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == hgdn1,
+ 'dn': hgdn1,
'cn': [hostgroup1],
'description': [u'Test hostgroup 1'],
'member_hostgroup': [hostgroup2],
@@ -788,7 +758,7 @@ class test_nesting(Declarative):
value=hostgroup1,
summary=None,
result={
- 'dn': lambda x: DN(x) == hgdn1,
+ 'dn': hgdn1,
'memberindirect_host': [u'testhost1.%s' % api.env.domain],
'member_hostgroup': [hostgroup2],
'cn': [hostgroup1],
@@ -805,7 +775,7 @@ class test_nesting(Declarative):
value=fqdn1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == host_dn1,
+ dn=host_dn1,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
diff --git a/tests/test_xmlrpc/test_netgroup_plugin.py b/tests/test_xmlrpc/test_netgroup_plugin.py
index 951bc77a3..b54291a64 100644
--- a/tests/test_xmlrpc/test_netgroup_plugin.py
+++ b/tests/test_xmlrpc/test_netgroup_plugin.py
@@ -28,7 +28,7 @@ from ipalib import errors
from ipaserver.plugins.ldap2 import ldap2
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid, fuzzy_netgroupdn
from tests.test_xmlrpc import objectclasses
-from ipalib.dn import *
+from ipapython.dn import DN
# Global so we can save the value between tests
netgroup_dn = None
@@ -142,7 +142,6 @@ class test_netgroup(Declarative):
value=netgroup1,
summary=u'Added netgroup "%s"' % netgroup1,
result=dict(
-# dn=u'ipauniqueid=%s,cn=ng,cn=alt,%s' % (fuzzy_uuid, api.env.basedn),
dn=fuzzy_netgroupdn,
cn=[netgroup1],
objectclass=objectclasses.netgroup,
@@ -163,7 +162,6 @@ class test_netgroup(Declarative):
value=netgroup2,
summary=u'Added netgroup "%s"' % netgroup2,
result=dict(
-# dn=u'ipauniqueid=%s,cn=ng,cn=alt,%s' % (fuzzy_uuid, api.env.basedn),
dn=fuzzy_netgroupdn,
cn=[netgroup2],
objectclass=objectclasses.netgroup,
@@ -229,7 +227,7 @@ class test_netgroup(Declarative):
value=host1,
summary=u'Added host "%s"' % host1,
result=dict(
- dn=lambda x: DN(x) == host_dn1,
+ dn=host_dn1,
fqdn=[host1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -253,13 +251,12 @@ class test_netgroup(Declarative):
value=hostgroup1,
summary=u'Added hostgroup "%s"' % hostgroup1,
result=dict(
- dn=lambda x: DN(x) == hostgroup_dn1,
+ dn=hostgroup_dn1,
cn=[hostgroup1],
objectclass=objectclasses.hostgroup,
description=[u'Test hostgroup 1'],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',hostgroup1),('cn','ng'),('cn','alt'),
- api.env.basedn)],
+ mepmanagedentry=[DN(('cn',hostgroup1),('cn','ng'),('cn','alt'),
+ api.env.basedn)],
ipauniqueid=[fuzzy_uuid],
),
),
@@ -289,18 +286,15 @@ class test_netgroup(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid',user1),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid',user1),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -328,18 +322,15 @@ class test_netgroup(Declarative):
cn=[u'Test User2'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user2),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid',user2),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid',user2),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -359,9 +350,8 @@ class test_netgroup(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn',group1),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('cn',group1),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -381,9 +371,8 @@ class test_netgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group1),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group1),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': (user2,),
'gidnumber': [fuzzy_digits],
'cn': [group1],
diff --git a/tests/test_xmlrpc/test_permission_plugin.py b/tests/test_xmlrpc/test_permission_plugin.py
index 8aaa4a999..a1062f085 100644
--- a/tests/test_xmlrpc/test_permission_plugin.py
+++ b/tests/test_xmlrpc/test_permission_plugin.py
@@ -25,7 +25,7 @@ Test the `ipalib/plugins/permission.py` module.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
permission1 = u'testperm'
permission1_dn = DN(('cn',permission1),
@@ -110,7 +110,7 @@ class test_permission(Declarative):
value=permission1,
summary=u'Added permission "%s"' % permission1,
result=dict(
- dn=lambda x: DN(x) == permission1_dn,
+ dn=permission1_dn,
cn=[permission1],
objectclass=objectclasses.permission,
type=u'user',
@@ -141,7 +141,7 @@ class test_permission(Declarative):
value=privilege1,
summary=u'Added privilege "%s"' % privilege1,
result=dict(
- dn=lambda x: DN(x) == privilege1_dn,
+ dn=privilege1_dn,
cn=[privilege1],
description=[u'privilege desc. 1'],
objectclass=objectclasses.privilege,
@@ -163,7 +163,7 @@ class test_permission(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1],
@@ -179,7 +179,7 @@ class test_permission(Declarative):
value=permission1,
summary=None,
result={
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
@@ -196,11 +196,12 @@ class test_permission(Declarative):
value=permission1,
summary=None,
result={
- 'dn': unicode(permission1_dn),
+ 'dn': permission1_dn,
'cn': [permission1],
- 'member': [unicode(privilege1_dn)],
- 'aci': u'(target = "ldap:///uid=*,cn=users,cn=accounts,%s")(version 3.0;acl "permission:testperm";allow (write) groupdn = "ldap:///cn=testperm,cn=permissions,cn=pbac,%s";)' \
- % (api.env.basedn, api.env.basedn),
+ 'member': [privilege1_dn],
+ 'aci': u'(target = "ldap:///%s")(version 3.0;acl "permission:testperm";allow (write) groupdn = "ldap:///%s";)' % \
+ (DN(('uid', '*'), ('cn', 'users'), ('cn', 'accounts'), api.env.basedn),
+ DN(('cn', 'testperm'), ('cn', 'permissions'), ('cn', 'pbac'), api.env.basedn))
},
),
),
@@ -215,7 +216,7 @@ class test_permission(Declarative):
summary=u'1 permission matched',
result=[
{
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
@@ -235,7 +236,7 @@ class test_permission(Declarative):
summary=u'1 permission matched',
result=[
{
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
@@ -267,7 +268,7 @@ class test_permission(Declarative):
summary=u'1 permission matched',
result=[
{
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
@@ -287,11 +288,12 @@ class test_permission(Declarative):
summary=u'1 permission matched',
result=[
{
- 'dn': unicode(permission1_dn),
+ 'dn': permission1_dn,
'cn': [permission1],
- 'member': [unicode(privilege1_dn)],
- 'aci': u'(target = "ldap:///uid=*,cn=users,cn=accounts,%s")(version 3.0;acl "permission:testperm";allow (write) groupdn = "ldap:///cn=testperm,cn=permissions,cn=pbac,%s";)' \
- % (api.env.basedn, api.env.basedn),
+ 'member': [privilege1_dn],
+ 'aci': u'(target = "ldap:///%s")(version 3.0;acl "permission:testperm";allow (write) groupdn = "ldap:///%s";)' % \
+ (DN(('uid', '*'), ('cn', 'users'), ('cn', 'accounts'), api.env.basedn),
+ DN(('cn', 'testperm'), ('cn', 'permissions'), ('cn', 'pbac'), api.env.basedn)),
},
],
),
@@ -312,7 +314,7 @@ class test_permission(Declarative):
value=permission2,
summary=u'Added permission "%s"' % permission2,
result=dict(
- dn=lambda x: DN(x) == permission2_dn,
+ dn=permission2_dn,
cn=[permission2],
objectclass=objectclasses.permission,
type=u'user',
@@ -332,14 +334,14 @@ class test_permission(Declarative):
summary=u'2 permissions matched',
result=[
{
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
'permissions': [u'write'],
},
{
- 'dn': lambda x: DN(x) == permission2_dn,
+ 'dn': permission2_dn,
'cn': [permission2],
'type': u'user',
'permissions': [u'write'],
@@ -358,11 +360,11 @@ class test_permission(Declarative):
summary=u'2 permissions matched',
result=[
{
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
},
{
- 'dn': lambda x: DN(x) == permission2_dn,
+ 'dn': permission2_dn,
'cn': [permission2],
},
],
@@ -380,8 +382,8 @@ class test_permission(Declarative):
summary=u'1 permission matched',
result=[
{
- 'dn': lambda x: DN(x) == DN(('cn','Modify Group Password Policy'),
- api.env.container_permission,api.env.basedn),
+ 'dn': DN(('cn','Modify Group Password Policy'),
+ api.env.container_permission, api.env.basedn),
'cn': [u'Modify Group Password Policy'],
},
],
@@ -398,7 +400,7 @@ class test_permission(Declarative):
summary=u'1 privilege matched',
result=[
{
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1],
@@ -417,7 +419,7 @@ class test_permission(Declarative):
summary=u'1 permission matched',
result=[
{
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
@@ -437,14 +439,14 @@ class test_permission(Declarative):
summary=u'2 permissions matched',
result=[
{
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
'permissions': [u'write'],
},
{
- 'dn': lambda x: DN(x) == permission2_dn,
+ 'dn': permission2_dn,
'cn': [permission2],
'type': u'user',
'permissions': [u'write'],
@@ -468,14 +470,14 @@ class test_permission(Declarative):
summary=u'1 permission matched',
result=[
{
- 'dn': lambda x: DN(x) == DN(('cn', 'Modify HBAC rule'),
- api.env.container_permission,api.env.basedn),
+ 'dn': DN(('cn', 'Modify HBAC rule'),
+ api.env.container_permission, api.env.basedn),
'cn': [u'Modify HBAC rule'],
'member_privilege': [u'HBAC Administrator'],
'permissions' : [u'write'],
'attrs': [u'servicecategory', u'sourcehostcategory', u'cn', u'description', u'ipaenabledflag', u'accesstime', u'usercategory', u'hostcategory', u'accessruletype', u'sourcehost'],
- 'subtree' : u'ldap:///ipauniqueid=*,cn=hbac,%s' % api.env.basedn,
- 'memberindirect': [u'cn=hbac administrator,cn=privileges,cn=pbac,%s' % api.env.basedn, u'cn=it security specialist,cn=roles,cn=accounts,%s' % api.env.basedn],
+ 'subtree' : u'ldap:///%s' % DN(('ipauniqueid', '*'), ('cn', 'hbac'), api.env.basedn),
+ 'memberindirect': [DN(('cn', 'it security specialist'), ('cn', 'roles'), ('cn', 'accounts'), api.env.basedn)],
},
],
),
@@ -496,7 +498,7 @@ class test_permission(Declarative):
value=permission1,
summary=u'Modified permission "%s"' % permission1,
result=dict(
- dn=lambda x: DN(x) == permission1_dn,
+ dn=permission1_dn,
cn=[permission1],
member_privilege=[privilege1],
type=u'user',
@@ -515,7 +517,7 @@ class test_permission(Declarative):
value=permission1,
summary=None,
result={
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
@@ -556,7 +558,7 @@ class test_permission(Declarative):
value=permission1,
summary=None,
result={
- 'dn': lambda x: DN(x) == permission1_dn,
+ 'dn': permission1_dn,
'cn': [permission1],
'member_privilege': [privilege1],
'type': u'user',
@@ -578,7 +580,7 @@ class test_permission(Declarative):
value=permission1,
summary=u'Modified permission "%s"' % permission1,
result={
- 'dn': lambda x: DN(x) == permission1_renamed_dn,
+ 'dn': permission1_renamed_dn,
'cn': [permission1_renamed],
'member_privilege': [privilege1],
'type': u'user',
@@ -600,7 +602,7 @@ class test_permission(Declarative):
value=permission1_renamed,
summary=u'Modified permission "%s"' % permission1_renamed,
result={
- 'dn': lambda x: DN(x) == permission1_renamed_ucase_dn,
+ 'dn': permission1_renamed_ucase_dn,
'cn': [permission1_renamed_ucase],
'member_privilege': [privilege1],
'type': u'user',
@@ -614,16 +616,18 @@ class test_permission(Declarative):
dict(
desc='Change %r to a subtree type' % permission1_renamed_ucase,
command=(
- 'permission_mod', [permission1_renamed_ucase], dict(subtree=u'ldap:///cn=*,cn=test,cn=accounts,%s' % api.env.basedn, type=None)
+ 'permission_mod', [permission1_renamed_ucase],
+ dict(subtree=u'ldap:///%s' % DN(('cn', '*'), ('cn', 'test'), ('cn', 'accounts'), api.env.basedn),
+ type=None)
),
expected=dict(
value=permission1_renamed_ucase,
summary=u'Modified permission "%s"' % permission1_renamed_ucase,
result=dict(
- dn=lambda x: DN(x) == permission1_renamed_ucase_dn,
+ dn=permission1_renamed_ucase_dn,
cn=[permission1_renamed_ucase],
member_privilege=[privilege1],
- subtree=u'ldap:///cn=*,cn=test,cn=accounts,%s' % api.env.basedn,
+ subtree=u'ldap:///%s' % DN(('cn', '*'), ('cn', 'test'), ('cn', 'accounts'), api.env.basedn),
permissions=[u'write'],
memberof=u'ipausers',
),
@@ -633,17 +637,18 @@ class test_permission(Declarative):
dict(
desc='Search for %r using --subtree' % permission1,
- command=('permission_find', [], {'subtree': 'ldap:///cn=*,cn=test,cn=accounts,%s' % api.env.basedn}),
+ command=('permission_find', [],
+ {'subtree': u'ldap:///%s' % DN(('cn', '*'), ('cn', 'test'), ('cn', 'accounts'), api.env.basedn)}),
expected=dict(
count=1,
truncated=False,
summary=u'1 permission matched',
result=[
{
- 'dn':lambda x: DN(x) == permission1_renamed_ucase_dn,
+ 'dn':permission1_renamed_ucase_dn,
'cn':[permission1_renamed_ucase],
'member_privilege':[privilege1],
- 'subtree':u'ldap:///cn=*,cn=test,cn=accounts,%s' % api.env.basedn,
+ 'subtree':u'ldap:///%s' % DN(('cn', '*'), ('cn', 'test'), ('cn', 'accounts'), api.env.basedn),
'permissions':[u'write'],
'memberof':u'ipausers',
},
@@ -756,7 +761,7 @@ class test_permission(Declarative):
value=permission1,
summary=u'Added permission "%s"' % permission1,
result=dict(
- dn=lambda x: DN(x) == permission1_dn,
+ dn=permission1_dn,
cn=[permission1],
objectclass=objectclasses.permission,
memberof=u'editors',
@@ -784,7 +789,7 @@ class test_permission(Declarative):
value=permission1,
summary=u'Modified permission "%s"' % permission1,
result=dict(
- dn=lambda x: DN(x) == permission1_dn,
+ dn=permission1_dn,
cn=[permission1],
memberof=u'admins',
permissions=[u'write'],
@@ -804,7 +809,7 @@ class test_permission(Declarative):
summary=u'Modified permission "%s"' % permission1,
value=permission1,
result=dict(
- dn=lambda x: DN(x) == permission1_dn,
+ dn=permission1_dn,
cn=[permission1],
permissions=[u'write'],
type=u'user',
@@ -836,7 +841,7 @@ class test_permission(Declarative):
value=permission1,
summary=u'Added permission "%s"' % permission1,
result=dict(
- dn=lambda x: DN(x) == permission1_dn,
+ dn=permission1_dn,
cn=[permission1],
objectclass=objectclasses.permission,
targetgroup=u'editors',
diff --git a/tests/test_xmlrpc/test_privilege_plugin.py b/tests/test_xmlrpc/test_privilege_plugin.py
index d8d9b22a6..d4784af8c 100644
--- a/tests/test_xmlrpc/test_privilege_plugin.py
+++ b/tests/test_xmlrpc/test_privilege_plugin.py
@@ -24,7 +24,7 @@ Test the `ipalib/plugins/privilege.py` module.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
permission1 = u'testperm'
permission1_dn = DN(('cn',permission1),
@@ -97,7 +97,7 @@ class test_privilege(Declarative):
value=permission1,
summary=u'Added permission "%s"' % permission1,
result=dict(
- dn=lambda x: DN(x) == permission1_dn,
+ dn=permission1_dn,
cn=[permission1],
objectclass=objectclasses.permission,
type=u'user',
@@ -116,7 +116,7 @@ class test_privilege(Declarative):
value=privilege1,
summary=u'Added privilege "%s"' % privilege1,
result=dict(
- dn=lambda x: DN(x) == privilege1_dn,
+ dn=privilege1_dn,
cn=[privilege1],
description=[u'privilege desc. 1'],
objectclass=objectclasses.privilege,
@@ -138,7 +138,7 @@ class test_privilege(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1],
@@ -154,7 +154,7 @@ class test_privilege(Declarative):
value=privilege1,
summary=None,
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1],
@@ -172,7 +172,7 @@ class test_privilege(Declarative):
summary=u'1 privilege matched',
result=[
{
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1],
@@ -191,7 +191,7 @@ class test_privilege(Declarative):
summary=u'1 privilege matched',
result=[
{
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1],
@@ -213,7 +213,7 @@ class test_privilege(Declarative):
value=permission2,
summary=u'Added permission "%s"' % permission2,
result=dict(
- dn=lambda x: DN(x) == permission2_dn,
+ dn=permission2_dn,
cn=[permission2],
objectclass=objectclasses.permission,
type=u'user',
@@ -236,7 +236,7 @@ class test_privilege(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1, permission2],
@@ -258,7 +258,7 @@ class test_privilege(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1, permission2],
@@ -276,7 +276,7 @@ class test_privilege(Declarative):
summary=u'1 privilege matched',
result=[
{
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'privilege desc. 1'],
'memberof_permission': [permission1, permission2],
@@ -316,7 +316,7 @@ class test_privilege(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'New desc 1'],
'memberof_permission': [permission2],
@@ -338,7 +338,7 @@ class test_privilege(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'New desc 1'],
'memberof_permission': [permission2],
@@ -360,7 +360,7 @@ class test_privilege(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'New desc 1'],
'memberof_permission': [permission2],
@@ -382,7 +382,7 @@ class test_privilege(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == privilege1_dn,
+ 'dn': privilege1_dn,
'cn': [privilege1],
'description': [u'New desc 1'],
'memberof_permission': [permission2],
diff --git a/tests/test_xmlrpc/test_range_plugin.py b/tests/test_xmlrpc/test_range_plugin.py
index 76ffc58b7..ea4bc2b2d 100644
--- a/tests/test_xmlrpc/test_range_plugin.py
+++ b/tests/test_xmlrpc/test_range_plugin.py
@@ -24,7 +24,7 @@ Test the `ipalib/plugins/range.py` module, and XML-RPC in general.
from ipalib import api, errors, _
from tests.util import assert_equal, Fuzzy
from xmlrpc_test import Declarative
-from ipalib.dn import *
+from ipapython.dn import *
testrange1 = u't-range-1'
@@ -41,9 +41,8 @@ class test_range(Declarative):
ipabaserid=1000, ipasecondarybaserid=20000)),
expected=dict(
result=dict(
- dn=lambda x: DN(x) == \
- DN(('cn',testrange1),('cn','ranges'),('cn','etc'),
- api.env.basedn),
+ dn=DN(('cn',testrange1),('cn','ranges'),('cn','etc'),
+ api.env.basedn),
cn=[testrange1],
objectclass=[u'ipaIDrange', u'ipadomainidrange'],
ipabaseid=[u'900000'],
@@ -62,9 +61,8 @@ class test_range(Declarative):
command=('range_show', [testrange1], dict()),
expected=dict(
result=dict(
- dn=lambda x: DN(x) == \
- DN(('cn',testrange1),('cn','ranges'),('cn','etc'),
- api.env.basedn),
+ dn=DN(('cn',testrange1),('cn','ranges'),('cn','etc'),
+ api.env.basedn),
cn=[testrange1],
ipabaseid=[u'900000'],
ipabaserid=[u'1000'],
diff --git a/tests/test_xmlrpc/test_replace.py b/tests/test_xmlrpc/test_replace.py
index f5203607c..434f71d70 100644
--- a/tests/test_xmlrpc/test_replace.py
+++ b/tests/test_xmlrpc/test_replace.py
@@ -28,7 +28,7 @@ gen_modlist code.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
user1=u'tuser1'
@@ -66,18 +66,15 @@ class test_replace(Declarative):
initials=[u'TU'],
mail=[u'test1@example.com', u'test2@example.com'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),('cn','kerberos'),
- api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),('cn','kerberos'),
+ api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
diff --git a/tests/test_xmlrpc/test_role_plugin.py b/tests/test_xmlrpc/test_role_plugin.py
index e2bd28cd6..b847ca9eb 100644
--- a/tests/test_xmlrpc/test_role_plugin.py
+++ b/tests/test_xmlrpc/test_role_plugin.py
@@ -25,7 +25,7 @@ Test the `ipalib/plugins/role.py` module.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
search = u'test-role'
@@ -117,7 +117,7 @@ class test_role(Declarative):
value=role1,
summary=u'Added role "%s"' % role1,
result=dict(
- dn=lambda x: DN(x) == role1_dn,
+ dn=role1_dn,
cn=[role1],
description=[u'role desc 1'],
objectclass=objectclasses.role,
@@ -133,7 +133,7 @@ class test_role(Declarative):
value=role1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == role1_dn,
+ dn=role1_dn,
cn=[role1],
description=[u'role desc 1'],
),
@@ -151,7 +151,7 @@ class test_role(Declarative):
value=group1,
summary=u'Added group "testgroup1"',
result=dict(
- dn=lambda x: DN(x) == group1_dn,
+ dn=group1_dn,
cn=[group1],
description=[u'group desc 1'],
objectclass=objectclasses.group,
@@ -170,7 +170,7 @@ class test_role(Declarative):
value=privilege1,
summary=u'Added privilege "%s"' % privilege1,
result=dict(
- dn=lambda x: DN(x) == privilege1_dn,
+ dn=privilege1_dn,
cn=[privilege1],
description=[u'privilege desc. 1'],
objectclass=objectclasses.privilege,
@@ -192,7 +192,7 @@ class test_role(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'memberof_privilege': [privilege1],
@@ -213,7 +213,7 @@ class test_role(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'memberof_privilege': [privilege1],
@@ -234,7 +234,7 @@ class test_role(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'memberof_privilege': [privilege1],
@@ -257,7 +257,7 @@ class test_role(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'member_group': [group1],
@@ -274,7 +274,7 @@ class test_role(Declarative):
value=role1,
summary=None,
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'member_group': [group1],
@@ -293,7 +293,7 @@ class test_role(Declarative):
summary=u'1 role matched',
result=[
{
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'member_group': [group1],
@@ -313,7 +313,7 @@ class test_role(Declarative):
summary=u'1 role matched',
result=[
{
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'member_group': [group1],
@@ -333,7 +333,7 @@ class test_role(Declarative):
value=role2,
summary=u'Added role "%s"' % role2,
result=dict(
- dn=lambda x: DN(x) == role2_dn,
+ dn=role2_dn,
cn=[role2],
description=[u'role desc 2'],
objectclass=objectclasses.role,
@@ -351,7 +351,7 @@ class test_role(Declarative):
summary=u'1 role matched',
result=[
{
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'member_group': [group1],
@@ -371,14 +371,14 @@ class test_role(Declarative):
summary=u'2 roles matched',
result=[
{
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'role desc 1'],
'member_group': [group1],
'memberof_privilege': [privilege1],
},
{
- 'dn': lambda x: DN(x) == role2_dn,
+ 'dn': role2_dn,
'cn': [role2],
'description': [u'role desc 2'],
},
@@ -412,7 +412,7 @@ class test_role(Declarative):
value=role1,
summary=None,
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'New desc 1'],
'member_group': [group1],
@@ -436,7 +436,7 @@ class test_role(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'New desc 1'],
'memberof_privilege': [privilege1],
@@ -452,7 +452,7 @@ class test_role(Declarative):
value=role1,
summary=None,
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'New desc 1'],
'memberof_privilege': [privilege1],
@@ -515,7 +515,7 @@ class test_role(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'New desc 1'],
}
@@ -536,7 +536,7 @@ class test_role(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == role1_dn,
+ 'dn': role1_dn,
'cn': [role1],
'description': [u'New desc 1'],
}
@@ -586,7 +586,7 @@ class test_role(Declarative):
summary=u'1 role matched',
result=[
{
- 'dn': lambda x: DN(x) == role2_dn,
+ 'dn': role2_dn,
'cn': [role2],
'description': [u'role desc 2'],
},
diff --git a/tests/test_xmlrpc/test_selinuxusermap_plugin.py b/tests/test_xmlrpc/test_selinuxusermap_plugin.py
index 2f6f52c6d..c1bee54dc 100644
--- a/tests/test_xmlrpc/test_selinuxusermap_plugin.py
+++ b/tests/test_xmlrpc/test_selinuxusermap_plugin.py
@@ -23,7 +23,7 @@ Test the `ipalib/plugins/selinuxusermap.py` module.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
from tests.util import Fuzzy
rule1 = u'selinuxrule1'
@@ -34,15 +34,16 @@ user1 = u'tuser1'
group1 = u'testgroup1'
host1 = u'testhost1.%s' % api.env.domain
hostdn1 = DN(('fqdn',host1),('cn','computers'),('cn','accounts'),
- api.env.basedn)
+ api.env.basedn)
hbacrule1 = u'testhbacrule1'
hbacrule2 = u'testhbacrule12'
+# Note (?i) at the beginning of the regexp is the ingnore case flag
fuzzy_selinuxusermapdn = Fuzzy(
- 'ipauniqueid=[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12},%s,%s' % (api.env.container_selinux, api.env.basedn)
+ '(?i)ipauniqueid=[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12},%s,%s' % (api.env.container_selinux, api.env.basedn)
)
fuzzy_hbacruledn = Fuzzy(
- 'ipauniqueid=[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12},%s,%s' % (api.env.container_hbac, api.env.basedn)
+ '(?i)ipauniqueid=[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12},%s,%s' % (api.env.container_hbac, api.env.basedn)
)
class test_selinuxusermap(Declarative):
@@ -204,16 +205,13 @@ class test_selinuxusermap(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
- dn=lambda x: DN(x) == \
- DN(('uid',user1),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid',user1),('cn','users'),('cn','accounts'),
+ api.env.basedn),
has_keytab=False,
has_password=False,
),
@@ -234,9 +232,8 @@ class test_selinuxusermap(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn',group1),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('cn',group1),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -256,9 +253,8 @@ class test_selinuxusermap(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',group1),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ 'dn': DN(('cn',group1),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
'member_user': (user1,),
'gidnumber': [fuzzy_digits],
'cn': [group1],
@@ -281,7 +277,7 @@ class test_selinuxusermap(Declarative):
value=host1,
summary=u'Added host "%s"' % host1,
result=dict(
- dn=lambda x: DN(x) == hostdn1,
+ dn=hostdn1,
fqdn=[host1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
diff --git a/tests/test_xmlrpc/test_service_plugin.py b/tests/test_xmlrpc/test_service_plugin.py
index 28c6bb663..e06132fe1 100644
--- a/tests/test_xmlrpc/test_service_plugin.py
+++ b/tests/test_xmlrpc/test_service_plugin.py
@@ -27,7 +27,7 @@ from tests.test_xmlrpc.xmlrpc_test import fuzzy_digits, fuzzy_date, fuzzy_issuer
from tests.test_xmlrpc.xmlrpc_test import fuzzy_hex
from tests.test_xmlrpc import objectclasses
import base64
-from ipalib.dn import *
+from ipapython.dn import DN
fqdn1 = u'testhost1.%s' % api.env.domain
fqdn2 = u'testhost2.%s' % api.env.domain
@@ -93,7 +93,7 @@ class test_service(Declarative):
value=fqdn1,
summary=u'Added host "%s"' % fqdn1,
result=dict(
- dn=lambda x: DN(x) == host1dn,
+ dn=host1dn,
fqdn=[fqdn1],
description=[u'Test host 1'],
l=[u'Undisclosed location 1'],
@@ -121,7 +121,7 @@ class test_service(Declarative):
value=fqdn2,
summary=u'Added host "%s"' % fqdn2,
result=dict(
- dn=lambda x: DN(x) == host2dn,
+ dn=host2dn,
fqdn=[fqdn2],
description=[u'Test host 2'],
l=[u'Undisclosed location 2'],
@@ -149,7 +149,7 @@ class test_service(Declarative):
value=fqdn3.lower(),
summary=u'Added host "%s"' % fqdn3.lower(),
result=dict(
- dn=lambda x: DN(x) == host3dn,
+ dn=host3dn,
fqdn=[fqdn3.lower()],
description=[u'Test host 3'],
l=[u'Undisclosed location 3'],
@@ -175,7 +175,7 @@ class test_service(Declarative):
value=service1,
summary=u'Added service "%s"' % service1,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
objectclass=objectclasses.service,
ipauniqueid=[fuzzy_uuid],
@@ -205,7 +205,7 @@ class test_service(Declarative):
value=service1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
has_keytab=False,
ipakrbauthzdata=[u'MS-PAC'],
@@ -222,7 +222,7 @@ class test_service(Declarative):
value=service1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbprincipalalias=[service1],
objectclass=objectclasses.service,
@@ -244,7 +244,7 @@ class test_service(Declarative):
summary=u'1 service matched',
result=[
dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
managedby_host=[fqdn1],
ipakrbauthzdata=[u'MS-PAC'],
@@ -264,7 +264,7 @@ class test_service(Declarative):
summary=u'1 service matched',
result=[
dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbprincipalalias=[service1],
objectclass=objectclasses.service,
@@ -285,7 +285,7 @@ class test_service(Declarative):
failed=dict(managedby=dict(host=[(u'notfound', u'no such entry')])),
completed=0,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
@@ -301,7 +301,7 @@ class test_service(Declarative):
failed=dict(managedby=dict(host=[(u'notfound', u'This entry is not a member')])),
completed=0,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
@@ -317,7 +317,7 @@ class test_service(Declarative):
failed=dict(managedby=dict(host=[])),
completed=1,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1, fqdn2],
@@ -333,7 +333,7 @@ class test_service(Declarative):
failed=dict(managedby=dict(host=[])),
completed=1,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
@@ -349,7 +349,7 @@ class test_service(Declarative):
failed=dict(managedby=dict(host=[])),
completed=1,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1, fqdn3.lower()],
@@ -365,7 +365,7 @@ class test_service(Declarative):
failed=dict(managedby=dict(host=[])),
completed=1,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
krbprincipalname=[service1],
ipakrbauthzdata=[u'MS-PAC'],
managedby_host=[fqdn1],
@@ -396,8 +396,7 @@ class test_service(Declarative):
managedby_host=[fqdn1],
valid_not_before=fuzzy_date,
valid_not_after=fuzzy_date,
- subject=lambda x: DN(x) == \
- DN(('CN',api.env.host),x509.subject_base()),
+ subject=DN(('CN',api.env.host),x509.subject_base()),
serial_number=fuzzy_digits,
serial_number_hex=fuzzy_hex,
md5_fingerprint=fuzzy_hash,
@@ -415,7 +414,7 @@ class test_service(Declarative):
value=service1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == service1dn,
+ dn=service1dn,
usercertificate=[base64.b64decode(servercert)],
krbprincipalname=[service1],
has_keytab=False,
@@ -425,8 +424,7 @@ class test_service(Declarative):
# test case.
valid_not_before=fuzzy_date,
valid_not_after=fuzzy_date,
- subject=lambda x: DN(x) == \
- DN(('CN',api.env.host),x509.subject_base()),
+ subject=DN(('CN',api.env.host),x509.subject_base()),
serial_number=fuzzy_digits,
serial_number_hex=fuzzy_hex,
md5_fingerprint=fuzzy_hash,
diff --git a/tests/test_xmlrpc/test_sudocmd_plugin.py b/tests/test_xmlrpc/test_sudocmd_plugin.py
index 4574f774c..75b6bbccb 100644
--- a/tests/test_xmlrpc/test_sudocmd_plugin.py
+++ b/tests/test_xmlrpc/test_sudocmd_plugin.py
@@ -24,7 +24,7 @@ Test the `ipalib/plugins/sudocmd.py` module.
from ipalib import api, errors
from tests.test_xmlrpc.xmlrpc_test import Declarative, fuzzy_uuid
from tests.test_xmlrpc import objectclasses
-from ipalib.dn import *
+from ipapython.dn import DN
sudocmd1 = u'/usr/bin/sudotestcmd1'
@@ -72,9 +72,8 @@ class test_sudocmd(Declarative):
value=sudocmd1,
summary=u'Added Sudo Command "%s"' % sudocmd1,
result=dict(
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
- api.env.basedn),
+ dn=DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
+ api.env.basedn),
sudocmd=[sudocmd1],
description=[u'Test sudo command 1'],
objectclass=objectclasses.sudocmd,
@@ -103,9 +102,8 @@ class test_sudocmd(Declarative):
value=sudocmd1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
- api.env.basedn),
+ dn=DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
+ api.env.basedn),
sudocmd=[sudocmd1],
description=[u'Test sudo command 1'],
),
@@ -122,9 +120,8 @@ class test_sudocmd(Declarative):
summary=u'1 Sudo Command matched',
result=[
dict(
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd1),('cn','sudocmds'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('sudocmd',sudocmd1),('cn','sudocmds'),
+ ('cn','sudo'),api.env.basedn),
sudocmd=[sudocmd1],
description=[u'Test sudo command 1'],
),
@@ -155,9 +152,8 @@ class test_sudocmd(Declarative):
value=sudocmd1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
- api.env.basedn),
+ dn=DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
+ api.env.basedn),
sudocmd=[sudocmd1],
description=[u'Updated sudo command 1'],
),
diff --git a/tests/test_xmlrpc/test_sudocmdgroup_plugin.py b/tests/test_xmlrpc/test_sudocmdgroup_plugin.py
index 2bfbb6259..b8c15737d 100644
--- a/tests/test_xmlrpc/test_sudocmdgroup_plugin.py
+++ b/tests/test_xmlrpc/test_sudocmdgroup_plugin.py
@@ -23,7 +23,7 @@ Test the `ipalib/plugins/sudocmdgroup.py` module.
from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid
-from ipalib.dn import *
+from ipapython.dn import DN
sudocmdgroup1 = u'testsudocmdgroup1'
sudocmdgroup2 = u'testsudocmdgroup2'
@@ -45,9 +45,8 @@ def create_command(sudocmd):
sudocmd=[sudocmd],
ipauniqueid=[fuzzy_uuid],
description=[u'Test sudo command'],
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd),('cn','sudocmds'),('cn','sudo'),
- api.env.basedn),
+ dn=DN(('sudocmd',sudocmd),('cn','sudocmds'),('cn','sudo'),
+ api.env.basedn),
),
),
)
@@ -77,9 +76,8 @@ class test_sudocmdgroup(Declarative):
sudocmd=[u'/usr/bin/sudotestcmd1'],
ipauniqueid=[fuzzy_uuid],
description=[u'Test sudo command 1'],
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
- api.env.basedn),
+ dn=DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
+ api.env.basedn),
),
),
),
@@ -94,9 +92,8 @@ class test_sudocmdgroup(Declarative):
result=dict(
sudocmd=[sudocmd1],
description=[u'Test sudo command 1'],
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
- api.env.basedn),
+ dn=DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
+ api.env.basedn),
),
),
),
@@ -143,9 +140,8 @@ class test_sudocmdgroup(Declarative):
description=[u'Test desc 1'],
objectclass=objectclasses.sudocmdgroup,
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn','testsudocmdgroup1'),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn','testsudocmdgroup1'),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
),
),
),
@@ -171,9 +167,8 @@ class test_sudocmdgroup(Declarative):
result=dict(
cn=[sudocmdgroup1],
description=[u'Test desc 1'],
- dn=lambda x: DN(x) == \
- DN(('cn','testsudocmdgroup1'),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn','testsudocmdgroup1'),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
),
),
),
@@ -204,9 +199,8 @@ class test_sudocmdgroup(Declarative):
result=dict(
cn=[sudocmdgroup1],
description=[u'New desc 1'],
- dn=lambda x: DN(x) == \
- DN(('cn','testsudocmdgroup1'),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn','testsudocmdgroup1'),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
),
summary=None,
),
@@ -221,9 +215,8 @@ class test_sudocmdgroup(Declarative):
truncated=False,
result=[
dict(
- dn=lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
cn=[sudocmdgroup1],
description=[u'New desc 1'],
),
@@ -275,9 +268,8 @@ class test_sudocmdgroup(Declarative):
description=[u'Test desc 2'],
objectclass=objectclasses.sudocmdgroup,
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn','testsudocmdgroup2'),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn','testsudocmdgroup2'),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
),
),
),
@@ -304,9 +296,8 @@ class test_sudocmdgroup(Declarative):
result=dict(
cn=[sudocmdgroup2],
description=[u'Test desc 2'],
- dn=lambda x: DN(x) == \
- DN(('cn','testsudocmdgroup2'),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn','testsudocmdgroup2'),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
),
),
),
@@ -337,9 +328,8 @@ class test_sudocmdgroup(Declarative):
result=dict(
cn=[sudocmdgroup2],
description=[u'New desc 2'],
- dn=lambda x: DN(x) == \
- DN(('cn','testsudocmdgroup2'),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn','testsudocmdgroup2'),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
),
summary=None,
),
@@ -354,9 +344,8 @@ class test_sudocmdgroup(Declarative):
truncated=False,
result=[
dict(
- dn=lambda x: DN(x) == \
- DN(('cn',sudocmdgroup2),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn',sudocmdgroup2),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
cn=[sudocmdgroup2],
description=[u'New desc 2'],
),
@@ -375,16 +364,14 @@ class test_sudocmdgroup(Declarative):
truncated=False,
result=[
dict(
- dn=lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
cn=[sudocmdgroup1],
description=[u'New desc 1'],
),
dict(
- dn=lambda x: DN(x) == \
- DN(('cn',sudocmdgroup2),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ dn=DN(('cn',sudocmdgroup2),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
cn=[sudocmdgroup2],
description=[u'New desc 2'],
),
@@ -410,9 +397,8 @@ class test_sudocmdgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ 'dn': DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
'member_sudocmd': (sudocmd1,),
'cn': [sudocmdgroup1],
'description': [u'New desc 1'],
@@ -427,9 +413,8 @@ class test_sudocmdgroup(Declarative):
value=sudocmd1,
summary=None,
result=dict(
- dn=lambda x: DN(x) == \
- DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
- api.env.basedn),
+ dn=DN(('sudocmd',sudocmd1),('cn','sudocmds'),('cn','sudo'),
+ api.env.basedn),
sudocmd=[sudocmd1],
description=[u'Test sudo command 1'],
memberof_sudocmdgroup = [u'testsudocmdgroup1'],
@@ -451,9 +436,8 @@ class test_sudocmdgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ 'dn': DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
'member_sudocmd': (u'/usr/bin/sudotestcmd1',),
'cn': [sudocmdgroup1],
'description': [u'New desc 1'],
@@ -474,9 +458,8 @@ class test_sudocmdgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ 'dn': DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
'cn': [sudocmdgroup1],
'description': [u'New desc 1'],
},
@@ -497,9 +480,8 @@ class test_sudocmdgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ 'dn': DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
'cn': [sudocmdgroup1],
'description': [u'New desc 1'],
},
@@ -523,9 +505,8 @@ class test_sudocmdgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ 'dn': DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
'member_sudocmd': (sudocmd_plus,),
'cn': [sudocmdgroup1],
'description': [u'New desc 1'],
@@ -546,9 +527,8 @@ class test_sudocmdgroup(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
- ('cn','sudo'),api.env.basedn),
+ 'dn': DN(('cn',sudocmdgroup1),('cn','sudocmdgroups'),
+ ('cn','sudo'),api.env.basedn),
'cn': [sudocmdgroup1],
'description': [u'New desc 1'],
},
diff --git a/tests/test_xmlrpc/test_user_plugin.py b/tests/test_xmlrpc/test_user_plugin.py
index b257a90a3..4a4c69c19 100644
--- a/tests/test_xmlrpc/test_user_plugin.py
+++ b/tests/test_xmlrpc/test_user_plugin.py
@@ -27,7 +27,7 @@ from ipalib import api, errors
from tests.test_xmlrpc import objectclasses
from tests.util import assert_equal, assert_not_equal
from xmlrpc_test import Declarative, fuzzy_digits, fuzzy_uuid, fuzzy_password, fuzzy_string, fuzzy_dergeneralizedtime
-from ipalib.dn import *
+from ipapython.dn import DN
user1=u'tuser1'
user2=u'tuser2'
@@ -52,7 +52,7 @@ def not_upg_check(response):
class test_user(Declarative):
cleanup_commands = [
- ('user_del', [user1, user2], {}),
+ ('user_del', [user1, user2, renameduser1], {}),
('group_del', [group1], {}),
]
@@ -81,7 +81,7 @@ class test_user(Declarative):
dict(
desc='Try to rename non-existent %r' % user1,
- command=('user_mod', [user1], dict(setattr=u'uid=tuser')),
+ command=('user_mod', [user1], dict(setattr=u'uid=%s' % renameduser1)),
expected=errors.NotFound(reason=u'%s: user not found' % user1),
),
@@ -109,18 +109,15 @@ class test_user(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
extra_check = upg_check,
@@ -144,9 +141,8 @@ class test_user(Declarative):
),
expected=dict(
result=dict(
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
givenname=[u'Test'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
@@ -173,9 +169,8 @@ class test_user(Declarative):
expected=dict(
result=[
{
- 'dn': lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),
- ('cn','accounts'),api.env.basedn),
+ 'dn': DN(('uid','tuser1'),('cn','users'),
+ ('cn','accounts'),api.env.basedn),
'cn': [u'Test User1'],
'gecos': [u'Test User1'],
'givenname': [u'Test'],
@@ -189,12 +184,10 @@ class test_user(Declarative):
'uidnumber': [fuzzy_digits],
'gidnumber': [fuzzy_digits],
'ipauniqueid': [fuzzy_uuid],
- 'mepmanagedentry': lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
- 'krbpwdpolicyreference': lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
+ 'mepmanagedentry': [DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
+ 'krbpwdpolicyreference': [DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
'nsaccountlock': False,
'has_keytab': False,
'has_password': False,
@@ -217,9 +210,8 @@ class test_user(Declarative):
expected=dict(
result=[
{
- 'dn':lambda x: DN(x) == \
- DN(('uid',user1),('cn','users'),
- ('cn','accounts'),api.env.basedn),
+ 'dn':DN(('uid',user1),('cn','users'),
+ ('cn','accounts'),api.env.basedn),
'uid': [user1],
},
],
@@ -237,9 +229,8 @@ class test_user(Declarative):
expected=dict(
result=[
dict(
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),
+ ('cn','accounts'),api.env.basedn),
givenname=[u'Test'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
@@ -267,9 +258,8 @@ class test_user(Declarative):
expected=dict(
result=[
dict(
- dn=lambda x: DN(x) == \
- DN(('uid','admin'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','admin'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
homedirectory=[u'/home/admin'],
loginshell=[u'/bin/bash'],
sn=[u'Administrator'],
@@ -281,9 +271,8 @@ class test_user(Declarative):
gidnumber=[fuzzy_digits],
),
dict(
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),
- ('cn','accounts'),api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),
+ ('cn','accounts'),api.env.basedn),
givenname=[u'Test'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
@@ -311,9 +300,8 @@ class test_user(Declarative):
expected=dict(
result=[
dict(
- dn=lambda x: DN(x) == \
- DN(('uid','admin'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','admin'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
homedirectory=[u'/home/admin'],
loginshell=[u'/bin/bash'],
sn=[u'Administrator'],
@@ -465,9 +453,8 @@ class test_user(Declarative):
command=('user_show', [user1], {}),
expected=dict(
result=dict(
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
givenname=[u'Finkle'],
homedirectory=[u'/home/tuser1'],
loginshell=[u'/bin/sh'],
@@ -591,18 +578,15 @@ class test_user(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
extra_check = upg_check,
@@ -632,18 +616,15 @@ class test_user(Declarative):
cn=[u'Test User2'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user2),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
extra_check = upg_check,
@@ -783,9 +764,8 @@ class test_user(Declarative):
gidnumber=[fuzzy_digits],
objectclass=objectclasses.group + [u'posixgroup'],
ipauniqueid=[fuzzy_uuid],
- dn=lambda x: DN(x) == \
- DN(('cn',group1),('cn','groups'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('cn',group1),('cn','groups'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -830,18 +810,15 @@ class test_user(Declarative):
postalcode=[u'01234-5678'],
telephonenumber=[u'410-555-1212'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -880,12 +857,10 @@ class test_user(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=True,
has_password=True,
@@ -893,9 +868,8 @@ class test_user(Declarative):
krbextradata=[fuzzy_string],
krbpasswordexpiration=[fuzzy_dergeneralizedtime],
krblastpwdchange=[fuzzy_dergeneralizedtime],
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -933,18 +907,15 @@ class test_user(Declarative):
cn=[u'Test User2'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user2),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user2),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -1008,18 +979,15 @@ class test_user(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -1085,18 +1053,15 @@ class test_user(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -1151,18 +1116,15 @@ class test_user(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
- mepmanagedentry=lambda x: [DN(i) for i in x] == \
- [DN(('cn',user1),('cn','groups'),('cn','accounts'),
- api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
+ mepmanagedentry=[DN(('cn',user1),('cn','groups'),('cn','accounts'),
+ api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -1217,15 +1179,13 @@ class test_user(Declarative):
cn=[u'Test User2'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
memberof_group=[u'ipausers'],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -1272,15 +1232,13 @@ class test_user(Declarative):
cn=[u'Test User1'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
memberof_group=[group1],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser1'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
extra_check = not_upg_check,
@@ -1310,15 +1268,13 @@ class test_user(Declarative):
cn=[u'Test User2'],
initials=[u'TU'],
ipauniqueid=[fuzzy_uuid],
- krbpwdpolicyreference=lambda x: [DN(i) for i in x] == \
- [DN(('cn','global_policy'),('cn',api.env.realm),
- ('cn','kerberos'),api.env.basedn)],
+ krbpwdpolicyreference=[DN(('cn','global_policy'),('cn',api.env.realm),
+ ('cn','kerberos'),api.env.basedn)],
memberof_group=[group1],
has_keytab=False,
has_password=False,
- dn=lambda x: DN(x) == \
- DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
- api.env.basedn),
+ dn=DN(('uid','tuser2'),('cn','users'),('cn','accounts'),
+ api.env.basedn),
),
),
),
@@ -1350,9 +1306,8 @@ class test_user(Declarative):
),
),
result={
- 'dn': lambda x: DN(x) == \
- DN(('cn', 'admins'), ('cn', 'groups'),
- ('cn', 'accounts'), api.env.basedn),
+ 'dn': DN(('cn', 'admins'), ('cn', 'groups'),
+ ('cn', 'accounts'), api.env.basedn),
'member_user': [u'admin', user2],
'gidnumber': [fuzzy_digits],
'cn': [u'admins'],
diff --git a/tests/test_xmlrpc/xmlrpc_test.py b/tests/test_xmlrpc/xmlrpc_test.py
index cfba35fc5..7c32be0db 100644
--- a/tests/test_xmlrpc/xmlrpc_test.py
+++ b/tests/test_xmlrpc/xmlrpc_test.py
@@ -40,9 +40,9 @@ fuzzy_uuid = Fuzzy(
'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'
)
-# Matches netgroup dn
+# Matches netgroup dn. Note (?i) at the beginning of the regexp is the ingnore case flag
fuzzy_netgroupdn = Fuzzy(
- 'ipauniqueid=[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12},cn=ng,cn=alt,%s' % api.env.basedn
+ '(?i)ipauniqueid=[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12},cn=ng,cn=alt,%s' % api.env.basedn
)
# Matches a hash signature, not enforcing length
diff --git a/tests/util.py b/tests/util.py
index 54a8dd14f..ed62a223a 100644
--- a/tests/util.py
+++ b/tests/util.py
@@ -30,6 +30,7 @@ import re
import ipalib
from ipalib.plugable import Plugin
from ipalib.request import context
+from ipapython.dn import DN
class TempDir(object):
def __init__(self):
@@ -303,6 +304,9 @@ def assert_deepequal(expected, got, doc='', stack=tuple()):
expected = list(expected)
if isinstance(got, tuple):
got = list(got)
+ if isinstance(expected, DN):
+ if isinstance(got, basestring):
+ got = DN(got)
if not (isinstance(expected, Fuzzy) or callable(expected) or type(expected) is type(got)):
raise AssertionError(
TYPE % (doc, type(expected), type(got), expected, got, stack)