Contents
LDAP Foreign Data Wrapper for PostgreSQL 9.2
Synopsis
A PostgreSQL's Foreign Data Wrapper (FDW) to query LDAP servers.
Warnings
- USE WITH CAUTION: It is not production ready but you could test it in your test server and help us to improve it;
- it not implements limits yet, so if you do a
select * from ldap_table
it will fetch all records from LDAP server. Some LDAP servers limits this to 500; - by now it only supports two columns:
dn
andobject_body
where the former is populated with the DN and the last with the LDAP entry converted to a Hstore compatible format;
Description
LDAP Foreign Data Wrapper for PostgreSQL 9.2.
Usage
Create the extension in your database:
CREATE EXTENSION ldap_fdw;
Then create a foreign server to connect to your LDAP server:
CREATE SERVER ldap_myldap_server
FOREIGN DATA WRAPPER ldap_fdw
OPTIONS ( address 'myldap_server_address', port '389');
Create user mapping:
CREATE USER MAPPING FOR current_user
SERVER ldap_myldap_server
OPTIONS (user_dn 'cn=SomeUser,dc=example,dc=net', password 'the_user_password');
Finally create a foreign table with a base DN pointing to some OU:
CREATE FOREIGN TABLE ldap_people (
dn text,
object_body text
)
SERVER ldap_myldap_server
OPTIONS (base_dn 'OU=people,DC=example,DC=net');
And voila!
> SELECT * FROM ldap_people;
dn | object_body
---------------------------------------------------+----------------------------------------------------------------
cn=Dickson Guedes,ou=people,dc=example,dc=net | cn => "Dickson Guedes", +
| gidNumber => "500", +
| homeDirectory => "/home/users/guedes", +
| sn => "Guedes", +
| loginShell => "/bin/sh", +
| objectClass => "{\"inetOrgPerson\",\"posixAccount\",\"top\"}",+
| userPassword => "ldap", +
| uidNumber => "1000", +
| uid => "guedes", +
| givenName => "{\"Dickson, Guedes\",\"Gueduxo\"}", +
|
cn=John Smith,ou=people,dc=example,dc=net | cn => "John Smith", +
| givenName => "John", +
| gidNumber => "500", +
| homeDirectory => "/home/users/jsmith", +
| sn => "Smith", +
| loginShell => "/bin/sh", +
| objectClass => "{\"inetOrgPerson\",\"posixAccount\",\"top\"}",+
| userPassword => "{SSHA}y0GfklAHS9AEDz87AdQ+UAQi3bGlfqXt", +
| uidNumber => "1001", +
| uid => "jsmith", +
|
If you use a filter on dn
column ldap_fdw
will convert it to LDAP dialect and will send it to the server and this one
will reply less entries. By now, only dn
has this behaviour.
See:
> SELECT object_body FROM ldap_people WHERE dn = 'cn=Dickson Guedes';
object_body
----------------------------------------------------------------
cn => "Dickson Guedes", +
gidNumber => "500", +
homeDirectory => "/home/users/guedes", +
sn => "Guedes", +
loginShell => "/bin/sh", +
objectClass => "{\"inetOrgPerson\",\"posixAccount\",\"top\"}",+
userPassword => "ldap", +
uidNumber => "1000", +
uid => "guedes", +
givenName => "{\"Dickson, Guedes\",\"Gueduxo\"}", +
(1 row)
Retrieving specific attributes
You can choose a list of attributes to retrieve, just add an option attributes
to FOREIGN TABLE's options with
a comma-separeted attributes like this:
ALTER FOREIGN TABLE ldap_people
OPTIONS ( ADD attributes 'gidNumber,uidNumber,homeDirectory' );
SELECT * FROM ldap_people WHERE dn = 'cn=John Smith';
dn | object_body
---------------------------------------------+----------------------------------------
cn=John Smith,ou=people,dc=guedesoft,dc=net | gidNumber => "500", +
| uidNumber => "1001", +
| homeDirectory => "/home/users/jsmith",+
|
(1 row)
Integration with Hstore
Well, you could do better than just retrieve that object_body
! What about using Hstore?
See:
> CREATE EXTENSION hstore;
> WITH
_hstore as (
SELECT hstore(object_body) as h
FROM ldap_people
)
SELECT h -> 'cn' as cn,
h -> 'objectClass' as object_class,
h -> 'homeDirectory' as home
FROM _hstore;
cn | object_class | home
------------------+----------------------------------------+----------------------
Dickson Guedes | {"inetOrgPerson","posixAccount","top"} | /home/users/guedes
John Smith | {"inetOrgPerson","posixAccount","top"} | /home/users/jsmith
Integration with pgcrypto
Your application doesn't know how to query a LDAP server? But it know SELECT
? What about
check if some user's password is correct using your PostgreSQL server as a proxy
?
Yes, you can! See:
> CREATE EXTENSION pgcrypto;
> WITH
_hstore as
(
SELECT hstore(object_body) as h
FROM ldap_people
WHERE dn = 'cn=John Smith'
),
_user_pass as
(
SELECT substr(decode(substr( h -> 'userPassword' , 7 ), 'base64'), 21) as salt,
h -> 'userPassword' as encrypted_password
FROM _hstore
),
_generated_pass as
(
SELECT '{SSHA}' || encode(digest( 'TheUserPassword123' || salt, 'sha1') || salt, 'base64') as password,
encrypted_password
FROM _user_pass
)
SELECT password = encrypted_password as password_match
FROM _generated_pass;
password_match
----------------
t
(1 row)
Well too verbose, but you could use a function, no? :)
Support
Copyright and License
This software is released under the PostgreSQL Licence.
Copyright (c) 2011-2013 Dickson S. Guedes.