Notes on XMPP authentication in Citadel. (2011-02-14) Extended with notes on other XMPP servers. For use with further XMPP development this document is copied into ../xmpp . Symptom: 1. the docs don't say who you can actually authenticate as. 2. Can't get a buddy relation, when I request authorization nothing happens on the buddy's side, I get 503 no service available when I ask for user info, and no presence info is ever sent. 3. When the partner logs out, the buddy icon vanishes. Looking in modules/xmpp/xmpp_sasl_service.c Doesn't do real SASL, it does its own PLAIN auth. XMPP is governed by RFC 3920. Per the RFC: Sect. 3.1. JID (Jabber ID) = node@domain/resource (node and /resource are actually optional, @domain is required.) Domain should be a FQDN but may be an IPv4 or IPv6 address. It's intended that DNS lookups of this FQDN should eventually yield the connect server address. Sect. 6.1 rule 7: The authentication entity is the one whose credential you are presenting. The authorization entity is the one you want to log in as. The authz ent MUST be omitted if it is the same as the authen ent. Sect 6.2.2: If there is a valid cert from TLS, the server SHOULD offer SASL EXTERNAL which appears to mean to use the cert for auth. Sect. 9: XML Stanzas. 3 kinds: (push to specific recipient), (broadcast to all subscribers), (client requests info, or polling). Sect. 9.3.3: "service unavailable" meas server does not provide that kind of service. Also (sect 10.5.2) "service unavailable" is returned if the "to" attribute specifies a resource and that resource is not logged on. But if no resource is specified the server should deliver the stanza to at least one matching node@domain/rsc (app specific rules determine if only one receives it, or more.) SASL is governed by RFC 2222. An auth string comes in which is base64 encoded (decode it). As interpreted by xmpp_auth_plain(char* authstring), this string contains ident\0user\0passwd Convert spaces to underbars (some clients do not allow spaces). Calls CtdlLoginExistingUser(user, ident) or (NULL, user) (the usual case). And then checks the password. CtdlLoginExistingUser(authz, authen) is defined in ./user_ops.c Only give authz if using the "master user" feature. It doesn't want to see @domain: wants loginID in host mode or LDAP, either screen name or email address in native mode. Looking in modules/xmpp/xmpp_presence.c xmpp_indicate_presence (char* jid) sends a presence stanza describing the argument JID to a client identified in a global variable XMPP. The type of presence (e.g. "do not disturb") is not included. xmpp_is_visible(CitContext* cptr, CitContext* to_whom) tests if session *cptr is visible to session *to_whom. cptr has to be logged in, and (not stealth || to_whom is an aide) and users are different (don't see yourself) and session can receive IM traffic. No tests for being a buddy. xmpp_wholist_presence_dump sends presence (xmpp_indicate_presence) to every known session. No check for visibility. Recipient is context->cs_inet_email. <==NOTE xmpp_destroy_buddy (jid) operates on the session pointed to by global XMPP. 1. It announces presence(jid) = unavailable to *XMPP 2. It announces presence(jid) = unsubscribed to *XMPP 3. Sends unsolicited IQ result from *jid to *XMPP saying to remove the subscription. xmpp_presence_notify when a user logs in (1st session only) or out (last session only) it runs xmpp_indicate_presence (on login) or xmpp_destroy_buddy (on logout). This seems rather bogus! Conclusion: Citadel's concept of buddies is a lot different from anyone else's; buddies appear to be transient and must be established on each session. There seems to be no concept of authorization to be a buddy. Conclusion #2: Citadel isn't going to make it as the CFT XMPP server. --------------------------- Searching for a XMPP server. Starting at http://www.jabber.org/ They're a server, they don't build servers. Jump to http://xmpp.org/ and follow links to xmpp-software/clients/ and /servers/ They have 80 clients registered. 23 servers registered. Looking at all. Commercial and rejected ones first. . CommuniGate Pro Commercial . IceWarp Commercial . iChat Server Commercial . Isode M-Link Commercial . Jabber XCP Commercial . Jerry Messenger Commercial . SoapBox Server Commercial . Citadel Already worked on it. . ejabberd Trying to replace this one. . jabberd 1.x Rejected . jabberd 2.x Replaced this one by ejabberd. . Kwickserver For Windows (GPL) . Open IM BSD . Sun Java System IM Rejected The comments are mostly quotes from the project/vendor websites. . djabberd http://www.danga.com/djabberd/ (redirects to:) https://github.com/djabberd/ Mature product since 2007. Used by LiveJournal and many other sites. Written in Perl. Can handle 3e5 connections in 1e9 bytes memory. Purpose is a customization or special project framework, although it comes with an example server. Inter-server communication works. XMPP 1.0 including STARTTLS. Various authentication plugins. jimc says: what's their business model? . in.jabberd http://inetdxtra.sourceforge.net/#jabberd A tiny server started by inetd. Plain auth, and a config file holds a list of usernames and passwords. jimc says: Forget this. . Openfire http://www.igniterealtime.org/projects/openfire/index.jsp Actively developed. "Incredibly easy to set up and administer, but offers rock-solid security and performance." Written in Java. Has lots of plugins: Asterisk, Email notification (biff?), MOTD, HTTP output of presence, user registration or subscription, import and export user data, web interface for administering users. GPLv2. Uses JDBC, provided setups for MySQL, PostgreSQL, etc., other databases can be used. Or use provided internal database. Distributed as RPM or TGZ. Requires a special user "jive". . Prosody http://prosody.im/ Written in Lua. Active development. MIT/X11 license. Server-server communication works (incl. with Google Talk). Lots of optional modules. List of extensions -- Many features don't involve the server, specifically audio/video. There are a zillion extensions, most either client-client or are supported. XEP-0045 multi user chat. XEP-0049 Private XML storage. XEP-0054 vCard-temp (Pidgin does this -- maybe involved with fine-grained presence.) XEP-0055 Jabber search (not supported). XEP-0078 Non-SASL auth. XEP-0107/8 User mood/activity. XEP-0159 Spim-blocking (not supported). XEP-0178 Best Practices for SASL External (X.509) (not supported). XEP-0214 File repository and sharing (not supported). Community modules available from http://code.google.com/p/prosody-modules/w/list (wiki): mod_auth_external, mod_auth_ldap, mod_openid (turns it into an OpenID provider), lots of useless stuff. Jimc says: the one item that may be missing is implicit provisioning. . psyced http://www.psyced.org/ It's a super-multi-protocol server for chat and social networking. I didn't think much of it the last time around. . synapse http://synapse.malkier.net/ (license unknown) A small XMPP server written in Ruby. Might not have too much activity since 2008. . Tigase http://www.tigase.org/ Active development. "Powered by Java". Nice logo image of a tiger. Can use any JDBC database (schemas provided for major ones) and looks like native support for MySQL, PostgreSQL, etc.) Seems to have all the major features. Resource use: tests give it 100Mb RAM and have 1000 concurrent connections running flat out. . Vysper http://cwiki.apache.org/labs/vysper.html (license unkn) (Vysper has moved to become a sub-project of Apache MINA at http://mina.apache.org/) Seems to be Java powered. I can't dig up much info from the web pages. . Wokkel http://wokkel.ik.nu/ (license unknown) Based on Twisted, a Python networking framework. It is intended as a development framework for XMPP protocol extensions. It has a lot of extensions that other servers lack. Let's investigate Prosody first, then Openfire, then djabberd. Actually, is ejabberd really that bad? Let's just restore ejabberd and put energy into something that's actually broken. ----------------------------- More work on XMPP, 2012-04-10 With advances in Kerberos at Mathnet, I would like to move forward with Kerberos authentication, specifically with the client at Mathnet. https://groups.google.com/group/comp.protocols.kerberos/browse_thread/thread/03ab1e15b92f0569 OP Oliver Schmidt (2009-11-30) is trying to set up a XMPP server with Krb auth. He failed to get working the GSSAPI patch for ejabberd, and had trouble making Openfire work also. Asks what people are using. Russ Allbery @stanford says they use Openfire but it has some "serious issues". Many clients can do both GSSAPI and TLS. Including Pidgin. http://itlab.stanford.edu/blog/archives/2009/test-services/openfire-and-kerberos-implementation-notes Blog by Greg Hudson (2009-03-06) describing how they got GSSAPI working in Openfire, linked from the above forum posting. I think I'm going to put Openfire at the end of the list because it's in Java and the GSSAPI support is entangled with bad Java support for Kerberos specifically and encryption generally. http://www.ejabberd.im/cyrsasl_gssapi -- How to set up GSSAPI in ejabberd (link is dead) Correct URL: http://www.ejabberd.im/cyrsasl_gssapi (I can't see the difference). But this isn't real Kerberos auth; it wants a password and checks it by decrypting a Krb ticket that it obtains. There is said to be real GSSAPI (Krb) since 2.1.9 (in Russian). Recent versions of ejabberd in SuSE Build Service: server:messaging (2.1.10) -- does PAM and SSL, no direct SASL or Krb. Ditto for 5 different versions. SuSE Build Service has djabberd-0.84 ; you need an auth plugin (from where?) Install requirements: perl(Danga::Socket) >= 1.51 Don't have perl(Digest::HMAC_SHA1) We have (perl-Digest-HMAC) perl(Log::Log4perl) Have (not inst.) perl(Net::DNS) >= 0.48 Have (not inst.) perl(Net::SSLeay) Have (inst.) perl(XML::LibXML::SAX) Have (perl-XML-LibXML inst.) perl(XML::SAX) Have (inst.) perl = 5.12.3 Our version See https://metacpan.org/module/DJabberd::SASL::AuthenSASL This module only does Plain, Login, Digest-MD5; not GSSAPI. See also https://metacpan.org/module/DJabberd::SASL (its parent class). It looks like djabberd is not going to do what we want. Prosody is on the SuSE Build Service in server:messaging. Requires: luaexpat On SBS in server_messaging luasocket ditto luafilesystem ditto luasec Implements starttls (on SBS) https://groups.google.com/group/prosody-users/browse_thread/thread/f718bbf6c6a80197 OP Mansur Mamkin (2012-02-22) asks if Prosody can do Kerberos auth. Matthew Wild replies: yes but he's never done it. See this link: http://prosody.im/doc/cyrus_sasl Get the lua-cyrussasl package (not on SuSE Build Service?) The SBS server:messaging repo contains these packages: centerim Multi-protocol instant message client using ncurses. ejabberd XMPP server (in erlang) (and erlang infrastructure) emesene MSN Messenger client (in Python) jabberd-2.2 XMPP server mcabber XMPP client using ncurses openfire XMPP server (in Java) prosody XMPP server (in LUA) sxmppd XMPP server (in C++), pre-alpha software lua-cyrussasl or liblua5.1-cyrussasl are target names in various distros. Under the 2nd name it isn't on SBS either. Nor lua51-cyrussasl10 etc. etc. https://github.com/JorjBauer/lua-cyrussasl -- The source code. Prosydy requires luaexpat luasocket luafilesystem luasec Downloaded and installed all, successfully. It would be helpful to install lua. Package name: lua51 like, this package has the interpreter -- should be an explicit dependency. Got it set up, and it does offer GSSAPI (and then can't fall back to Plain). Should be able to fall back to plain -- ask on Prosody mailing list. Client is reverse mapping the IP adr of the server and trying to get a host ticket for that. Web auth (SPNEGO) does the same thing. Fix #1: hack the client to use the URL address of the server. Yeah, sure. Fix #2: Issue ourselves a host ticket. 1. Reverse DNS gives pool-71-104-222-103.lsanca.dsl-w.verizon.net. 2. We know we'll never need to contact the nonexistent real Kerberos server of verizon.net (or at least lsanca.dsl-w.verizon.net ). 3. Use domain_realm (on the client and the server) to put Verizon's domain namespace in our realm. 4. When the aleatory IP address is updated, create a principal for the current Verizon name of that IP with the relevant services: host/$PTR, HTTP/$PTR, xmpp/$PTR. Copy these to the service keytabs. 5. Housekeeping: Maybe weekly, purge outdated principals and keytab entries. 6. What the client does: A Client is told to contact otter.mine.nu B Forward map to 71.104.222.103 C Reverse map to pool-71-104-222-103.lsanca.dsl-w.verizon.net. D Domain_realm says this is in CFT.CA.US realm E Gets host/pool-71-104-222-103.lsanca.dsl-w.verizon.net@CFT.CA.US and similarly for xmpp/pool....@CFT.CA.US F Client is happy. Server is happy. We hope. 7. Procedure for a new aleatory IP. Doing this manually once. A Edit /etc/krb5.conf with the right domain_realm stanza. .lsanca.dsl-w.verizon.net. = CFT.CA.US B Many of the following use kadmin.local. ank host/pool-71-104-222-103.lsanca.dsl-w.verizon.net@CFT.CA.US (give password or use -randkey) ank HTTP/pool-71-104-222-103.lsanca.dsl-w.verizon.net@CFT.CA.US ank xmpp/pool-71-104-222-103.lsanca.dsl-w.verizon.net@CFT.CA.US C On the server extract into the keytabs: krb5.keytab host xmpp www2.keytab host HTTP Use this command (in kadmin.local): ktadd -k /etc/krb5/krb5.keytab -norandkey xmpp/pool-71-104-222-103.lsanca.dsl-w.verizon.net@CFT.CA.US (change principal and keytab as appropriate) D To check: ktutil rkt /etc/krb5/krb5.keytab (or www2.keytab) list quit Outcomes: xmpp (pidgin) gets 2 copies of xmpp/pool-...verizon.net@CFT.CA.US (and no host key) and gives an error message of "unacceptable". Asks for a password, which fails. HTTP browser does not get any tickets, falls back to basicoid auth. Likely one problem is that the host keys are differently salted on Xena's KDC than on Jacinth due to lameass propagation. Fixed. But something else is wrong. Testing with Pidgin running on Jacinth. OK, if I specify that the connect server is pool-...verizon.net then it will bitch about the certificate name mismatch but will connect using GSSAPI. If I specify that the connect server is otter.mine.nu it will accept the certificate but will not use GSSAPI, falling back (successfully) to Plain (which is listed as a mechanism in /usr/lib/sasl2/prosody.conf ). The client gets a krb ticket for xmpp/pool-...verizon.net@CFT.CA.US but not for the host. In either case, "c2s_require_encryption = false" is ineffective at non-requiring encryption; the server returns "406 not acceptable, SSL/TLS is required to connect to this server". This is with the cert and key commented out. Same scenario with Pidgin running on Xena (wild side). Configured connect server = /pool-...verizon.net. It bitched about the cert mismatch, got a ticket for xmpp/pool-...verizon.net@CFT.CA.US, then did not use GSSAPI and fell back (successfully) to Plain. (I have addressless tickets.) Scenario table: Server Client Clients Has krb SSL Mech Connect Krb svc cert nm on svr nm ticket bitch Used ticket Otter jacinth jacinth no no Plain Yes -- Otter jacinth jacinth yes no Plain Yes Verizon Otter xena verizon no no Plain Yes -- Otter xena verizon yes no Plain Yes Verizon Otter xena jacinth yes no* GSSAPI Yes jacinth Otter xena otter no no Plain Yes -- Otter xena otter yes no Plain Yes Verizon (Removed xmpp/pool...verizon.net@CFT from krb5.keytab) Otter xena otter yes no Plain Yes Verizon (delprinc xmpp/pool-71-104-222-103.lsanca.dsl-w.verizon.net@CFT.CA.US) Otter xena otter yes no Plain Yes (none) http://xmpp.org/extensions/xep-0178.html XEP-0178 Best practices for using SASL External with certs (in XMPP). This is for PKIX (RFC 5280) certs. ------- Trying simba -> otter. . kinit jimc@CFT.CA.US; /usr/lib/mit/bin/kvno xmpp/otter.mine.nu@CFT.CA.US kinit no problems, but if kvno starts with a UDP packet, otter's UDP reply never comes back, and TCP fallback appears to be a replay so is rejected. But if kvno starts with TCP (udp_preference_limit = 1) the ticket is received. . Starting with just the TGT. Server announces GSSAPI mechanism. Even so, client sends nothing at all to otter's Kerberos and uses Plain auth. This is seen for simba -> otter and xena -> otter. . HOWEVER, xena asks its *OWN* kdc (using IPv6) for xmpp/pool-71-104-222-103.lsanca.dsl-w.verizon.net and doesn't get it. Even though krb5.conf says rdns=false.