Source code: edu/ou/kmi/buddyspace/core/BSAuthorizationBean.java
1 package edu.ou.kmi.buddyspace.core;
2
3 /*
4 * BSAuthorizationBean.java
5 *
6 * Project: BuddySpace
7 * (C) Copyright Knowledge Media Institute 2002
8 *
9 *
10 * Created on 16 July 2002, 11:49
11 */
12
13 import java.util.*;
14 import org.jabber.jabberbeans.*;
15 import org.jabber.jabberbeans.util.*;
16 import org.jabber.jabberbeans.Extension.*;
17
18 /**
19 * <code>BSAuthorizationBean</code> provides athentication handling.
20 * It relies on <code>BSInfoQueryBean</code>, which must be set after each
21 * reconnection.
22 *
23 * @author Jiri Komzak, Knowledge Media Institute, Open University, United Kingdom
24 */
25 public class BSAuthorizationBean implements PacketListener {
26 private IQBean iqBean = null;
27 private BSAuthState state;
28 private String user = null;
29 private String password = null;
30 private String resource = null;
31 private final String name = "Authorization";
32 private Vector authListeners;
33
34 /**
35 * Constructor
36 */
37 BSAuthorizationBean() {
38 state = new BSAuthState();
39 state.value = BSAuthState.NOT_AUTHORIZED;
40 authListeners = new Vector();
41 }
42
43 /**
44 * Constructor, which sets existing and connected <code>IQBean</code>.
45 * Then this is registered as listener for IQ packets.
46 */
47 BSAuthorizationBean(IQBean iqBean) {
48 this();
49 setIQBean(iqBean);
50 }
51
52 /**
53 * Sets existing and connected <code>IQBean</code>.
54 * Then this is registered as listener for IQ packets.
55 */
56 protected void setIQBean(IQBean iqBean) {
57 if (this.iqBean != null)
58 this.iqBean.delPacketListener(this);
59 this.iqBean = iqBean;
60 if (iqBean != null)
61 iqBean.addPacketListener(this);
62
63 state.value = BSAuthState.NOT_AUTHORIZED;
64 state.servedID = null;
65 state.jid = null;
66 }
67
68 /**
69 * Returns currently used <code>IQBean</code>.
70 */
71 protected IQBean getIQBean() {
72 return iqBean;
73 }
74
75 /**
76 * Frees all object bindings to allow object destroy
77 */
78 protected void prepareToDestroy() {
79 removeAllAuthListeners();
80 if (iqBean != null)
81 iqBean.delPacketListener(this);
82 iqBean = null;
83 }
84
85 /**
86 * Sets current state in authentication process.
87 */
88 private void setState(JID jid, int state, String id) {
89 this.state.value = state;
90 this.state.jid = jid;
91 this.state.servedID = id;
92 notifyAuthListeners(new BSAuthEvent(this, state));
93 }
94
95 /**
96 * Invokes authentication of given <code>user</code>.
97 */
98 protected void authorize(String user, String password, String resource) {
99 this.user = user;
100 this.password = password;
101 this.resource = resource;
102
103 // returns when not set properly
104 if (iqBean == null || iqBean.getConnection() == null) {
105 BSCore.logEvent(name, "error: not connected");
106 setState(null, BSAuthState.NOT_AUTHORIZED, null);
107 return;
108 }
109
110 // starts loging in
111 String id = new String("BS_AUTH_" + String.valueOf(BSCore.getNextID()));
112 setState(null, BSAuthState.AUTHORIZING1, id);
113 InfoQueryBuilder iqBuilder = new InfoQueryBuilder();
114 IQAuthBuilder iqAuthBuilder = new IQAuthBuilder();
115 iqAuthBuilder.setUsername(user);
116
117 try {
118 iqBuilder.addExtension(iqAuthBuilder.build());
119 iqBuilder.setType("get");
120 iqBuilder.setIdentifier(id);
121 //iqBean.send((InfoQuery)iqBuilder.build());
122 iqBean.getConnection().send(iqBuilder.build());
123 } catch (InstantiationException e) {
124 BSCore.logEvent(name, "error: IQ builder failed");
125 setState(null, BSAuthState.NOT_AUTHORIZED, null);
126 }
127
128 BSCore.logEvent(name, "authentication phase 1");
129 }
130
131 /**
132 * Sends user information including password.
133 * This is done during the second phase of authentication process.
134 */
135 private void sendPassword(IQAuth extension) {
136
137 // should ask user for the info according to extension
138
139 this.sendPassword(user, password, resource);
140 }
141
142 /**
143 * Sends user information including password.
144 * This way the first phase when asking for required data is omitted
145 * and data is sent directly.
146 */
147 protected void sendPassword(String user, String password, String resource) {
148 this.user = user;
149 this.password = password;
150 this.resource = resource;
151
152 // returns when not set properly
153 if (iqBean == null || iqBean.getConnection() == null) {
154 BSCore.logEvent(name, "error: not connected");
155 setState(null, BSAuthState.NOT_AUTHORIZED, null);
156 return;
157 }
158 // sends the authorization request
159 //eventsTextArea.append("RECEIVED: iq auth result\n");
160 String id = new String("BS_AUTH_" + String.valueOf(BSCore.getNextID()));
161 setState(null, BSAuthState.AUTHORIZING2, id);
162 InfoQueryBuilder iqBuilder = new InfoQueryBuilder();
163 IQAuthBuilder iqAuthBuilder = new IQAuthBuilder();
164 iqAuthBuilder.setUsername(user);
165 iqAuthBuilder.setPassword(password);
166 iqAuthBuilder.setResource(resource);
167
168 try {
169 iqBuilder.addExtension(iqAuthBuilder.build());
170 iqBuilder.setType("set");
171 iqBuilder.setIdentifier(id);
172 //iqBean.send((InfoQuery)iqBuilder.build());
173 iqBean.getConnection().send(iqBuilder.build());
174 } catch (InstantiationException e) {
175 BSCore.logEvent(name, "error: IQ builder failed");
176 setState(null, BSAuthState.NOT_AUTHORIZED, null);
177 return;
178 }
179
180 // will wait for auth response
181 BSCore.logEvent(name, "authentication phase 2");
182 }
183
184 // *** packet handling ***
185
186 /**
187 * Invoked when a IQ packet is received.
188 */
189 public void receivedPacket(PacketEvent pe) {
190 if (!(pe.getPacket() instanceof InfoQuery)) {
191 BSCore.logEvent(name, "warning: nonIQ packet received");
192 return;
193 }
194
195 InfoQuery iq = (InfoQuery) pe.getPacket();
196 //if no ID or packet with that ID not expected
197 if (state.servedID == null || !state.servedID.equals(iq.getIdentifier())) {
198 return;
199 }
200
201 if ((new String("result")).equals(iq.getType()))
202 handleResult(iq);
203 else if ((new String("error")).equals(iq.getType()))
204 handleError(iq);
205 else if ((new String("set")).equals(iq.getType()))
206 handleSet(iq);
207 }
208
209 /**
210 * Invoked when a IQ packet send failes.
211 */
212 public void sendFailed(PacketEvent pe) {
213 }
214
215 /**
216 * Invoked when a IQ packet is sent.
217 */
218 public void sentPacket(PacketEvent pe) {
219 }
220
221 // *** infoQuery handling ***
222
223 /**
224 * Handles <code>InfoQuery</code> packet, if it does contain an error.
225 * Before this is called it checks if that is response on the sent IQ
226 * authentication packet.
227 */
228 private void handleError(InfoQuery iq) {
229 BSCore.logEvent(name, "error " + iq.getErrorCode() + ": " + iq.getErrorText());
230 setState(null, BSAuthState.NOT_AUTHORIZED, null);
231 }
232
233 /**
234 * Handles <code>InfoQuery</code> packet, if it does contain a result.
235 * Before this is called it checks if that is response on the sent IQ
236 * authentication packet.
237 */
238 private void handleResult(InfoQuery iq) {
239 Enumeration extensions = iq.Extensions();
240
241 // when in first phase of authentication
242 if (state.value == BSAuthState.AUTHORIZING1) {
243 while (extensions != null && extensions.hasMoreElements()) {
244 Extension ext = (Extension) extensions.nextElement();
245 if (ext instanceof IQAuth)
246 sendPassword((IQAuth)ext);
247 else {
248 BSCore.logEvent(name, "error: unexpected IQ extension");
249 setState(null, BSAuthState.NOT_AUTHORIZED, null);
250 }
251 }
252 }
253
254 // when in second phase of authentication
255 else if (state.value == BSAuthState.AUTHORIZING2) {
256 if (extensions == null || !extensions.hasMoreElements()) {
257 BSCore.logEvent(name, "authenticated");
258 setState(null, BSAuthState.AUTHORIZED, null);
259 }
260 else {
261 BSCore.logEvent(name, "error: IQ extension not expected");
262 setState(null, BSAuthState.NOT_AUTHORIZED, null);
263 }
264 }
265
266 else {
267 BSCore.logEvent(name, "error: unexpected IQ result");
268 //servedID = null;
269 //setState(BSAuthState.NOT_AUTHORIZED);
270 }
271 }
272
273 /**
274 * Handles <code>InfoQuery</code> packet, if it IQ-set.
275 * Before this is called it checks if that is response on the sent IQ
276 * authentication packet.
277 */
278 private void handleSet(InfoQuery iq) {
279 return;
280 }
281
282 /**
283 * Invoked when authentication succeeded.
284 */
285 private void authorized() {
286 return;
287 }
288
289 // *** authorization listeners ***
290 /**
291 * Adds <code>BSAuthListener</code> to listeners notified when
292 * authentication state changes.
293 *
294 * @see #removeAuthListener
295 * @see #removeAllAuthListeners
296 * @see #notifyAuthListeners
297 */
298 public void addAuthListener(BSAuthListener listener) {
299 //assert listener != null : listener;
300 if (listener == null) return;
301 if (!authListeners.contains(listener)) {
302 authListeners.addElement(listener);
303 }
304 }
305
306 /**
307 * Removes <code>BSAuthListener</code> to listeners notified when
308 * authentication state changes.
309 *
310 * @see #addAuthListener
311 * @see #removeAllAuthListeners
312 * @see #notifyAuthListeners
313 */
314 public void removeAuthListener(BSAuthListener listener) {
315 //assert listener != null : listener;
316 if (listener == null) return;
317 authListeners.removeElement(listener);
318 }
319
320 /**
321 * Removes all listeners notified when authentication state changes.
322 * This can be used before to free dependencies and allow dispose of
323 * all objects.
324 *
325 * @see #addAuthListener
326 * @see #removeAuthListener
327 * @see #notifyAuthListeners
328 */
329 public void removeAllAuthListeners() {
330 authListeners.clear();
331 }
332
333 /**
334 * Notifies authentication listeners when
335 * authentication state changes.
336 *
337 * @see #addAuthListeners
338 * @see #removeAuthListener
339 * @see #removeAllAuthListeners
340 */
341 private void notifyAuthListeners(BSAuthEvent ae) {
342 for (Enumeration e = authListeners.elements(); e.hasMoreElements(); ) {
343 BSAuthListener listener = (BSAuthListener) e.nextElement();
344
345 switch (ae.getState().value) {
346 case BSAuthState.NOT_AUTHORIZED:
347 listener.authError(ae);
348 break;
349
350 case BSAuthState.AUTHORIZING1:
351 case BSAuthState.AUTHORIZING2:
352 listener.authorizing(ae);
353 break;
354
355 case BSAuthState.AUTHORIZED:
356 listener.authorized(ae);
357 break;
358 }
359 }
360 }
361
362 }