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.