Shuyi Chen | d7955ce | 2013-05-22 14:51:55 -0700 | [diff] [blame] | 1 | /**
|
| 2 | * $RCSfile$
|
| 3 | * $Revision$
|
| 4 | * $Date$
|
| 5 | *
|
| 6 | * Copyright 2003-2007 Jive Software.
|
| 7 | *
|
| 8 | * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
|
| 9 | * you may not use this file except in compliance with the License.
|
| 10 | * You may obtain a copy of the License at
|
| 11 | *
|
| 12 | * http://www.apache.org/licenses/LICENSE-2.0
|
| 13 | *
|
| 14 | * Unless required by applicable law or agreed to in writing, software
|
| 15 | * distributed under the License is distributed on an "AS IS" BASIS,
|
| 16 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 17 | * See the License for the specific language governing permissions and
|
| 18 | * limitations under the License.
|
| 19 | */
|
| 20 |
|
| 21 | package org.jivesoftware.smack;
|
| 22 |
|
| 23 | import org.jivesoftware.smack.filter.PacketIDFilter;
|
| 24 | import org.jivesoftware.smack.packet.Bind;
|
| 25 | import org.jivesoftware.smack.packet.IQ;
|
| 26 | import org.jivesoftware.smack.packet.Packet;
|
| 27 | import org.jivesoftware.smack.packet.Session;
|
| 28 | import org.jivesoftware.smack.sasl.*;
|
| 29 |
|
| 30 | import org.apache.harmony.javax.security.auth.callback.CallbackHandler;
|
| 31 | import java.io.IOException;
|
| 32 | import java.lang.reflect.Constructor;
|
| 33 | import java.util.*;
|
| 34 |
|
| 35 | /**
|
| 36 | * <p>This class is responsible authenticating the user using SASL, binding the resource
|
| 37 | * to the connection and establishing a session with the server.</p>
|
| 38 | *
|
| 39 | * <p>Once TLS has been negotiated (i.e. the connection has been secured) it is possible to
|
| 40 | * register with the server, authenticate using Non-SASL or authenticate using SASL. If the
|
| 41 | * server supports SASL then Smack will first try to authenticate using SASL. But if that
|
| 42 | * fails then Non-SASL will be tried.</p>
|
| 43 | *
|
| 44 | * <p>The server may support many SASL mechanisms to use for authenticating. Out of the box
|
| 45 | * Smack provides several SASL mechanisms, but it is possible to register new SASL Mechanisms. Use
|
| 46 | * {@link #registerSASLMechanism(String, Class)} to register a new mechanisms. A registered
|
| 47 | * mechanism wont be used until {@link #supportSASLMechanism(String, int)} is called. By default,
|
| 48 | * the list of supported SASL mechanisms is determined from the {@link SmackConfiguration}. </p>
|
| 49 | *
|
| 50 | * <p>Once the user has been authenticated with SASL, it is necessary to bind a resource for
|
| 51 | * the connection. If no resource is passed in {@link #authenticate(String, String, String)}
|
| 52 | * then the server will assign a resource for the connection. In case a resource is passed
|
| 53 | * then the server will receive the desired resource but may assign a modified resource for
|
| 54 | * the connection.</p>
|
| 55 | *
|
| 56 | * <p>Once a resource has been binded and if the server supports sessions then Smack will establish
|
| 57 | * a session so that instant messaging and presence functionalities may be used.</p>
|
| 58 | *
|
| 59 | * @see org.jivesoftware.smack.sasl.SASLMechanism
|
| 60 | *
|
| 61 | * @author Gaston Dombiak
|
| 62 | * @author Jay Kline
|
| 63 | */
|
| 64 | public class SASLAuthentication implements UserAuthentication {
|
| 65 |
|
| 66 | private static Map<String, Class<? extends SASLMechanism>> implementedMechanisms = new HashMap<String, Class<? extends SASLMechanism>>();
|
| 67 | private static List<String> mechanismsPreferences = new ArrayList<String>();
|
| 68 |
|
| 69 | private Connection connection;
|
| 70 | private Collection<String> serverMechanisms = new ArrayList<String>();
|
| 71 | private SASLMechanism currentMechanism = null;
|
| 72 | /**
|
| 73 | * Boolean indicating if SASL negotiation has finished and was successful.
|
| 74 | */
|
| 75 | private boolean saslNegotiated;
|
| 76 | /**
|
| 77 | * Boolean indication if SASL authentication has failed. When failed the server may end
|
| 78 | * the connection.
|
| 79 | */
|
| 80 | private boolean saslFailed;
|
| 81 | private boolean resourceBinded;
|
| 82 | private boolean sessionSupported;
|
| 83 | /**
|
| 84 | * The SASL related error condition if there was one provided by the server.
|
| 85 | */
|
| 86 | private String errorCondition;
|
| 87 |
|
| 88 | static {
|
| 89 |
|
| 90 | // Register SASL mechanisms supported by Smack
|
| 91 | registerSASLMechanism("EXTERNAL", SASLExternalMechanism.class);
|
| 92 | registerSASLMechanism("GSSAPI", SASLGSSAPIMechanism.class);
|
| 93 | registerSASLMechanism("DIGEST-MD5", SASLDigestMD5Mechanism.class);
|
| 94 | registerSASLMechanism("CRAM-MD5", SASLCramMD5Mechanism.class);
|
| 95 | registerSASLMechanism("PLAIN", SASLPlainMechanism.class);
|
| 96 | registerSASLMechanism("ANONYMOUS", SASLAnonymous.class);
|
| 97 |
|
| 98 | supportSASLMechanism("GSSAPI",0);
|
| 99 | supportSASLMechanism("DIGEST-MD5",1);
|
| 100 | supportSASLMechanism("CRAM-MD5",2);
|
| 101 | supportSASLMechanism("PLAIN",3);
|
| 102 | supportSASLMechanism("ANONYMOUS",4);
|
| 103 |
|
| 104 | }
|
| 105 |
|
| 106 | /**
|
| 107 | * Registers a new SASL mechanism
|
| 108 | *
|
| 109 | * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
|
| 110 | * @param mClass a SASLMechanism subclass.
|
| 111 | */
|
| 112 | public static void registerSASLMechanism(String name, Class<? extends SASLMechanism> mClass) {
|
| 113 | implementedMechanisms.put(name, mClass);
|
| 114 | }
|
| 115 |
|
| 116 | /**
|
| 117 | * Unregisters an existing SASL mechanism. Once the mechanism has been unregistered it won't
|
| 118 | * be possible to authenticate users using the removed SASL mechanism. It also removes the
|
| 119 | * mechanism from the supported list.
|
| 120 | *
|
| 121 | * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
|
| 122 | */
|
| 123 | public static void unregisterSASLMechanism(String name) {
|
| 124 | implementedMechanisms.remove(name);
|
| 125 | mechanismsPreferences.remove(name);
|
| 126 | }
|
| 127 |
|
| 128 |
|
| 129 | /**
|
| 130 | * Registers a new SASL mechanism in the specified preference position. The client will try
|
| 131 | * to authenticate using the most prefered SASL mechanism that is also supported by the server.
|
| 132 | * The SASL mechanism must be registered via {@link #registerSASLMechanism(String, Class)}
|
| 133 | *
|
| 134 | * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
|
| 135 | */
|
| 136 | public static void supportSASLMechanism(String name) {
|
| 137 | mechanismsPreferences.add(0, name);
|
| 138 | }
|
| 139 |
|
| 140 | /**
|
| 141 | * Registers a new SASL mechanism in the specified preference position. The client will try
|
| 142 | * to authenticate using the most prefered SASL mechanism that is also supported by the server.
|
| 143 | * Use the <tt>index</tt> parameter to set the level of preference of the new SASL mechanism.
|
| 144 | * A value of 0 means that the mechanism is the most prefered one. The SASL mechanism must be
|
| 145 | * registered via {@link #registerSASLMechanism(String, Class)}
|
| 146 | *
|
| 147 | * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
|
| 148 | * @param index preference position amongst all the implemented SASL mechanism. Starts with 0.
|
| 149 | */
|
| 150 | public static void supportSASLMechanism(String name, int index) {
|
| 151 | mechanismsPreferences.add(index, name);
|
| 152 | }
|
| 153 |
|
| 154 | /**
|
| 155 | * Un-supports an existing SASL mechanism. Once the mechanism has been unregistered it won't
|
| 156 | * be possible to authenticate users using the removed SASL mechanism. Note that the mechanism
|
| 157 | * is still registered, but will just not be used.
|
| 158 | *
|
| 159 | * @param name common name of the SASL mechanism. E.g.: PLAIN, DIGEST-MD5 or KERBEROS_V4.
|
| 160 | */
|
| 161 | public static void unsupportSASLMechanism(String name) {
|
| 162 | mechanismsPreferences.remove(name);
|
| 163 | }
|
| 164 |
|
| 165 | /**
|
| 166 | * Returns the registerd SASLMechanism classes sorted by the level of preference.
|
| 167 | *
|
| 168 | * @return the registerd SASLMechanism classes sorted by the level of preference.
|
| 169 | */
|
| 170 | public static List<Class<? extends SASLMechanism>> getRegisterSASLMechanisms() {
|
| 171 | List<Class<? extends SASLMechanism>> answer = new ArrayList<Class<? extends SASLMechanism>>();
|
| 172 | for (String mechanismsPreference : mechanismsPreferences) {
|
| 173 | answer.add(implementedMechanisms.get(mechanismsPreference));
|
| 174 | }
|
| 175 | return answer;
|
| 176 | }
|
| 177 |
|
| 178 | SASLAuthentication(Connection connection) {
|
| 179 | super();
|
| 180 | this.connection = connection;
|
| 181 | this.init();
|
| 182 | }
|
| 183 |
|
| 184 | /**
|
| 185 | * Returns true if the server offered ANONYMOUS SASL as a way to authenticate users.
|
| 186 | *
|
| 187 | * @return true if the server offered ANONYMOUS SASL as a way to authenticate users.
|
| 188 | */
|
| 189 | public boolean hasAnonymousAuthentication() {
|
| 190 | return serverMechanisms.contains("ANONYMOUS");
|
| 191 | }
|
| 192 |
|
| 193 | /**
|
| 194 | * Returns true if the server offered SASL authentication besides ANONYMOUS SASL.
|
| 195 | *
|
| 196 | * @return true if the server offered SASL authentication besides ANONYMOUS SASL.
|
| 197 | */
|
| 198 | public boolean hasNonAnonymousAuthentication() {
|
| 199 | return !serverMechanisms.isEmpty() && (serverMechanisms.size() != 1 || !hasAnonymousAuthentication());
|
| 200 | }
|
| 201 |
|
| 202 | /**
|
| 203 | * Performs SASL authentication of the specified user. If SASL authentication was successful
|
| 204 | * then resource binding and session establishment will be performed. This method will return
|
| 205 | * the full JID provided by the server while binding a resource to the connection.<p>
|
| 206 | *
|
| 207 | * The server may assign a full JID with a username or resource different than the requested
|
| 208 | * by this method.
|
| 209 | *
|
| 210 | * @param username the username that is authenticating with the server.
|
| 211 | * @param resource the desired resource.
|
| 212 | * @param cbh the CallbackHandler used to get information from the user
|
| 213 | * @return the full JID provided by the server while binding a resource to the connection.
|
| 214 | * @throws XMPPException if an error occures while authenticating.
|
| 215 | */
|
| 216 | public String authenticate(String username, String resource, CallbackHandler cbh)
|
| 217 | throws XMPPException {
|
| 218 | // Locate the SASLMechanism to use
|
| 219 | String selectedMechanism = null;
|
| 220 | for (String mechanism : mechanismsPreferences) {
|
| 221 | if (implementedMechanisms.containsKey(mechanism) &&
|
| 222 | serverMechanisms.contains(mechanism)) {
|
| 223 | selectedMechanism = mechanism;
|
| 224 | break;
|
| 225 | }
|
| 226 | }
|
| 227 | if (selectedMechanism != null) {
|
| 228 | // A SASL mechanism was found. Authenticate using the selected mechanism and then
|
| 229 | // proceed to bind a resource
|
| 230 | try {
|
| 231 | Class<? extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
|
| 232 | Constructor<? extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
|
| 233 | currentMechanism = constructor.newInstance(this);
|
| 234 | // Trigger SASL authentication with the selected mechanism. We use
|
| 235 | // connection.getHost() since GSAPI requires the FQDN of the server, which
|
| 236 | // may not match the XMPP domain.
|
| 237 | currentMechanism.authenticate(username, connection.getHost(), cbh);
|
| 238 |
|
| 239 | // Wait until SASL negotiation finishes
|
| 240 | synchronized (this) {
|
| 241 | if (!saslNegotiated && !saslFailed) {
|
| 242 | try {
|
| 243 | wait(30000);
|
| 244 | }
|
| 245 | catch (InterruptedException e) {
|
| 246 | // Ignore
|
| 247 | }
|
| 248 | }
|
| 249 | }
|
| 250 |
|
| 251 | if (saslFailed) {
|
| 252 | // SASL authentication failed and the server may have closed the connection
|
| 253 | // so throw an exception
|
| 254 | if (errorCondition != null) {
|
| 255 | throw new XMPPException("SASL authentication " +
|
| 256 | selectedMechanism + " failed: " + errorCondition);
|
| 257 | }
|
| 258 | else {
|
| 259 | throw new XMPPException("SASL authentication failed using mechanism " +
|
| 260 | selectedMechanism);
|
| 261 | }
|
| 262 | }
|
| 263 |
|
| 264 | if (saslNegotiated) {
|
| 265 | // Bind a resource for this connection and
|
| 266 | return bindResourceAndEstablishSession(resource);
|
| 267 | } else {
|
| 268 | // SASL authentication failed
|
| 269 | }
|
| 270 | }
|
| 271 | catch (XMPPException e) {
|
| 272 | throw e;
|
| 273 | }
|
| 274 | catch (Exception e) {
|
| 275 | e.printStackTrace();
|
| 276 | }
|
| 277 | }
|
| 278 | else {
|
| 279 | throw new XMPPException("SASL Authentication failed. No known authentication mechanisims.");
|
| 280 | }
|
| 281 | throw new XMPPException("SASL authentication failed");
|
| 282 | }
|
| 283 |
|
| 284 | /**
|
| 285 | * Performs SASL authentication of the specified user. If SASL authentication was successful
|
| 286 | * then resource binding and session establishment will be performed. This method will return
|
| 287 | * the full JID provided by the server while binding a resource to the connection.<p>
|
| 288 | *
|
| 289 | * The server may assign a full JID with a username or resource different than the requested
|
| 290 | * by this method.
|
| 291 | *
|
| 292 | * @param username the username that is authenticating with the server.
|
| 293 | * @param password the password to send to the server.
|
| 294 | * @param resource the desired resource.
|
| 295 | * @return the full JID provided by the server while binding a resource to the connection.
|
| 296 | * @throws XMPPException if an error occures while authenticating.
|
| 297 | */
|
| 298 | public String authenticate(String username, String password, String resource)
|
| 299 | throws XMPPException {
|
| 300 | // Locate the SASLMechanism to use
|
| 301 | String selectedMechanism = null;
|
| 302 | for (String mechanism : mechanismsPreferences) {
|
| 303 | if (implementedMechanisms.containsKey(mechanism) &&
|
| 304 | serverMechanisms.contains(mechanism)) {
|
| 305 | selectedMechanism = mechanism;
|
| 306 | break;
|
| 307 | }
|
| 308 | }
|
| 309 | if (selectedMechanism != null) {
|
| 310 | // A SASL mechanism was found. Authenticate using the selected mechanism and then
|
| 311 | // proceed to bind a resource
|
| 312 | try {
|
| 313 | Class<? extends SASLMechanism> mechanismClass = implementedMechanisms.get(selectedMechanism);
|
| 314 | Constructor<? extends SASLMechanism> constructor = mechanismClass.getConstructor(SASLAuthentication.class);
|
| 315 | currentMechanism = constructor.newInstance(this);
|
| 316 | // Trigger SASL authentication with the selected mechanism. We use
|
| 317 | // connection.getHost() since GSAPI requires the FQDN of the server, which
|
| 318 | // may not match the XMPP domain.
|
| 319 | currentMechanism.authenticate(username, connection.getServiceName(), password);
|
| 320 |
|
| 321 | // Wait until SASL negotiation finishes
|
| 322 | synchronized (this) {
|
| 323 | if (!saslNegotiated && !saslFailed) {
|
| 324 | try {
|
| 325 | wait(30000);
|
| 326 | }
|
| 327 | catch (InterruptedException e) {
|
| 328 | // Ignore
|
| 329 | }
|
| 330 | }
|
| 331 | }
|
| 332 |
|
| 333 | if (saslFailed) {
|
| 334 | // SASL authentication failed and the server may have closed the connection
|
| 335 | // so throw an exception
|
| 336 | if (errorCondition != null) {
|
| 337 | throw new XMPPException("SASL authentication " +
|
| 338 | selectedMechanism + " failed: " + errorCondition);
|
| 339 | }
|
| 340 | else {
|
| 341 | throw new XMPPException("SASL authentication failed using mechanism " +
|
| 342 | selectedMechanism);
|
| 343 | }
|
| 344 | }
|
| 345 |
|
| 346 | if (saslNegotiated) {
|
| 347 | // Bind a resource for this connection and
|
| 348 | return bindResourceAndEstablishSession(resource);
|
| 349 | }
|
| 350 | else {
|
| 351 | // SASL authentication failed so try a Non-SASL authentication
|
| 352 | return new NonSASLAuthentication(connection)
|
| 353 | .authenticate(username, password, resource);
|
| 354 | }
|
| 355 | }
|
| 356 | catch (XMPPException e) {
|
| 357 | throw e;
|
| 358 | }
|
| 359 | catch (Exception e) {
|
| 360 | e.printStackTrace();
|
| 361 | // SASL authentication failed so try a Non-SASL authentication
|
| 362 | return new NonSASLAuthentication(connection)
|
| 363 | .authenticate(username, password, resource);
|
| 364 | }
|
| 365 | }
|
| 366 | else {
|
| 367 | // No SASL method was found so try a Non-SASL authentication
|
| 368 | return new NonSASLAuthentication(connection).authenticate(username, password, resource);
|
| 369 | }
|
| 370 | }
|
| 371 |
|
| 372 | /**
|
| 373 | * Performs ANONYMOUS SASL authentication. If SASL authentication was successful
|
| 374 | * then resource binding and session establishment will be performed. This method will return
|
| 375 | * the full JID provided by the server while binding a resource to the connection.<p>
|
| 376 | *
|
| 377 | * The server will assign a full JID with a randomly generated resource and possibly with
|
| 378 | * no username.
|
| 379 | *
|
| 380 | * @return the full JID provided by the server while binding a resource to the connection.
|
| 381 | * @throws XMPPException if an error occures while authenticating.
|
| 382 | */
|
| 383 | public String authenticateAnonymously() throws XMPPException {
|
| 384 | try {
|
| 385 | currentMechanism = new SASLAnonymous(this);
|
| 386 | currentMechanism.authenticate(null,null,"");
|
| 387 |
|
| 388 | // Wait until SASL negotiation finishes
|
| 389 | synchronized (this) {
|
| 390 | if (!saslNegotiated && !saslFailed) {
|
| 391 | try {
|
| 392 | wait(5000);
|
| 393 | }
|
| 394 | catch (InterruptedException e) {
|
| 395 | // Ignore
|
| 396 | }
|
| 397 | }
|
| 398 | }
|
| 399 |
|
| 400 | if (saslFailed) {
|
| 401 | // SASL authentication failed and the server may have closed the connection
|
| 402 | // so throw an exception
|
| 403 | if (errorCondition != null) {
|
| 404 | throw new XMPPException("SASL authentication failed: " + errorCondition);
|
| 405 | }
|
| 406 | else {
|
| 407 | throw new XMPPException("SASL authentication failed");
|
| 408 | }
|
| 409 | }
|
| 410 |
|
| 411 | if (saslNegotiated) {
|
| 412 | // Bind a resource for this connection and
|
| 413 | return bindResourceAndEstablishSession(null);
|
| 414 | }
|
| 415 | else {
|
| 416 | return new NonSASLAuthentication(connection).authenticateAnonymously();
|
| 417 | }
|
| 418 | } catch (IOException e) {
|
| 419 | return new NonSASLAuthentication(connection).authenticateAnonymously();
|
| 420 | }
|
| 421 | }
|
| 422 |
|
| 423 | private String bindResourceAndEstablishSession(String resource) throws XMPPException {
|
| 424 | // Wait until server sends response containing the <bind> element
|
| 425 | synchronized (this) {
|
| 426 | if (!resourceBinded) {
|
| 427 | try {
|
| 428 | wait(30000);
|
| 429 | }
|
| 430 | catch (InterruptedException e) {
|
| 431 | // Ignore
|
| 432 | }
|
| 433 | }
|
| 434 | }
|
| 435 |
|
| 436 | if (!resourceBinded) {
|
| 437 | // Server never offered resource binding
|
| 438 | throw new XMPPException("Resource binding not offered by server");
|
| 439 | }
|
| 440 |
|
| 441 | Bind bindResource = new Bind();
|
| 442 | bindResource.setResource(resource);
|
| 443 |
|
| 444 | PacketCollector collector = connection
|
| 445 | .createPacketCollector(new PacketIDFilter(bindResource.getPacketID()));
|
| 446 | // Send the packet
|
| 447 | connection.sendPacket(bindResource);
|
| 448 | // Wait up to a certain number of seconds for a response from the server.
|
| 449 | Bind response = (Bind) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
| 450 | collector.cancel();
|
| 451 | if (response == null) {
|
| 452 | throw new XMPPException("No response from the server.");
|
| 453 | }
|
| 454 | // If the server replied with an error, throw an exception.
|
| 455 | else if (response.getType() == IQ.Type.ERROR) {
|
| 456 | throw new XMPPException(response.getError());
|
| 457 | }
|
| 458 | String userJID = response.getJid();
|
| 459 |
|
| 460 | if (sessionSupported) {
|
| 461 | Session session = new Session();
|
| 462 | collector = connection.createPacketCollector(new PacketIDFilter(session.getPacketID()));
|
| 463 | // Send the packet
|
| 464 | connection.sendPacket(session);
|
| 465 | // Wait up to a certain number of seconds for a response from the server.
|
| 466 | IQ ack = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
|
| 467 | collector.cancel();
|
| 468 | if (ack == null) {
|
| 469 | throw new XMPPException("No response from the server.");
|
| 470 | }
|
| 471 | // If the server replied with an error, throw an exception.
|
| 472 | else if (ack.getType() == IQ.Type.ERROR) {
|
| 473 | throw new XMPPException(ack.getError());
|
| 474 | }
|
| 475 | }
|
| 476 | return userJID;
|
| 477 | }
|
| 478 |
|
| 479 | /**
|
| 480 | * Sets the available SASL mechanism reported by the server. The server will report the
|
| 481 | * available SASL mechanism once the TLS negotiation was successful. This information is
|
| 482 | * stored and will be used when doing the authentication for logging in the user.
|
| 483 | *
|
| 484 | * @param mechanisms collection of strings with the available SASL mechanism reported
|
| 485 | * by the server.
|
| 486 | */
|
| 487 | void setAvailableSASLMethods(Collection<String> mechanisms) {
|
| 488 | this.serverMechanisms = mechanisms;
|
| 489 | }
|
| 490 |
|
| 491 | /**
|
| 492 | * Returns true if the user was able to authenticate with the server usins SASL.
|
| 493 | *
|
| 494 | * @return true if the user was able to authenticate with the server usins SASL.
|
| 495 | */
|
| 496 | public boolean isAuthenticated() {
|
| 497 | return saslNegotiated;
|
| 498 | }
|
| 499 |
|
| 500 | /**
|
| 501 | * The server is challenging the SASL authentication we just sent. Forward the challenge
|
| 502 | * to the current SASLMechanism we are using. The SASLMechanism will send a response to
|
| 503 | * the server. The length of the challenge-response sequence varies according to the
|
| 504 | * SASLMechanism in use.
|
| 505 | *
|
| 506 | * @param challenge a base64 encoded string representing the challenge.
|
| 507 | * @throws IOException If a network error occures while authenticating.
|
| 508 | */
|
| 509 | void challengeReceived(String challenge) throws IOException {
|
| 510 | currentMechanism.challengeReceived(challenge);
|
| 511 | }
|
| 512 |
|
| 513 | /**
|
| 514 | * Notification message saying that SASL authentication was successful. The next step
|
| 515 | * would be to bind the resource.
|
| 516 | */
|
| 517 | void authenticated() {
|
| 518 | synchronized (this) {
|
| 519 | saslNegotiated = true;
|
| 520 | // Wake up the thread that is waiting in the #authenticate method
|
| 521 | notify();
|
| 522 | }
|
| 523 | }
|
| 524 |
|
| 525 | /**
|
| 526 | * Notification message saying that SASL authentication has failed. The server may have
|
| 527 | * closed the connection depending on the number of possible retries.
|
| 528 | *
|
| 529 | * @deprecated replaced by {@see #authenticationFailed(String)}.
|
| 530 | */
|
| 531 | void authenticationFailed() {
|
| 532 | authenticationFailed(null);
|
| 533 | }
|
| 534 |
|
| 535 | /**
|
| 536 | * Notification message saying that SASL authentication has failed. The server may have
|
| 537 | * closed the connection depending on the number of possible retries.
|
| 538 | *
|
| 539 | * @param condition the error condition provided by the server.
|
| 540 | */
|
| 541 | void authenticationFailed(String condition) {
|
| 542 | synchronized (this) {
|
| 543 | saslFailed = true;
|
| 544 | errorCondition = condition;
|
| 545 | // Wake up the thread that is waiting in the #authenticate method
|
| 546 | notify();
|
| 547 | }
|
| 548 | }
|
| 549 |
|
| 550 | /**
|
| 551 | * Notification message saying that the server requires the client to bind a
|
| 552 | * resource to the stream.
|
| 553 | */
|
| 554 | void bindingRequired() {
|
| 555 | synchronized (this) {
|
| 556 | resourceBinded = true;
|
| 557 | // Wake up the thread that is waiting in the #authenticate method
|
| 558 | notify();
|
| 559 | }
|
| 560 | }
|
| 561 |
|
| 562 | public void send(Packet stanza) {
|
| 563 | connection.sendPacket(stanza);
|
| 564 | }
|
| 565 |
|
| 566 | /**
|
| 567 | * Notification message saying that the server supports sessions. When a server supports
|
| 568 | * sessions the client needs to send a Session packet after successfully binding a resource
|
| 569 | * for the session.
|
| 570 | */
|
| 571 | void sessionsSupported() {
|
| 572 | sessionSupported = true;
|
| 573 | }
|
| 574 |
|
| 575 | /**
|
| 576 | * Initializes the internal state in order to be able to be reused. The authentication
|
| 577 | * is used by the connection at the first login and then reused after the connection
|
| 578 | * is disconnected and then reconnected.
|
| 579 | */
|
| 580 | protected void init() {
|
| 581 | saslNegotiated = false;
|
| 582 | saslFailed = false;
|
| 583 | resourceBinded = false;
|
| 584 | sessionSupported = false;
|
| 585 | }
|
| 586 | }
|