Re: LDAP Auth: Require user to be in specified LDAP-group
This patch appears to work. Note, I have only done superficial testing (checked that I can log in as a user who is in the specified group and that I can not log in as one that is not in this group). I have not tested this against AD, only OpenLDAP. This patch applies to 2.2.17, but not to git-master. Guidodiff -rup jabberd-2.2.17-orig/etc/c2s.xml.dist.in jabberd-2.2.17/etc/c2s.xml.dist.in --- jabberd-2.2.17-orig/etc/c2s.xml.dist.in 2012-05-22 22:27:51.0 +0200 +++ jabberd-2.2.17/etc/c2s.xml.dist.in 2012-12-12 16:39:54.490003311 +0100 @@ -546,6 +546,15 @@ !-- validattrvalid/validattr -- + + !-- Group that users must be members of + If this is set, only user that are members of the specified LDAP + group can log in. The group must be specified with its full + distinguished name -- + !-- + group_dncn=jabberdusers,ou=servicegroups,dc=example,dc=com/group_dn + -- + fulluid/ !-- If pwscheme is not defined, then passwords are stored in clear text and digest authentication may be done. diff -rup jabberd-2.2.17-orig/storage/authreg_ldapfull.c jabberd-2.2.17/storage/authreg_ldapfull.c --- jabberd-2.2.17-orig/storage/authreg_ldapfull.c 2012-02-19 14:23:09.0 +0100 +++ jabberd-2.2.17/storage/authreg_ldapfull.c 2012-12-12 16:52:30.43587 +0100 @@ -68,6 +68,7 @@ typedef struct moddata_st char *objectclass; char *uidattr; char *validattr; +char *group_dn; char *pwattr; char *pwscheme; @@ -583,6 +584,50 @@ retry: return dn; } +/** Is this user part of the given LDAP group? */ +static int _ldapfull_user_in_group(moddata_t data, char *user_dn, char *group_dn) +{ +LDAPMessage *result, *entry; +int tried = 0; +char filter[1024]; + +log_debug(ZONE, checking whether user with dn %s is in group %s, user_dn, group_dn); + +memset(filter, 0, 1024); +snprintf(filter, 1024, (member=%s), user_dn); // TODO Check if snprintf result was truncated + +retry: +if(ldap_search_s(data-ld, group_dn, LDAP_SCOPE_BASE, filter, NULL, 0, result)) +{ +if( tried++ LDAPFULL_SEARCH_MAX_RETRIES ) { +log_debug(ZONE, ldap: group search fail, will retry; %s: %s, filter, ldap_err2string(_ldapfull_get_lderrno(data-ld))); +_ldapfull_unbind(data); +if( _ldapfull_connect_bind(data) == 0 ) { +goto retry; +} else { +return 0; +} +} +log_write(data-ar-c2s-log, LOG_ERR, ldap: group search %s failed: %s, filter, ldap_err2string(_ldapfull_get_lderrno(data-ld))); +_ldapfull_unbind(data); +return 0; +} + +entry = ldap_first_entry(data-ld, result); +if(entry == NULL) +{ +ldap_msgfree(result); + +return 0; +} +else +{ +ldap_msgfree(result); + +return 1; +} +} + /** do we have this user? */ static int _ldapfull_find_user_dn(moddata_t data, char *username, char *realm, char **dn) { @@ -601,6 +646,11 @@ static int _ldapfull_user_exists(authreg { char *dn; if (_ldapfull_find_user_dn((moddata_t) ar-private, username, realm, dn)) { +if(((moddata_t) ar-private)-group_dn != NULL + !_ldapfull_user_in_group((moddata_t) ar-private, dn, ((moddata_t) ar-private)-group_dn)) { +ldap_memfree(dn); +return 0; +} ldap_memfree(dn); return 1; } @@ -748,22 +798,40 @@ static int _ldapfull_check_password(auth { moddata_t data = (moddata_t) ar-private; char buf[LDAPFULL_PASSBUF_MAX]; +char *dn; log_debug(ZONE, checking password for %s, username); if(password[0] == '\0') return 1; +if(data-group_dn != NULL) { +if (!_ldapfull_find_user_dn(data, username, realm, dn)) +return 1; +} /* The bind scheme doesn't need the password read first, so short circuit the whole passhash scheme */ -if (!strcmp(data-pwscheme, bind)) -return _ldapfull_check_password_bind(ar, username, realm, password); +if (!strcmp(data-pwscheme, bind)) { +if(_ldapfull_check_password_bind(ar, username, realm, password) == 0) { +if(data-group_dn != NULL !_ldapfull_user_in_group(data, dn, data-group_dn)) +return 1; +else +return 0; +} +} if( _ldapfull_get_password(ar,username,realm,buf) != 0 ) { return 1; } -return ! _ldapfull_check_passhash(data,buf,password); +if(_ldapfull_check_passhash(data,buf,password)){ +if(data-group_dn != NULL !_ldapfull_user_in_group(data, dn, data-group_dn)) + return 1; +else +return 0; +} +else + return 1; } static int _ldapfull_create_user(authreg_t ar, char *username, char *realm) { @@ -856,6 +924,8 @@ DLLEXPORT int ar_init(authreg_t ar)
two ldap modules (Re: LDAP Auth: Require user to be in specified LDAP-group)
I compared the two ldap modules here: http://www.mail-archive.com/jabberd2@lists.xiaoka.com/msg01381.html (Was it really three years ago??) Is there any reason to maintain both? What does full mean in ldapfull? Justin On Wed, Dec 12, 2012 at 05:07:34PM +0100, Guido Winkelmann wrote: This patch appears to work. Note, I have only done superficial testing (checked that I can log in as a user who is in the specified group and that I can not log in as one that is not in this group). I have not tested this against AD, only OpenLDAP. This patch applies to 2.2.17, but not to git-master. Guido diff -rup jabberd-2.2.17-orig/etc/c2s.xml.dist.in jabberd-2.2.17/etc/c2s.xml.dist.in --- jabberd-2.2.17-orig/etc/c2s.xml.dist.in 2012-05-22 22:27:51.0 +0200 +++ jabberd-2.2.17/etc/c2s.xml.dist.in2012-12-12 16:39:54.490003311 +0100 @@ -546,6 +546,15 @@ !-- validattrvalid/validattr -- + + !-- Group that users must be members of + If this is set, only user that are members of the specified LDAP + group can log in. The group must be specified with its full + distinguished name -- + !-- + group_dncn=jabberdusers,ou=servicegroups,dc=example,dc=com/group_dn + -- + fulluid/ !-- If pwscheme is not defined, then passwords are stored in clear text and digest authentication may be done. diff -rup jabberd-2.2.17-orig/storage/authreg_ldapfull.c jabberd-2.2.17/storage/authreg_ldapfull.c --- jabberd-2.2.17-orig/storage/authreg_ldapfull.c2012-02-19 14:23:09.0 +0100 +++ jabberd-2.2.17/storage/authreg_ldapfull.c 2012-12-12 16:52:30.43587 +0100 @@ -68,6 +68,7 @@ typedef struct moddata_st char *objectclass; char *uidattr; char *validattr; +char *group_dn; char *pwattr; char *pwscheme; @@ -583,6 +584,50 @@ retry: return dn; } +/** Is this user part of the given LDAP group? */ +static int _ldapfull_user_in_group(moddata_t data, char *user_dn, char *group_dn) +{ +LDAPMessage *result, *entry; +int tried = 0; +char filter[1024]; + +log_debug(ZONE, checking whether user with dn %s is in group %s, user_dn, group_dn); + +memset(filter, 0, 1024); +snprintf(filter, 1024, (member=%s), user_dn); // TODO Check if snprintf result was truncated + +retry: +if(ldap_search_s(data-ld, group_dn, LDAP_SCOPE_BASE, filter, NULL, 0, result)) +{ +if( tried++ LDAPFULL_SEARCH_MAX_RETRIES ) { +log_debug(ZONE, ldap: group search fail, will retry; %s: %s, filter, ldap_err2string(_ldapfull_get_lderrno(data-ld))); +_ldapfull_unbind(data); +if( _ldapfull_connect_bind(data) == 0 ) { +goto retry; +} else { +return 0; +} +} +log_write(data-ar-c2s-log, LOG_ERR, ldap: group search %s failed: %s, filter, ldap_err2string(_ldapfull_get_lderrno(data-ld))); +_ldapfull_unbind(data); +return 0; +} + +entry = ldap_first_entry(data-ld, result); +if(entry == NULL) +{ +ldap_msgfree(result); + +return 0; +} +else +{ +ldap_msgfree(result); + +return 1; +} +} + /** do we have this user? */ static int _ldapfull_find_user_dn(moddata_t data, char *username, char *realm, char **dn) { @@ -601,6 +646,11 @@ static int _ldapfull_user_exists(authreg { char *dn; if (_ldapfull_find_user_dn((moddata_t) ar-private, username, realm, dn)) { +if(((moddata_t) ar-private)-group_dn != NULL + !_ldapfull_user_in_group((moddata_t) ar-private, dn, ((moddata_t) ar-private)-group_dn)) { +ldap_memfree(dn); +return 0; +} ldap_memfree(dn); return 1; } @@ -748,22 +798,40 @@ static int _ldapfull_check_password(auth { moddata_t data = (moddata_t) ar-private; char buf[LDAPFULL_PASSBUF_MAX]; +char *dn; log_debug(ZONE, checking password for %s, username); if(password[0] == '\0') return 1; +if(data-group_dn != NULL) { +if (!_ldapfull_find_user_dn(data, username, realm, dn)) +return 1; +} /* The bind scheme doesn't need the password read first, so short circuit the whole passhash scheme */ -if (!strcmp(data-pwscheme, bind)) -return _ldapfull_check_password_bind(ar, username, realm, password); +if (!strcmp(data-pwscheme, bind)) { +if(_ldapfull_check_password_bind(ar, username, realm, password) == 0) { +if(data-group_dn != NULL !_ldapfull_user_in_group(data, dn, data-group_dn)) +return 1; +else +return 0; +} +} if( _ldapfull_get_password(ar,username,realm,buf) != 0 ) {
Unable to connect to server, probably database related
Okay, so I'm trying to set up a jabber server on my laptop. I'm running on Fedora 17 x86_64 and installed it from the provided binaries with yum install jabberd. I've been following the rpm quick start guide https://github.com/jabberd2/jabberd2/wiki/InstallGuide-QuickStartGuideRPM.I was able to get a database set up and the server starts fine, but I think it's having some problems actually using the database. When it's set to the default sqlite database it sort of works - the server is up, anyway, though I can't seem to register any accounts on it (I'm using pidgin and get a 500: Internal Server Error). This I don't care about - I don't plan on using sqlite anyway, just not sure if it's related. When using MySQL, the service appears to start fine (I start it with service jabberd start) but I'm not able to connect to the server at all. I have double and triple checked that I can log in to the jabberd2 database with the jabberd2 user and the secret_pass password (I'm just trying to get it running with the defaults right now) and that those are the credentials listed in the sm.xml and c2s.xml files. Oh, and I'm running it on my laptop just using the localhost.localdomain domain to rule out any firewall issues. I have no idea what's wrong. Any suggestions? Attached are my c2s.xml and sm.xml configuration files, the only two I've changed. !-- Session manager configuration -- sm !-- Our ID on the network (default: sm) -- idsm/id !-- The process ID file. Comment this out if you don't need to know the process ID from outside the process (eg for control scripts) -- pidfile/var/lib/jabberd/pid/sm.pid/pidfile !-- Router connection configuration -- router !-- IP/port the router is waiting for connections on -- ip127.0.0.1/ip!-- default: 127.0.0.1 -- port5347/port !-- default: 5347 -- !-- Username/password to authenticate as -- userjabberd/user !-- default: jabberd -- pass3498e9b05da27cfc60f8bdf6d66726db1f3f6c68/pass !-- default: secret -- !-- File containing an SSL certificate and private key to use when setting up an encrypted channel with the router. From SSL_CTX_use_certificate_chain_file(3): The certificates must be in PEM format and must be sorted starting with the subject's certificate (actual client or server certificate), followed by intermediate CA certificates if applicable, and ending at the highest level (root) CA (the latter one being optional). If this is commented out, or the file can't be read, no attempt will be made to establish an encrypted channel with the router. -- !-- pemfile/etc/jabberd/server.pem/pemfile -- !-- Router connection retry -- retry !-- If the connection to the router can't be established at startup, we should try again this many times before exiting. Use -1 to retry indefinitely. [default: 3] -- init3/init !-- If we lost the connection to the router during normal operation (ie we've successfully connected to the router in the past), we should try to reconnect this many times before exiting. Use -1 to retry indefinitely. [default: 3] -- lost3/lost !-- Sleep for this many seconds before trying attempting a reconnect. [default: 2] -- sleep2/sleep /retry /router !-- Log configuration - type is syslog, file or stdout -- log type='syslog' !-- If logging to syslog, this is the log ident -- identjabberd/sm/ident !-- If logging to syslog, this is the log facility (local0 - local7)[default: local3] -- facilitylocal3/facility !-- If logging to file, this is the filename of the logfile -- !-- file/var/lib/jabberd/log/sm.log/file -- /log !-- Local network configuration -- local !-- Who we identify ourselves as. Users will have this as the domain part of their JID. If you want your server to be accessible from other Jabber servers, this IDs must be FQDN resolvable by DNSes. If not set, the SM id is used. -- idlocalhost.localdomain/id !-- idvhost1.localdomain/id idvhost2.localdomain/id -- /local !-- Storage database configuration -- storage !-- Dynamic storage modules path -- path/usr/lib64/jabberd/path !-- By default, we use the SQLite driver for all storage -- drivermysql/driver !-- Its also possible to explicitly list alternate drivers for specific data types. -- !-- Store vcards in a ldapvcard database instead -- !-- driver type='vcard'ldapvcard/driver -- !-- Read mapping for group id - group name from ldap. Used by mod_published_roster. See ldapvcard section for options. When resolving group id to group name, it searches for groupsobjectclass objects at groupsdn