Skip to content

Commit 0f83de6

Browse files
committed
WIP on #278
Would be nice if result4 returned the operation result as well (but for that we'd need to expose the result codes too, at the moment all of them are just exceptions that can't even be converted to ints).
1 parent 334186a commit 0f83de6

File tree

8 files changed

+87
-13
lines changed

8 files changed

+87
-13
lines changed

Lib/ldap/functions.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import sys,pprint,time,_ldap,ldap
1818
from calendar import timegm
1919

20-
from ldap import LDAPError
20+
from ldap import LDAPError, RAISE_ALL
2121

2222
from ldap.dn import explode_dn,explode_rdn
2323

@@ -67,7 +67,7 @@ def _ldap_function_call(lock,func,*args,**kwargs):
6767

6868
def initialize(
6969
uri, trace_level=0, trace_file=sys.stdout, trace_stack_limit=None,
70-
bytes_mode=None, **kwargs
70+
bytes_mode=None, raise_for_result=RAISE_ALL, **kwargs
7171
):
7272
"""
7373
Return LDAPObject instance by opening LDAP connection to
@@ -89,7 +89,8 @@ def initialize(
8989
passed to ``LDAPObject``.
9090
"""
9191
return LDAPObject(
92-
uri, trace_level, trace_file, trace_stack_limit, bytes_mode, **kwargs)
92+
uri, trace_level, trace_file, trace_stack_limit, bytes_mode,
93+
raise_for_result, **kwargs)
9394

9495

9596
def get_option(option):

Lib/ldap/ldapobject.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
from ldap.extop import ExtendedRequest,ExtendedResponse
3131
from ldap.compat import reraise
3232

33-
from ldap import LDAPError
33+
from ldap import LDAPError, RAISE_ALL
3434

3535
PY2 = sys.version_info[0] <= 2
3636
if PY2:
@@ -96,14 +96,14 @@ class SimpleLDAPObject:
9696
def __init__(
9797
self,uri,
9898
trace_level=0,trace_file=None,trace_stack_limit=5,bytes_mode=None,
99-
bytes_strictness=None,
99+
bytes_strictness=None,raise_for_result=RAISE_ALL,
100100
):
101101
self._trace_level = trace_level or ldap._trace_level
102102
self._trace_file = trace_file or ldap._trace_file
103103
self._trace_stack_limit = trace_stack_limit
104104
self._uri = uri
105105
self._ldap_object_lock = self._ldap_lock('opcall')
106-
self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri)
106+
self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri,raise_for_result)
107107
self.timeout = -1
108108
self.protocol_version = ldap.VERSION3
109109

Modules/LDAPObject.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ static void free_attrs(char ***);
2121
/* constructor */
2222

2323
LDAPObject *
24-
newLDAPObject(LDAP *l)
24+
newLDAPObject(LDAP *l, int raise_for_result)
2525
{
2626
LDAPObject *self = (LDAPObject *)PyObject_NEW(LDAPObject, &LDAP_Type);
2727

@@ -30,6 +30,7 @@ newLDAPObject(LDAP *l)
3030
self->ldap = l;
3131
self->_save = NULL;
3232
self->valid = 1;
33+
self->raise_for_result = raise_for_result;
3334
return self;
3435
}
3536

@@ -1086,6 +1087,7 @@ l_ldap_result4(LDAPObject *self, PyObject *args)
10861087
char *retoid = 0;
10871088
PyObject *valuestr = NULL;
10881089
int result = LDAP_SUCCESS;
1090+
int should_raise = 0;
10891091
LDAPControl **serverctrls = 0;
10901092

10911093
if (!PyArg_ParseTuple
@@ -1161,7 +1163,21 @@ l_ldap_result4(LDAPObject *self, PyObject *args)
11611163
LDAP_END_ALLOW_THREADS(self);
11621164
}
11631165

1164-
if (result != LDAP_SUCCESS) { /* result error */
1166+
switch (result) {
1167+
case LDAP_SUCCESS:
1168+
should_raise = 0;
1169+
break;
1170+
case LDAP_COMPARE_FALSE:
1171+
case LDAP_COMPARE_TRUE:
1172+
case LDAP_REFERRAL:
1173+
case LDAP_SASL_BIND_IN_PROGRESS:
1174+
if ( self->raise_for_result <= RAISE_ON_ERROR ) break;
1175+
/* Fallthrough */
1176+
default:
1177+
should_raise = self->raise_for_result > DONT_RAISE;
1178+
break;
1179+
}
1180+
if (should_raise) {
11651181
ldap_controls_free(serverctrls);
11661182
Py_XDECREF(valuestr);
11671183
return LDAPerror(self->ldap, "ldap_parse_result", msg);

Modules/LDAPObject.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,14 @@ typedef struct {
2121
PyObject_HEAD LDAP *ldap;
2222
_threadstate _save; /* for thread saving on referrals */
2323
int valid;
24+
int raise_for_result;
2425
} LDAPObject;
2526

2627
extern PyTypeObject LDAP_Type;
2728

2829
#define LDAPObject_Check(v) (Py_TYPE(v) == &LDAP_Type)
2930

30-
extern LDAPObject *newLDAPObject(LDAP *);
31+
extern LDAPObject *newLDAPObject(LDAP *, int);
3132

3233
/* macros to allow thread saving in the context of an LDAP connection */
3334

Modules/constants.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,13 @@ LDAPinit_constants(PyObject *m)
196196
if (PyModule_AddIntConstant(m, "OPT_OFF", 0) != 0)
197197
return -1;
198198

199+
if (PyModule_AddIntMacro(m, DONT_RAISE) != 0)
200+
return -1;
201+
if (PyModule_AddIntMacro(m, RAISE_ON_ERROR) != 0)
202+
return -1;
203+
if (PyModule_AddIntMacro(m, RAISE_ALL) != 0)
204+
return -1;
205+
199206
/* exceptions */
200207

201208
LDAPexception_class = PyErr_NewException("ldap.LDAPError", NULL, NULL);

Modules/constants.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ PyObject *LDAPerr(int errnum);
2222
#define LDAP_CONTROL_VALUESRETURNFILTER "1.2.826.0.1.3344810.2.3" /* RFC 3876 */
2323
#endif /* !LDAP_CONTROL_VALUESRETURNFILTER */
2424

25+
#define DONT_RAISE 0
26+
#define RAISE_ON_ERROR 1
27+
#define RAISE_ALL 2
28+
2529
#endif /* __h_constants_ */

Modules/functions.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,17 @@ static PyObject *
1313
l_ldap_initialize(PyObject *unused, PyObject *args)
1414
{
1515
char *uri;
16+
int raise_for_result = RAISE_ALL;
1617
LDAP *ld = NULL;
1718
int ret;
1819

19-
if (!PyArg_ParseTuple(args, "s:initialize", &uri))
20+
if (!PyArg_ParseTuple(args, "s|i:initialize", &uri, &raise_for_result))
2021
return NULL;
2122

2223
Py_BEGIN_ALLOW_THREADS ret = ldap_initialize(&ld, uri);
2324
Py_END_ALLOW_THREADS if (ret != LDAP_SUCCESS)
2425
return LDAPerror(ld, "ldap_initialize", NULL);
25-
return (PyObject *)newLDAPObject(ld);
26+
return (PyObject *)newLDAPObject(ld, raise_for_result);
2627
}
2728

2829
/* ldap_str2dn */

Tests/t_cext.py

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ def writesuffix(self):
8686
)
8787
return self._writesuffix
8888

89-
def _open_conn(self, bind=True):
89+
def _open_conn(self, bind=True, raise_for_result=_ldap.RAISE_ALL):
9090
"""
9191
Starts a server, and returns a LDAPObject bound to it
9292
"""
93-
l = _ldap.initialize(self.server.ldap_uri)
93+
l = _ldap.initialize(self.server.ldap_uri, raise_for_result)
9494
if bind:
9595
# Perform a simple bind
9696
l.set_option(_ldap.OPT_PROTOCOL_VERSION, _ldap.VERSION3)
@@ -412,6 +412,50 @@ def test_compare(self):
412412
else:
413413
self.fail("expected LDAPError, got %r" % r)
414414

415+
def test_compare_noraise(self):
416+
"""
417+
test compare operation
418+
"""
419+
l = self._open_conn(raise_for_result=_ldap.RAISE_ON_ERROR)
420+
# first, add an object with a field we can compare on
421+
dn = "cn=CompareTest," + self.writesuffix
422+
m = l.add_ext(
423+
dn,
424+
[
425+
('objectClass', b'person'),
426+
('sn', b'CompareTest'),
427+
('cn', b'CompareTest'),
428+
('userPassword', b'the_password'),
429+
],
430+
)
431+
self.assertEqual(type(m), type(0))
432+
result, pmsg, msgid, ctrls = l.result4(m, _ldap.MSG_ALL, self.timeout)
433+
self.assertEqual(result, _ldap.RES_ADD)
434+
# try a false compare
435+
m = l.compare_ext(dn, "userPassword", "bad_string")
436+
result, pmsg, msgid, ctrls = l.result4(m, _ldap.MSG_ALL, self.timeout)
437+
self.assertEqual(result, _ldap.RES_COMPARE)
438+
self.assertEqual(msgid, m)
439+
self.assertEqual(pmsg, [])
440+
self.assertEqual(ctrls, [])
441+
# try a true compare
442+
m = l.compare_ext(dn, "userPassword", "the_password")
443+
result, pmsg, msgid, ctrls = l.result4(m, _ldap.MSG_ALL, self.timeout)
444+
self.assertEqual(result, _ldap.RES_COMPARE)
445+
self.assertEqual(msgid, m)
446+
self.assertEqual(pmsg, [])
447+
self.assertEqual(ctrls, [])
448+
# try a compare on bad attribute
449+
m = l.compare_ext(dn, "badAttribute", "ignoreme")
450+
try:
451+
r = l.result4(m, _ldap.MSG_ALL, self.timeout)
452+
except _ldap.error as e:
453+
self.assertEqual(e.args[0]['msgid'], m)
454+
self.assertEqual(e.args[0]['msgtype'], _ldap.RES_COMPARE)
455+
self.assertEqual(e.args[0]['result'], 17)
456+
else:
457+
self.fail("expected LDAPError, got %r" % r)
458+
415459
def test_delete_no_such_object(self):
416460
"""
417461
try deleting an object that doesn't exist

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy