LDAP-groups problem

88 views
Skip to first unread message

Wayne

unread,
Dec 17, 2009, 7:32:33 PM12/17/09
to Django users
Hi,

I tried to use djando-ldap-groups but got some errors from database
configuration. Could somebody shed some light on the possible problems
of my set up?

Thanks,

Our LDAP server is Sun One Server and the site is running in the
windows environment.

The settings.py file:
LDAP_SERVER = 'directory.XXX.xx'

# If using SSL use these:
LDAP_PORT = 636
LDAP_URL = 'ldaps://xxx.xxx:636'
SEARCH_DN = 'ou=people,dc=xxxxx,dc=xxxxx'
SEARCH_FIELDS = ['sn','cn','uid']
BIND_USER = 'xxxxxxxx'
sBIND_PASSWORD = 'xxxxxxxxxxxxxxxxxx'


AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
) .

The error message came from command: python manage.py syncdb
Creating table ldap_groups_ldapgroup
Traceback (most recent call last):
File "manage.py", line 11, in <module>
execute_manager(settings)
File "C:\Python26\lib\site-packages\django\core\management
\__init__.py", line
362, in execute_manager
utility.execute()
File "C:\Python26\lib\site-packages\django\core\management
\__init__.py", line
303, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\Python26\lib\site-packages\django\core\management\base.py",
line 195,
in run_from_argv
self.execute(*args, **options.__dict__)
File "C:\Python26\lib\site-packages\django\core\management\base.py",
line 222,
in execute
output = self.handle(*args, **options)
File "C:\Python26\lib\site-packages\django\core\management\base.py",
line 351,
in handle
return self.handle_noargs(**options)
File "C:\Python26\lib\site-packages\django\core\management\commands
\syncdb.py"
, line 78, in handle_noargs
cursor.execute(statement)
File "C:\Python26\lib\site-packages\django\db\backends\util.py",
line 19, in e
xecute
return self.cursor.execute(sql, params)
File "C:\Python26\lib\site-packages\django\db\backends\oracle
\base.py", line 4
34, in execute
raise e
cx_Oracle.DatabaseError: ORA-02329: column of datatype LOB cannot be
unique or a
primary key


Mike Dewhirst

unread,
Dec 17, 2009, 8:19:04 PM12/17/09
to django...@googlegroups.com
Wayne wrote:
> Hi,
>
> I tried to use djando-ldap-groups but got some errors from database
> configuration. Could somebody shed some light on the possible problems
> of my set up?
>

<snip>

Maybe the Oracle API is translating the PK into a LOB? If LOB is a large
object then that is probably the issue.

I can say there is no problem with that particular app with PostgreSQL.

> cx_Oracle.DatabaseError: ORA-02329: column of datatype LOB cannot be
> unique or a
> primary key
>
>

> --
>
> You received this message because you are subscribed to the Google Groups "Django users" group.
> To post to this group, send email to django...@googlegroups.com.
> To unsubscribe from this group, send email to django-users...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/django-users?hl=en.
>
>
>
>

Peter Herndon

unread,
Dec 18, 2009, 10:15:17 AM12/18/09
to django...@googlegroups.com

On Dec 17, 2009, at 7:32 PM, Wayne wrote:

> Hi,

Hi Wayne,

>
> I tried to use djando-ldap-groups but got some errors from database
> configuration. Could somebody shed some light on the possible problems
> of my set up?

Hmm, I think I found the problem below.


>
> Our LDAP server is Sun One Server and the site is running in the
> windows environment.

Aside: If you get all this running properly, please let me know, I've not tried it with Sun One and would be glad to know that it works with that particular LDAP server.

> AUTHENTICATION_BACKENDS = (
> 'django.contrib.auth.backends.ModelBackend',
> ) .

You will need to add one of the LDAP backends to this setting. The eDirectory backend is pretty generic, and will be a better bet than the ActiveDirectory backend. That's not the problem you are having, but is something you'll need to handle shortly.


>
> The error message came from command: python manage.py syncdb
> Creating table ldap_groups_ldapgroup
> Traceback (most recent call last):
>

[snip]


> cx_Oracle.DatabaseError: ORA-02329: column of datatype LOB cannot be
> unique or a
> primary key
>

In ldap_groups/models.py, the LDAPGroup.org_unit field is a TextField, and is marked unique=True. I'm thinking that the cx_Oracle backend is translating the TextField into a Large Object (LOB) field in Oracle, and Oracle cannot ensure uniqueness of a Large Object. In short, remove the "unique=True" from the ldap-groups code and try again. It should work after that.

This error arises from an inconsistency between the behavior of Oracle and the behavior of PostgreSQL, as Mike noted. It works under Postgres. I'll check with the dev list and see if this behavior difference is known, and whether the fix is to never use unique=True on a TextField (a bug in my code), or something that needs to be smoothed over in the SQL generation for Oracle specifically (a bug in the underlying Django behavior).

Let me know if you have further questions, I'm happy to assist.

Regards,

---Peter Herndon

Peter Herndon

unread,
Dec 18, 2009, 10:26:22 AM12/18/09
to Peter Herndon, django...@googlegroups.com

On Dec 18, 2009, at 10:15 AM, Peter Herndon wrote:

>
> On Dec 17, 2009, at 7:32 PM, Wayne wrote:
>
>> Hi,
>

> This error arises from an inconsistency between the behavior of Oracle and the behavior of PostgreSQL, as Mike noted. It works under Postgres. I'll check with the dev list and see if this behavior difference is known, and whether the fix is to never use unique=True on a TextField (a bug in my code), or something that needs to be smoothed over in the SQL generation for Oracle specifically (a bug in the underlying Django behavior).
>

Hi Wayne,

Can you tell me the Django version, the version of cx_Oracle, and the Oracle version? If this has been fixed for certain versions, that would make this error a moot point. And the developers are certainly going to ask. :)

Thanks,

---Peter

Wayne

unread,
Dec 18, 2009, 11:47:37 AM12/18/09
to Django users
Hi,

Sorry for the late reply. Here is more info.

Django Verstion: 1.1
Oracle Version:Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit
Production
cx_oracle for Python 2.6.

Thanks for the help.

Wayne

Peter Herndon

unread,
Dec 19, 2009, 9:31:30 PM12/19/09
to Peter Herndon, django...@googlegroups.com

On Dec 18, 2009, at 10:15 AM, Peter Herndon wrote:

>>
>> The error message came from command: python manage.py syncdb
>> Creating table ldap_groups_ldapgroup
>> Traceback (most recent call last):
>>
> [snip]
>> cx_Oracle.DatabaseError: ORA-02329: column of datatype LOB cannot be
>> unique or a
>> primary key
>>
>
> In ldap_groups/models.py, the LDAPGroup.org_unit field is a TextField, and is marked unique=True. I'm thinking that the cx_Oracle backend is translating the TextField into a Large Object (LOB) field in Oracle, and Oracle cannot ensure uniqueness of a Large Object. In short, remove the "unique=True" from the ldap-groups code and try again. It should work after that.
>
> This error arises from an inconsistency between the behavior of Oracle and the behavior of PostgreSQL, as Mike noted. It works under Postgres. I'll check with the dev list and see if this behavior difference is known, and whether the fix is to never use unique=True on a TextField (a bug in my code), or something that needs to be smoothed over in the SQL generation for Oracle specifically (a bug in the underlying Django behavior).
>

Hi Wayne,

The limitation is known, there's a note in the Oracle backend mentioning that TextFields do not support indexes, which includes unique constraints. For your use, just remove the unique=True from the model definition and run syncdb again.

Regards,

---Peter

Wayne

unread,
Dec 22, 2009, 10:40:45 AM12/22/09
to Django users
Thanks for the prompt reply. Yes, unique=True was the problem. Now I
passed the "run syncdb" and new tables were created. However, I still
could not "contact LDAP". Could somebody help me with this? There
could be many reasons so I want to start with loggings for Django-LDAP-
Groups.

Thanks!

My settings:

LDAP_SERVER = 'directory.XXXXX'

# If using SSL use these:
LDAP_PORT = 636

LDAP_URL = 'ldaps://XXXXXXXX:636'
SEARCH_DN = 'XXXXXXXX'


SEARCH_FIELDS = ['sn','cn','uid']

BIND_USER = 'XXXXXXXXXX'
BIND_PASSWORD = 'XXXXXXXXX'
CERT_FILE = 'XXXXXXXXXX'

AUTHENTICATION_BACKENDS = (
'ldap_groups.accounts.backends.eDirectoryGroupMembershipSSLBackend',
'django.contrib.auth.backends.ModelBackend',
)

The traceback:
Environment:

Request Method: POST
Request URL: http://localhost:8080/admin/
Django Version: 1.1
Python Version: 2.6.2
Installed Applications:
['ldap_groups',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'DjangoTests.TestAdmin']
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware')


Traceback:
File "C:\Python26\lib\site-packages\django\core\handlers\base.py" in
get_response
92. response = callback(request, *callback_args,
**callback_kwargs)
File "C:\Python26\lib\site-packages\django\contrib\admin\sites.py" in
wrapper
196. return self.admin_view(view, cacheable)(*args,
**kwargs)
File "C:\Python26\lib\site-packages\django\views\decorators\cache.py"
in _wrapped_view_func
44. response = view_func(request, *args, **kwargs)
File "C:\Python26\lib\site-packages\django\contrib\admin\sites.py" in
inner
185. return self.login(request)
File "C:\Python26\lib\site-packages\django\views\decorators\cache.py"
in _wrapped_view_func
44. response = view_func(request, *args, **kwargs)
File "C:\Python26\lib\site-packages\django\contrib\admin\sites.py" in
login
300. user = authenticate(username=username,
password=password)
File "C:\Python26\lib\site-packages\django\contrib\auth\__init__.py"
in authenticate
37. user = backend.authenticate(**credentials)
File "C:\Python26\lib\site-packages\ldap_groups\accounts\backends.py"
in authenticate
161. l = self.bind_ldap(settings.BIND_USER,
settings.BIND_PASSWORD)
File "C:\Python26\lib\site-packages\ldap_groups\accounts\backends.py"
in bind_ldap
154. l.simple_bind_s(username, password)
File "C:\Python26\lib\site-packages\ldap\ldapobject.py" in
simple_bind_s
206. msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
File "C:\Python26\lib\site-packages\ldap\ldapobject.py" in simple_bind
200. return self._ldap_call
(self._l.simple_bind,who,cred,EncodeControlTuples
(serverctrls),EncodeControlTuples(clientctrls))
File "C:\Python26\lib\site-packages\ldap\ldapobject.py" in _ldap_call
96. result = func(*args,**kwargs)

Exception Type: SERVER_DOWN at /admin/
Exception Value: {'desc': "Can't contact LDAP server"}

Peter Herndon

unread,
Dec 22, 2009, 2:36:25 PM12/22/09
to django...@googlegroups.com

On Dec 22, 2009, at 10:40 AM, Wayne wrote:

> Thanks for the prompt reply. Yes, unique=True was the problem. Now I
> passed the "run syncdb" and new tables were created. However, I still
> could not "contact LDAP". Could somebody help me with this?

That would be me.

>
> Thanks!
>
> My settings:
>
> LDAP_SERVER = 'directory.XXXXX'
>
> # If using SSL use these:
> LDAP_PORT = 636
> LDAP_URL = 'ldaps://XXXXXXXX:636'
> SEARCH_DN = 'XXXXXXXX'
> SEARCH_FIELDS = ['sn','cn','uid']

Future note: The point of ldap-groups is to allow a mapping between LDAP OU group memberships and Django groups, in order to have LDAP users acquire the permissions that have been assigned to the Django group. So at some point you will need to add to SEARCH_FIELDS the field on your LDAP user that contains the list of groups to which the user belongs. If that field is not called 'groupMembership', you will need to edit the ldap_groups.accounts.backends module, and change lines 205 and 206 to match the name of that field.

This change isn't your initial problem, though, so it can be deferred for a bit. Eventually I should refactor that field out to its own setting.

> BIND_USER = 'XXXXXXXXXX'
> BIND_PASSWORD = 'XXXXXXXXX'
> CERT_FILE = 'XXXXXXXXXX'
>
> AUTHENTICATION_BACKENDS = (
> 'ldap_groups.accounts.backends.eDirectoryGroupMembershipSSLBackend',
> 'django.contrib.auth.backends.ModelBackend',
> )

[snip]

> Traceback:
>
[snip]

> 154. l.simple_bind_s(username, password)
> File "C:\Python26\lib\site-packages\ldap\ldapobject.py" in
> simple_bind_s
> 206. msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
> File "C:\Python26\lib\site-packages\ldap\ldapobject.py" in simple_bind
> 200. return self._ldap_call
> (self._l.simple_bind,who,cred,EncodeControlTuples
> (serverctrls),EncodeControlTuples(clientctrls))
> File "C:\Python26\lib\site-packages\ldap\ldapobject.py" in _ldap_call
> 96. result = func(*args,**kwargs)
>
> Exception Type: SERVER_DOWN at /admin/
> Exception Value: {'desc': "Can't contact LDAP server"}

The error messages are typically accurate. In this case, "Can't contact LDAP server" should be taken literally. You should first confirm that the LDAP server is listening on whatever port at the appropriate DNS name, and that you have network connectivity to the LDAP server. Once you've confirmed the DNS name and port, make sure those are in your settings.py file. A quick way to test is to try to telnet from the system running Django to the LDAP server. An example:

Ralf: $ telnet ldap.example.com 636
Trying 1.2.3.4...
Connected to ldap.example.com.
Escape character is '^]'.

If you get the above response ("Connected to XXX"), then you have confirmed you can contact the server, and your next step is to diagnose why python is not able to establish a client connection. If you do not get that response, your port or DNS name is incorrect, or you do not have connectivity to the server. The next step in this case is to figure out why your network connection is not working as expected.

One starting note: while the standard port for LDAPS is 636, and the standard port for unencrypted LDAP is 389, vendors may not follow the standard. In addition, your LDAP administrator can also decide to listen on different ports. This would be the first thing I'd check.

Let me know your results, and we can move on to the next step.

Regards,

---Peter

Wayne

unread,
Dec 23, 2009, 3:00:41 PM12/23/09
to Django users
Hi,

Many thanks for your reply.

I did the test and it seemed that our network is working fine and I
could telnet to the directory with "Connected" feedback. What other
things we could try next?

Wayne

Peter Herndon

unread,
Dec 23, 2009, 3:56:40 PM12/23/09
to django...@googlegroups.com

On Dec 23, 2009, at 3:00 PM, Wayne wrote:

> Hi,
>
> Many thanks for your reply.
>
> I did the test and it seemed that our network is working fine and I
> could telnet to the directory with "Connected" feedback. What other
> things we could try next?
>

Our next step is to work out how to make your connection work properly from Python. Django-ldap-groups is basically a thin wrapper around python-ldap, with added code to work with Django. So what we need to do next is establish a connection to your LDAP server from a Python shell using python-ldap. Once we have that connection working, we'll know what we need to change in the ldap-groups code to make it work with Sun ONE, and/or your particular environment.

I'm including a transcript of a python shell session. This session shows the steps needed to make a working connection to a server, and is based on the flow of events in the bind_ldap() method of eDirectoryGroupMembershipSSLBackend, in ldap_groups/accounts/backends.py. It also shows the kind of error you'll receive if the certificate you are trying to use is not correct:

Ralf:~ herndonp$ python
Python 2.6.1 (r261:67515, Jul 7 2009, 23:51:51)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ldap
>>> ldap.set_option(ldap.OPT_X_TLS_CACERTFILE,'/Users/herndonp/Downloads/wrongcert.b64')
>>> l = ldap.initialize('ldaps://ldap.example.com:636')
>>> l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
>>> l.simple_bind_s('cn=fake_username,o=fake_org', 'fake_password')


Traceback (most recent call last):

File "<stdin>", line 1, in <module>
File "/Library/Python/2.6/site-packages/ldap/ldapobject.py", line 206, in simple_bind_s
msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
File "/Library/Python/2.6/site-packages/ldap/ldapobject.py", line 200, in simple_bind
return self._ldap_call(self._l.simple_bind,who,cred,EncodeControlTuples(serverctrls),EncodeControlTuples(clientctrls))
File "/Library/Python/2.6/site-packages/ldap/ldapobject.py", line 96, in _ldap_call
result = func(*args,**kwargs)
ldap.SERVER_DOWN: {'info': 'error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed', 'desc': "Can't contact LDAP server"}
>>>

I'm including the error because it is most likely the cause of the problem, having eliminated connectivity. Getting the right certificate is not straight-forward. You do not need the actual certificate of the LDAP server, you need the trusted root certificate (including any intermediary signers) of the certificate authority that issued the certificate used by the LDAP server.

If you do get the error above, or something similar, it might be useful to confirm that there are no other problems connecting. If your LDAP server is listening for *un*encrypted traffic, you may want to try the above steps without encryption, just to see that you can connect successfully. An example session:

Ralf:~ herndonp$ python
Python 2.6.1 (r261:67515, Jul 7 2009, 23:51:51)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import ldap
>>> l = ldap.initialize('ldap://pledir1.mskcc.org:389')
>>> l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
>>> l.simple_bind_s('cn=fake_user,o=fake_org', 'fake_password!')
(97, [])
>>>


If you do get that error, you will need to work with your LDAP admin to identify the right certificate to export, export it as Base64 PEM encoded file, and place it somewhere you can reference from Python.

Give that a try and let me know how it goes.

---Peter

Reply all
Reply to author
Forward
0 new messages