Настройка корпоративной адресной книги (Postfix+LDAP)

Устанавливаем пакеты

  1. apt install slapd odbc-postgresql unixodbc

Вносим изменения в БД postfix

  1. ALTER TABLE DOMAIN ADD COLUMN id SERIAL;
  2. ALTER TABLE mailbox ADD COLUMN id SERIAL;
  3.  
  4. CREATE TABLE ldap_entry_objclasses (
  5. entry_id INTEGER NOT NULL,
  6. oc_name CHARACTER VARYING(64)
  7. );
  8.  
  9. CREATE TABLE ldap_oc_mappings (
  10. name CHARACTER VARYING(64) NOT NULL,
  11. keytbl CHARACTER VARYING(64) NOT NULL,
  12. keycol CHARACTER VARYING(64) NOT NULL,
  13. create_proc CHARACTER VARYING(255),
  14. delete_proc CHARACTER VARYING(255),
  15. expect_return INTEGER NOT NULL
  16. );
  17.  
  18. ALTER TABLE ldap_oc_mappings ADD COLUMN id SERIAL;
  19. ALTER TABLE ldap_oc_mappings ADD PRIMARY KEY (id);
  20.  
  21. CREATE TABLE ldap_attr_mappings (
  22. oc_map_id INTEGER NOT NULL REFERENCES ldap_oc_mappings(id),
  23. name CHARACTER VARYING(255) NOT NULL,
  24. sel_expr CHARACTER VARYING(255) NOT NULL,
  25. sel_expr_u CHARACTER VARYING(255),
  26. from_tbls CHARACTER VARYING(255) NOT NULL,
  27. join_where CHARACTER VARYING(255),
  28. add_proc CHARACTER VARYING(255),
  29. delete_proc CHARACTER VARYING(255),
  30. param_order INTEGER NOT NULL,
  31. expect_return INTEGER NOT NULL
  32. );
  33.  
  34. ALTER TABLE ldap_attr_mappings ADD COLUMN id SERIAL;
  35. ALTER TABLE ldap_attr_mappings ADD PRIMARY KEY (id);
  36.  
  37. CREATE VIEW ldap_dcs AS
  38. ((SELECT (DOMAIN.id + 100000) AS id,
  39. ('dc='::text || REPLACE((DOMAIN.DOMAIN)::text, '.'::text, ',dc='::text)) AS dn,
  40. 1 AS oc_map_id,
  41. 100000 AS parent,
  42. 0 AS keyval,
  43. DOMAIN.DOMAIN
  44. FROM DOMAIN
  45. WHERE DOMAIN.DOMAIN <> 'ALL')
  46. UNION
  47. (SELECT 100000 AS id,
  48. ('dc=' || regexp_replace((DOMAIN.DOMAIN)::text, '.*\.', ''::text)) AS dn,
  49. 1 AS oc_map_id,
  50. 0 AS parent,
  51. 0 AS keyval,
  52. (regexp_replace((DOMAIN.DOMAIN)::text, '.*\.', ''::text)) AS DOMAIN
  53. FROM DOMAIN
  54. WHERE DOMAIN.DOMAIN <> 'ALL'
  55. LIMIT 1));
  56.  
  57. CREATE VIEW ldap_entries AS
  58. SELECT mailbox.id,
  59. ((('cn='::text || initcap(REPLACE(split_part((mailbox.username)::text, '@'::text, 1), '.'::text, ' '::text))) || ',dc='::text) ||
  60. REPLACE(regexp_replace((mailbox.username)::text, '.*@', ''::text), '.'::text, ',dc='::text)) AS dn,
  61. 1 AS oc_map_id,
  62. (SELECT ldap_dcs.id
  63. FROM ldap_dcs
  64. WHERE ((ldap_dcs.DOMAIN)::text = (mailbox.DOMAIN)::text)) AS parent,
  65. mailbox.id AS keyval
  66. FROM mailbox
  67. UNION
  68. SELECT ldap_dcs.id,
  69. ldap_dcs.dn,
  70. ldap_dcs.oc_map_id,
  71. ldap_dcs.parent,
  72. ldap_dcs.keyval
  73. FROM ldap_dcs;
  74.  
  75. COPY ldap_oc_mappings (id, name, keytbl, keycol, create_proc, delete_proc, expect_return) FROM stdin;
  76. 1 exampleBox mailbox id \N \N 1
  77. \.
  78. COPY ldap_attr_mappings (id, oc_map_id, name, sel_expr, sel_expr_u, from_tbls, join_where, add_proc, delete_proc, param_order, expect_return) FROM stdin;
  79. 1 1 displayName mailbox.name \N mailbox \N \N \N 3 0
  80. 2 1 mail mailbox.username \N mailbox \N \N \N 3 0
  81. 3 1 cn mailbox.name \N mailbox \N \N \N 3 0
  82. 4 1 userPassword '{CRYPT}'||mailbox.password \N mailbox \N \N \N 3 0
  83. \.
  84.  

Проверяем, ldap_dcs должен выглядеть примерно так:

  1. id | dn | oc_map_id | parent | keyval | domain
  2. --------+-----------------------------+-----------+--------+--------+--------------------
  3. 100000 | dc=com | 1 | 0 | 0 | com
  4. 100001 | dc=example,dc=com | 1 | 100000 | 0 | example.com

ldap_entries должен выглядеть примерно вот так:

  1. id | dn | oc_map_id | parent | keyval
  2. --------+-------------------------------------------------------+-----------+--------+--------
  3. 1 | cn=address1,dc=example,dc=com | 1 | 100001 | 1
  4. ...
  5. 123 | cn=address123,dc=example,dc=com | 1 | 100001 | 1
  6. 100000 | dc=com | 1 | 0 | 0
  7. 100001 | dc=example,dc=com | 1 | 100000 | 0

Настраиваем ODBC: /etc/odbc.ini

  1. [PostgreSQL]
  2. Description = Connection to Postgres
  3. Driver = PostgreSQL
  4. Trace = Yes
  5. TraceFile = sql.log
  6. Database = postfix
  7. Servername = 127.0.0.1
  8. UserName =
  9. Password =
  10. Port = 5432
  11. Protocol = 6.4
  12. ReadOnly = No
  13. RowVersining = No
  14. ShowSystemTables = No
  15. ShowOidColumn = No
  16. FakeOidIndex = No
  17. ConnSettings =

/etc/odbcinst.ini

  1. [PostgreSQL]
  2. Description = PostgreSQL driver for Linux
  3. Driver = /usr/lib/psqlodbcw.so
  4. Setup = /usr/lib/libodbcpsqlS.so
  5. FileUsage = 1

Проверяем соединение ODBC

  1. echo "select * from domain;" | isql PostgreSQL postgres

Делаем LDAP схему /etc/ldap/schema/mail.schema

  1. attributetype ( 0.9.2342.19200300.100.1.3
  2. NAME ( 'mail' 'rfc822Mailbox' )
  3. DESC 'RFC1274: RFC822 Mailbox'
  4. EQUALITY caseIgnoreIA5Match
  5. SUBSTR caseIgnoreIA5SubstringsMatch
  6. SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
  7.  
  8. attributetype ( 2.16.840.1.113730.3.1.241
  9. NAME 'displayName'
  10. DESC 'RFC2798: preferred name to be used when displaying entries'
  11. EQUALITY caseIgnoreMatch
  12. SUBSTR caseIgnoreSubstringsMatch
  13. SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  14. SINGLE-VALUE )
  15.  
  16. objectclass ( 2.16.840.1.113730.3.2.2
  17. NAME 'exampleBox'
  18. DESC 'example.com mailbox'
  19. MUST ( displayName $ mail $ userPassword )
  20. )
  21.  
  22. # RFC 1274 + RFC 2247
  23. attributetype ( 0.9.2342.19200300.100.1.25
  24. NAME ( 'dc' 'domainComponent' )
  25. DESC 'RFC1274/2247: domain component'
  26. EQUALITY caseIgnoreIA5Match
  27. SUBSTR caseIgnoreIA5SubstringsMatch
  28. SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
  29.  
  30. attributetype ( 2.5.4.46 NAME 'dnQualifier'
  31. DESC 'RFC2256: DN qualifier'
  32. EQUALITY caseIgnoreMatch
  33. ORDERING caseIgnoreOrderingMatch
  34. SUBSTR caseIgnoreSubstringsMatch
  35. SYNTAX 1.3.6.1.4.1.1466.115.121.1.44 )
  36.  

Настраиваем ldap демона /etc/ldap/slapd.conf

  1. include /etc/ldap/schema/mail.schema
  2. pidfile /var/run/slapd/slapd.pid
  3. argsfile /var/run/slapd/slapd.args
  4.  
  5.  
  6. TLSCACertificateFile /etc/ssl/certs/ca-certificates.crt
  7. TLSCertificateFile /etc/ssl/fullchain.pem
  8. TLSCertificateKeyFile /etc/ssl/privkey.pem
  9. TLSVerifyClient never
  10.  
  11. #loglevel stats ACL config filter
  12. loglevel stats
  13. moduleload /usr/lib/ldap/back_sql.so
  14. sizelimit 3000
  15.  
  16. database sql
  17.  
  18. dbname PostgreSQL
  19. dbuser postfix
  20. dbpasswd postfixpassword1
  21.  
  22. suffix "dc=example,dc=com"
  23.  
  24. upper_func "upper"
  25. strcast_func "text"
  26. concat_pattern "?||?"
  27. has_ldapinfo_dn_ru no
  28. lastmod off
  29.  
  30. access to attrs=userPassword by * auth
  31.  
  32. access to * by peername.ip=127.0.0.1 read
  33. by users read

Проверяем работоспособность LDAP

  1. ldapsearch -x
  2. ldapsearch -x -D "cn=test1,dc=example,dc=com" -W

Прикручиваем справочник к Roundcube roundcube/config/config.inc.php

  1. $rcmail_config['ldap_public']['example.com'] = array(
  2. 'name' => 'example.com',
  3. 'hosts' => array('127.0.0.1'),
  4. 'port' => 389,
  5. 'use_tls' => false,
  6. 'user_specific' => false,
  7. 'base_dn' => 'dc=example,dc=com',
  8. 'bind_dn' => '',
  9. 'bind_pass' => '',
  10. 'writable' => false,
  11. 'LDAP_Object_Classes' => array("top", "exampleBox"),
  12. 'required_fields' => array("cn", "sn", "mail"),
  13. 'LDAP_rdn' => 'mail',
  14. 'ldap_version' => 3,
  15. 'search_fields' => array('mail', 'cn', 'sn', 'givenName'),
  16. 'name_field' => 'cn',
  17. 'email_field' => 'mail',
  18. 'surname_field' => 'sn',
  19. 'firstname_field' => 'gn',
  20. 'sort' => 'cn',
  21. 'scope' => 'sub',
  22. 'filter' => '(objectClass=*)', // Construct here any filter you need
  23. 'fuzzy_search' => true);
  24.  
  25. $rcmail_config['autocomplete_addressbooks'] = array('sql','example.com');

Последние изменения на 08:50 12 марта 2019