User Registration

User registration with a Jabber server specifically means the creation (or modification) of a user account for the JSM component - the component that provides the basic IM services and has a notion of users and user sessions. It takes place at the start of a connection to a Jabber server, as does user authentication, as shown in Figure 6-1.

Let's take a look at the XML fragments involved in a typical user registration process. Example 6-1 shows the XML stream header exchange and the IQ packets in the jabber:iq:register namespace.

Example 6-1. A typical user registration process

First, the XML stream header exchange

SEND: <?xml version='1.0'?>
      <stream:stream to='yak' xmlns='jabber:client'
                     xmlns:stream='http://etherx.jabber.org/streams'>

RECV: <?xml version='1.0'?>
      <stream:stream xmlns:stream='http://etherx.jabber.org/streams'
                     id='3B2DB1A7' xmlns='jabber:client' from='yak'>

Then the client sends a request to discover what information must be passed to the Jabber server to register a new user:

SEND: <iq type='get'>
        <query xmlns='jabber:iq:register'/>
      </iq>

RECV: <iq type='result'>
        <query xmlns='jabber:iq:register'>
          <instructions>
            Choose a username and password to register with this server.
          </instructions>
          <name/>
          <email/>
          <username/>
          <password/>
        </query>
      </iq>

The client does as asked, and sends the required information, which results in a successful new user registration:

SEND: <iq type='set'>
        <query xmlns='jabber:iq:register'>
          <username>leslie</username>
          <password>secret</password>
          <email>lel@plevna.com</email>
          <name>Leslie Hawke</name>
        </query>
      </iq>

RECV: <iq type='result'/>

Configuration and Module Load Directives

Lets start by reviewing the relevant configuration in jabber.xml. User registration is a JSM feature, and we find two places of interest in that component instance definition. The first is in that instance's configuration, in the section qualified by the jabber:config:jsm namespace:

<register notify="yes">
  <instructions>
    Choose a username and password to register with this server.
  </instructions>
  <name/>
  <email/>
</register>

The second is in that instance's connection method, showing the mod_register module being loaded. The module plays a major part in handling the registration process, but there are others too, as we will see.

<load main="jsm">
  <jsm>./jsm/jsm.so</jsm>
  <mod_echo>./jsm/jsm.so</mod_echo>
  <mod_roster>./jsm/jsm.so</mod_roster>
  <mod_time>./jsm/jsm.so</mod_time>
  <mod_vcard>./jsm/jsm.so</mod_vcard>
  <mod_last>./jsm/jsm.so</mod_last>
  <mod_version>./jsm/jsm.so</mod_version>
  <mod_announce>./jsm/jsm.so</mod_announce>
  <mod_agents>./jsm/jsm.so</mod_agents>
  <mod_browse>./jsm/jsm.so</mod_browse>
  <mod_admin>./jsm/jsm.so</mod_admin>
  <mod_filter>./jsm/jsm.so</mod_filter>
  <mod_offline>./jsm/jsm.so</mod_offline>
  <mod_presence>./jsm/jsm.so</mod_presence>
  <mod_auth_plain>./jsm/jsm.so</mod_auth_plain>
  <mod_auth_digest>./jsm/jsm.so</mod_auth_digest>
  <mod_auth_0k>./jsm/jsm.so</mod_auth_0k>
  <mod_log>./jsm/jsm.so</mod_log>
  <mod_register>./jsm/jsm.so</mod_register>
  <mod_xml>./jsm/jsm.so</mod_xml>
</load>

The <register/> configuration section looks familiar - the contents are very similar to the IQ result returned in response to the IQ get in the jabber:iq:register namespace in Example 6-1. Indeed, to respond to an IQ get, the mod_register module looks for this <register/> section and formulates the contents into a reply, making a simple modification as it goes - it appends tags for the the two fields

<username/>

and

<password/>

as these two are always required, regardless of configuration.

Removing the <register/> section from the configuration effectively blocks the registration process, and returns an appropriate error to the user:

SEND: <iq type='get'>
        <query xmlns='jabber:iq:register'/>
      </iq>

RECV: <iq type='error'>
        <query xmlns='jabber:iq:register'/>
        <error code='501'>Not Implemented</error>
      </iq>

Removing the reference to the mod_register module from the component instance's connection method:

<!--
  <mod_register>./jsm/jsm.so</mod_register>
-->

has the same effect.

Step by Step

Taking the stream contents in Example 6-1 step by step, what do we see?

The XML Stream Header Exchange

The XML declaration that is send immediately preceding the opening <stream:stream/> root tag is optional. The Jabber server does not enforce its presence, and so you can leave it out if you wish. [1] The Jabber server will always send one in response, however. In both cases - both streamed XML documents - the encoding is assumed to be UTF-8.

For the most part, the rest of the <stream:stream/> root tag is static. The namespace qualifying the stream content is jabber:client (which is the only namespace acceptable when making such an XML stream connection to the c2s (Client to Server) component listening on port 5222), and the namespace qualifying the stream itself is fixed at http://etherx.jabber.org/streams. [2]

The only think that is going to be dynamic is the to attribute, which is used to specify the Jabber server name. Note that this is the internal name of the Jabber server. In our example we've already resolved the physical hostname 'yak' and connected to port 5222; the to attribute is to specify the virtual Jabber host, which in many cases - including an out-of-the-box jabber.xml configuration - is the same as the physical host.

If our Jabber server has just a single virtual host, we can use an <alias/> configuration tag in the c2s component instance configuration, as described in Chapter 5, to remove the requirement of specifying the to attribute:

<alias to='yak'/>

in the configuration section for the c2s instance will set the default alias to 'yak' and indeed override any value specified in the to attribute.

The Query

While all the examples in this book follow the convention that the opening tag name used in an IQ extension is 'query', we know from the section called IQ Subelements in Chapter 5 that in this case, the tag name must be 'query' and nothing else. This is due to the way that the XML is parsed by the Jabber server at this early stage in the connection. The same is true for the user authorization case too.

'Required' Fields?

The list of fields returned in the response to the IQ get in the jabber:iq:register namespace:

<name/>
<email/>
<username/>
<password/>

is actually supposed to be a list of mandatory fields. However, with the current version of the Jabber server (1.4.1, which is our reference version for this book), this is not the case.

The two fields <username/> and <password/> are mandatory; not supplying, or supplying an invalid username or password will result in an error:

SEND: <iq type='set'>
        <query xmlns='jabber:iq:register'>
          <username>leslie</username>
          <email>lel@plevna.com</email>
          <name>Leslie Hawke</name>
        </query>
      </iq>

RECV: <iq type='error'>
        <query xmlns='jabber:iq:register'>
          <username>leslie</username>
          <email>lel@plevna.com</email>
          <name>Leslie Hawke</name>
        </query>
        <error code='406'>Not Acceptable</error>
      </iq>

However, currently, not supplying any of the other fields - the fields that are specified in the <register/> section of the JSM instance's configuration - will not result in an error. This may be fixed in a later release. In any case, it's no great loss; the details are simply stored in the user's spool file on the server, and right now there's only one situation where this information is subsequently used - in answering a browse request made to a user's JID, the server looks up the <name/> tag from the registration data stored, and uses the value there in the browse response:

SEND: <iq type='get' to='dj@yak'>
        <query xmlns='jabber:iq:browse'/>
      </iq>

RECV: <iq type='result' from='dj@yak' to='sabine@yak/Work'>
        <user name='DJ Adams' xmlns='jabber:iq:browse' jid='dj@yak'/>
      </iq>

Set Without Get

In many of the examples of IQ throughout the book, we've seen a standard pattern: IQ get -> IQ result -> IQ set -> IQ result. This pattern isn't any different here, but it's not essential. Bearing in mind that registration field requirements aren't going to change that often, and even if they do, the only ones that are enforced are <username/> and <password/>, you can get away with forgoing the IQ get and cutting straight to the chase with an IQ set. This isn't a recommendation to do that, merely an observation, as it's always good practise to "ask first".

Still No Connection

After registering a new user, note that there's still no session. Only after successful authorization (see later in this Chapter) is a session created. Although used in authentication (and so implicitly in session creation), the value of the id attribute in the XML stream header returned by the server (which has the value '3B2DB1A7' in Example 6-1) is a connection id, not a session id.

So, what can we do at this stage? Well, one of two things. Register another user (yes!) or proceed to the authentication stage. Basically, reaching the end of the registration process, we're back where we started - a 'raw' connection where only one of two sequences are valid - the jabber:iq:register or jabber:iq:auth sequences.

Passwords

You may be wondering about the plaintext nature of the password sent in the registration process. Although the Jabber server offers different types of password-based authentication, there's a 'bootstrap' process required to get the password to the server in the first place. There's no way round the fact that the server must at one time receive the password in all its plaintext glory. After receiving it, there are authentication processes that don't use the plaintext password again.

So if you're concerned about the security of this registration phase, consider doing it over a secure (SSL) connection to the server.

We will look at the detail of the different authentication mechanisms later in this Chapter; however it is worth noting here, in the context of the registration process, that the JSM modules that implement the mechanism are responsible for storing the password when it's received. The mod_register module actually 'registers' the user, but it is the mod_auth_plain and mod_auth_0k modules that actually store the password when received. [3]

There's another occasion where passwords are stored, and that is when a user wishes to change their password. This procedure is also covered by the jabber:iq:register namespace, albeit in a different context - the context of a session. While a jabber:iq:register-based IQ conversation outside the context of a session is for registering a user, a similar conversation within the context of a session, that is, after a user has authenticated, is used to change the user's password. Among other reasons, this is for security - a session context implies the user has identified and authenticated himself, and so has the authority to change the password.

Example 6-2 shows a typical IQ set to change a password.

Example 6-2. Changing a password with jabber:iq:register

SEND: <iq type='set' id='pass_4' to='yak'>
        <query xmlns='jabber:iq:register'>
          <password>newsecret</password>
        </query>
      </iq>

RECV: <iq type='result' id='pass_4' from='yak' to='dj@yak/Work'/>

The to attribute is required here, to make sure the query is handled by the server itself. We can also see evidence that the context of this exchange is within a session in the value of the to attribute on the IQ result packet - the JID 'dj@yak/Work' includes a resource suffix, which implies a session (a resource must be specified in the authentication process - see later in this Chapter). And the specification of a <username/> is not necessary, as the server will stamp the incoming IQ set anyway with the JID associated with the user's session.

If you had made an IQ get, as recommended above, before doing the IQ set to change the password, the result would have looked like this:

RECV: <iq type='result' to='dj@yak/Work' id='pass_2' from='yak'>
        <query xmlns='jabber:iq:register'>
          <password/>
          <instructions>
            Choose a username and password to register with this server.
          </instructions>
          <name/>
          <email/>
          <key>9a6957b7f69535274afa5c134fb4d916c5d5c20b</key>
          <registered/>
        </query>
      </iq>

We see that, as in the registration IQ get outside the session context, the contents of the <register/> section of the JSM instance's configuration have been inserted (the <instructions/>, <name/> and <email/> tags). Additionally, we have a <key/> tag, as a simple security token as described in the section called IQ Subelements in Chapter 5, and a <registered/> tag. The <key/> is not actually checked in the current implementation, and is therefore not necessary to supply in the return IQ set packet. And the <register/> tag is merely a flag telling us that the user is already registered.

Use of the jabber:iq:register namespace in conversation with the JSM in a session context is not limited to changing passwords; you can modify the rest of the registration details supplied when the user was created - in this case, the <name/> and <email/> information. In fact, with the current implementation, because of the lack of checks, you can specify your own fields in the jabber:iq:register IQ set, in both contexts. But don't do it; it's a habit that will probably be impossible to keep up in later releases of the server. [4]

It almost goes without saying that because IQs in the jabber:iq:register namespace are handled differently in a session context, you can't register a new user once your session has started; you must end it. To end it, the XML stream must be closed with a </stream:stream>, and a new connection and stream must then be created.

Reversing a User Registration

The opposite of registering a user is unregistering a user. This is not the same as removing that user altogether. When the <remove/> tag, described in the section called jabber:iq:register in Chapter 5a, is used in a jabber:iq:register qualified IQ set during a user session, the user is unregistered. That is, all the information held in the user's spool file is removed. But the spool file itself is not removed until the Jabber server is shut down. This means that even if you <remove/> a user, the username will still exist until the server is cycled, causing an error if the same username is used in a new registration attempt:

RECV: <iq type='error'>
        <query xmlns='jabber:iq:register'>
          <username>dj</username>
          <password>secret</password>
        </query>
        <error code='409'>Username Not Available</error>
      </iq>

This may well be fixed in a later release of the Jabber server.

A Note On Error Messages

There are various errors that can occur during user registration. They are on the whole fairly plain and easy to understand. But because of the way the server has been written, you might be surprised at what error message you receive in certain circumstances.

Because the required fields <username/> and <password/> are checked before looking to see whether or not there is a <register/> section in the JSM instance configuration, you will always receive a 406 'Not Acceptable' instead of a 501 'Not Implemented' if you don't supply those fields.

Likewise, if you specify a username that already exists, you will receive a 409 'Username Not Available' instead of a 501 'Not Implemented'.

Of course, if you do an IQ get with the jabber:iq:register namespace beforehand, you will receive the 'correct' error - good practise pays!

Notes

[1]

This may not seem like a big deal, but when you're testing against a Jabber server using telnet, it's 20 less characters that you have to type every time you create a new connection ;-)

[2]

The name 'etherx' comes from an old library that implemented XML streams.

[3]

The mod_auth_digest module doesn't play a password-storing role, as the mechanism it provides uses the plaintext password that is stored by mod_auth_plain

[4]

And no, you can't spoof someone else by specifying the <username/> tag in a session context jabber:iq:register IQ set; it is ignored, the correct JID being taken from the from attribute stamp made as the packet hits the server.