KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jivesoftware > messenger > handler > IQRegisterHandler


1 /**
2  * $RCSfile: IQRegisterHandler.java,v $
3  * $Revision: 1.27 $
4  * $Date: 2005/07/16 01:37:54 $
5  *
6  * Copyright (C) 2004 Jive Software. All rights reserved.
7  *
8  * This software is published under the terms of the GNU Public License (GPL),
9  * a copy of which is included in this distribution.
10  */

11
12 package org.jivesoftware.messenger.handler;
13
14 import org.dom4j.DocumentHelper;
15 import org.dom4j.Element;
16 import org.dom4j.QName;
17 import org.jivesoftware.messenger.*;
18 import org.jivesoftware.messenger.auth.UnauthorizedException;
19 import org.jivesoftware.messenger.disco.ServerFeaturesProvider;
20 import org.jivesoftware.messenger.forms.DataForm;
21 import org.jivesoftware.messenger.forms.FormField;
22 import org.jivesoftware.messenger.forms.spi.XDataFormImpl;
23 import org.jivesoftware.messenger.forms.spi.XFormFieldImpl;
24 import org.jivesoftware.messenger.group.GroupManager;
25 import org.jivesoftware.messenger.roster.RosterManager;
26 import org.jivesoftware.messenger.user.User;
27 import org.jivesoftware.messenger.user.UserAlreadyExistsException;
28 import org.jivesoftware.messenger.user.UserManager;
29 import org.jivesoftware.messenger.user.UserNotFoundException;
30 import org.jivesoftware.util.Log;
31 import org.jivesoftware.util.JiveGlobals;
32 import org.xmpp.packet.IQ;
33 import org.xmpp.packet.JID;
34 import org.xmpp.packet.PacketError;
35
36 import java.util.ArrayList JavaDoc;
37 import java.util.Iterator JavaDoc;
38
39 /**
40  * Implements the TYPE_IQ jabber:iq:register protocol (plain only). Clients
41  * use this protocol to register a user account with the server.
42  * A 'get' query runs a register probe to obtain the fields needed
43  * for registration. Return the registration form.
44  * A 'set' query attempts to create a new user account
45  * with information given in the registration form.
46  * <p/>
47  * <h2>Assumptions</h2>
48  * This handler assumes that the request is addressed to the server.
49  * An appropriate TYPE_IQ tag matcher should be placed in front of this
50  * one to route TYPE_IQ requests not addressed to the server to
51  * another channel (probably for direct delivery to the recipient).
52  * <p/>
53
54  * <h2>Compatibility</h2>
55  * The current behavior is designed to emulate jabberd1.4. However
56  * this behavior differs significantly from JEP-0078 (non-SASL registration).
57  * In particular, authentication (IQ-Auth) must return an error when a user
58  * request is made to an account that doesn't exist to trigger auto-registration
59  * (JEP-0078 explicitly recommends against this practice to prevent hackers
60  * from probing for legitimate accounts).
61  *
62  * @author Iain Shigeoka
63  */

64 public class IQRegisterHandler extends IQHandler implements ServerFeaturesProvider {
65
66     private static boolean registrationEnabled;
67     private static boolean canChangePassword;
68     private static Element probeResult;
69
70     private UserManager userManager;
71     private RosterManager rosterManager;
72     private SessionManager sessionManager;
73
74     private IQHandlerInfo info;
75
76     /**
77      * <p>Basic constructor does nothing.</p>
78      */

79     public IQRegisterHandler() {
80         super("XMPP Registration Handler");
81         info = new IQHandlerInfo("query", "jabber:iq:register");
82     }
83
84     public void initialize(XMPPServer server) {
85         super.initialize(server);
86         userManager = server.getUserManager();
87         rosterManager = server.getRosterManager();
88         sessionManager = server.getSessionManager();
89
90         if (probeResult == null) {
91             // Create the basic element of the probeResult which contains the basic registration
92
// information (e.g. username, passoword and email)
93
probeResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:register"));
94             probeResult.addElement("username");
95             probeResult.addElement("password");
96             probeResult.addElement("email");
97             probeResult.addElement("name");
98
99             // Create the registration form to include in the probeResult. The form will include
100
// the basic information plus name and visibility of name and email.
101
// TODO Future versions could allow plugin modules to add new fields to the form
102
XDataFormImpl registrationForm = new XDataFormImpl(DataForm.TYPE_FORM);
103             registrationForm.setTitle("XMPP Client Registration");
104             registrationForm.addInstruction("Please provide the following information");
105
106             XFormFieldImpl field = new XFormFieldImpl("FORM_TYPE");
107             field.setType(FormField.TYPE_HIDDEN);
108             field.addValue("jabber:iq:register");
109             registrationForm.addField(field);
110
111             field = new XFormFieldImpl("username");
112             field.setType(FormField.TYPE_TEXT_SINGLE);
113             field.setLabel("Username");
114             field.setRequired(true);
115             registrationForm.addField(field);
116
117             field = new XFormFieldImpl("name");
118             field.setType(FormField.TYPE_TEXT_SINGLE);
119             field.setLabel("Full name");
120             registrationForm.addField(field);
121
122             field = new XFormFieldImpl("email");
123             field.setType(FormField.TYPE_TEXT_SINGLE);
124             field.setLabel("Email");
125             registrationForm.addField(field);
126
127             field = new XFormFieldImpl("password");
128             field.setType(FormField.TYPE_TEXT_PRIVATE);
129             field.setLabel("Password");
130             field.setRequired(true);
131             registrationForm.addField(field);
132
133             // Add the registration form to the probe result.
134
probeResult.add(registrationForm.asXMLElement());
135         }
136         // See if in-band registration should be enabled (default is true).
137
registrationEnabled = JiveGlobals.getBooleanProperty("register.inband", true);
138         // See if users can change their passwords (default is true).
139
canChangePassword = JiveGlobals.getBooleanProperty("register.password", true);
140     }
141
142     public IQ handleIQ(IQ packet) throws PacketException, UnauthorizedException {
143         ClientSession session = sessionManager.getSession(packet.getFrom());
144         IQ reply = null;
145         // If no session was found then answer an error (if possible)
146
if (session == null) {
147             Log.error("Error during registration. Session not found in " +
148                     sessionManager.getPreAuthenticatedKeys() +
149                     " for key " +
150                     packet.getFrom());
151             // This error packet will probably won't make it through
152
reply = IQ.createResultIQ(packet);
153             reply.setChildElement(packet.getChildElement().createCopy());
154             reply.setError(PacketError.Condition.internal_server_error);
155             return reply;
156         }
157         if (IQ.Type.get.equals(packet.getType())) {
158             // If inband registration is not allowed, return an error.
159
if (!registrationEnabled) {
160                 reply = IQ.createResultIQ(packet);
161                 reply.setChildElement(packet.getChildElement().createCopy());
162                 reply.setError(PacketError.Condition.forbidden);
163             }
164             else {
165                 reply = IQ.createResultIQ(packet);
166                 if (session.getStatus() == Session.STATUS_AUTHENTICATED) {
167                     try {
168                         User user = userManager.getUser(session.getUsername());
169                         Element currentRegistration = probeResult.createCopy();
170                         currentRegistration.addElement("registered");
171                         currentRegistration.element("username").setText(user.getUsername());
172                         currentRegistration.element("password").setText("");
173                         currentRegistration.element("email").setText(user.getEmail());
174                         currentRegistration.element("name").setText(user.getName());
175
176                         Element form = currentRegistration.element(QName.get("x", "jabber:x:data"));
177                         Iterator JavaDoc fields = form.elementIterator("field");
178                         Element field;
179                         while (fields.hasNext()) {
180                             field = (Element) fields.next();
181                             if ("username".equals(field.attributeValue("var"))) {
182                                 field.addElement("value").addText(user.getUsername());
183                             }
184                             else if ("name".equals(field.attributeValue("var"))) {
185                                 field.addElement("value").addText(user.getName());
186                             }
187                             else if ("email".equals(field.attributeValue("var"))) {
188                                 field.addElement("value").addText(user.getEmail());
189                             }
190                         }
191                         reply.setChildElement(currentRegistration);
192                     }
193                     catch (UserNotFoundException e) {
194                         reply.setChildElement(probeResult.createCopy());
195                     }
196                 }
197                 else {
198                     // This is a workaround. Since we don't want to have an incorrect TO attribute
199
// value we need to clean up the TO attribute. The TO attribute will contain an
200
// incorrect value since we are setting a fake JID until the user actually
201
// authenticates with the server.
202
reply.setTo((JID) null);
203                     reply.setChildElement(probeResult.createCopy());
204                 }
205             }
206         }
207         else if (IQ.Type.set.equals(packet.getType())) {
208             try {
209                 Element iqElement = packet.getChildElement();
210                 if (iqElement.element("remove") != null) {
211                     // If inband registration is not allowed, return an error.
212
if (!registrationEnabled) {
213                         reply = IQ.createResultIQ(packet);
214                         reply.setChildElement(packet.getChildElement().createCopy());
215                         reply.setError(PacketError.Condition.forbidden);
216                     }
217                     else {
218                         if (session.getStatus() == Session.STATUS_AUTHENTICATED) {
219                             User user = userManager.getUser(session.getUsername());
220                             // Delete the user
221
userManager.deleteUser(user);
222                             // Delete the roster of the user
223
rosterManager.deleteRoster(session.getAddress());
224                             // Delete the user from all the Groups
225
GroupManager.getInstance().deleteUser(user);
226
227                             reply = IQ.createResultIQ(packet);
228                             session.process(reply);
229                             // Close the user's connection
230
session.getConnection().close();
231                             // The reply has been sent so clean up the variable
232
reply = null;
233                         }
234                         else {
235                             throw new UnauthorizedException();
236                         }
237                     }
238                 }
239                 else {
240                     String JavaDoc username = null;
241                     String JavaDoc password = null;
242                     String JavaDoc email = null;
243                     String JavaDoc name = null;
244                     User newUser = null;
245                     XDataFormImpl registrationForm = null;
246                     FormField field;
247
248                     Element formElement = iqElement.element("x");
249                     // Check if a form was used to provide the registration info
250
if (formElement != null) {
251                         // Get the sent form
252
registrationForm = new XDataFormImpl();
253                         registrationForm.parse(formElement);
254                         // Get the username sent in the form
255
Iterator JavaDoc<String JavaDoc> values = registrationForm.getField("username").getValues();
256                         username = (values.hasNext() ? values.next() : " ");
257                         // Get the password sent in the form
258
field = registrationForm.getField("password");
259                         if (field != null) {
260                             values = field.getValues();
261                             password = (values.hasNext() ? values.next() : " ");
262                         }
263                         // Get the email sent in the form
264
field = registrationForm.getField("email");
265                         if (field != null) {
266                             values = field.getValues();
267                             email = (values.hasNext() ? values.next() : " ");
268                         }
269                         // Get the name sent in the form
270
field = registrationForm.getField("name");
271                         if (field != null) {
272                             values = field.getValues();
273                             name = (values.hasNext() ? values.next() : " ");
274                         }
275                     }
276                     else {
277                         // Get the registration info from the query elements
278
username = iqElement.elementText("username");
279                         password = iqElement.elementText("password");
280                         email = iqElement.elementText("email");
281                         name = iqElement.elementText("name");
282                     }
283                     if (email == null || "".equals(email)) {
284                         email = " ";
285                     }
286
287                     if (session.getStatus() == Session.STATUS_AUTHENTICATED) {
288                         // Flag that indicates if the user is *only* changing his password
289
boolean onlyPassword = false;
290                         if (iqElement.elements().size() == 2 &&
291                                 iqElement.element("username") != null &&
292                                 iqElement.element("password") != null) {
293                             onlyPassword = true;
294                         }
295                         // If users are not allowed to change their password, return an error.
296
if (password != null && !canChangePassword) {
297                             reply = IQ.createResultIQ(packet);
298                             reply.setChildElement(packet.getChildElement().createCopy());
299                             reply.setError(PacketError.Condition.forbidden);
300                             return reply;
301                         }
302                         // If inband registration is not allowed, return an error.
303
else if (!onlyPassword && !registrationEnabled) {
304                             reply = IQ.createResultIQ(packet);
305                             reply.setChildElement(packet.getChildElement().createCopy());
306                             reply.setError(PacketError.Condition.forbidden);
307                             return reply;
308                         }
309                         else {
310                             User user = userManager.getUser(session.getUsername());
311                             if (user != null) {
312                                 if (user.getUsername().equalsIgnoreCase(username)) {
313                                     if (password != null && password.trim().length() > 0) {
314                                         user.setPassword(password);
315                                     }
316                                     if (!onlyPassword) {
317                                         user.setEmail(email);
318                                     }
319                                     newUser = user;
320                                 }
321                                 else {
322                                     // An admin can create new accounts when logged in.
323
newUser = userManager.createUser(username, password, null, email);
324                                 }
325                             }
326                             else {
327                                 throw new UnauthorizedException();
328                             }
329                         }
330                     }
331                     else {
332                         // If inband registration is not allowed, return an error.
333
if (!registrationEnabled) {
334                             reply = IQ.createResultIQ(packet);
335                             reply.setChildElement(packet.getChildElement().createCopy());
336                             reply.setError(PacketError.Condition.forbidden);
337                             return reply;
338                         }
339                         // Inform the entity of failed registration if some required
340
// information was not provided
341
else if (password == null || password.trim().length() == 0) {
342                             reply = IQ.createResultIQ(packet);
343                             reply.setChildElement(packet.getChildElement().createCopy());
344                             reply.setError(PacketError.Condition.not_acceptable);
345                             return reply;
346                         }
347                         else {
348                             // Create the new account
349
newUser = userManager.createUser(username, password, null, email);
350                         }
351                     }
352                     // Set and save the extra user info (e.g. full name, etc.)
353
if (newUser != null && name != null) {
354                         newUser.setName(name);
355                     }
356
357                     reply = IQ.createResultIQ(packet);
358                 }
359             }
360             catch (UserAlreadyExistsException e) {
361                 reply = IQ.createResultIQ(packet);
362                 reply.setChildElement(packet.getChildElement().createCopy());
363                 reply.setError(PacketError.Condition.conflict);
364             }
365             catch (UserNotFoundException e) {
366                 reply = IQ.createResultIQ(packet);
367                 reply.setChildElement(packet.getChildElement().createCopy());
368                 reply.setError(PacketError.Condition.bad_request);
369             }
370             catch (IllegalArgumentException JavaDoc e) {
371                 // The specified username is not correct according to the stringprep specs
372
reply = IQ.createResultIQ(packet);
373                 reply.setChildElement(packet.getChildElement().createCopy());
374                 reply.setError(PacketError.Condition.jid_malformed);
375             }
376             catch (UnsupportedOperationException JavaDoc e) {
377                 // The User provider is read-only so this operation is not allowed
378
reply = IQ.createResultIQ(packet);
379                 reply.setChildElement(packet.getChildElement().createCopy());
380                 reply.setError(PacketError.Condition.not_allowed);
381             }
382             catch (Exception JavaDoc e) {
383                 // Some unexpected error happened so return an internal_server_error
384
reply = IQ.createResultIQ(packet);
385                 reply.setChildElement(packet.getChildElement().createCopy());
386                 reply.setError(PacketError.Condition.internal_server_error);
387                 Log.error(e);
388             }
389         }
390         if (reply != null) {
391             // why is this done here instead of letting the iq handler do it?
392
session.process(reply);
393         }
394         return null;
395     }
396
397     public boolean isInbandRegEnabled() {
398         return registrationEnabled;
399     }
400
401     public void setInbandRegEnabled(boolean allowed) {
402         registrationEnabled = allowed;
403         JiveGlobals.setProperty("register.inband", registrationEnabled ? "true" : "false");
404     }
405
406     public boolean canChangePassword() {
407         return canChangePassword;
408     }
409
410     public void setCanChangePassword(boolean allowed) {
411         canChangePassword = allowed;
412         JiveGlobals.setProperty("register.password", canChangePassword ? "true" : "false");
413     }
414
415     public IQHandlerInfo getInfo() {
416         return info;
417     }
418
419     public Iterator JavaDoc getFeatures() {
420         ArrayList JavaDoc features = new ArrayList JavaDoc();
421         features.add("jabber:iq:register");
422         return features.iterator();
423     }
424 }
425
Popular Tags