/** | |
* $RCSfile$ | |
* $Revision$ | |
* $Date$ | |
* | |
* Copyright 2003-2007 Jive Software. | |
* | |
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
package org.jivesoftware.smack; | |
import org.jivesoftware.smack.filter.PacketIDFilter; | |
import org.jivesoftware.smack.packet.Authentication; | |
import org.jivesoftware.smack.packet.IQ; | |
import org.apache.harmony.javax.security.auth.callback.CallbackHandler; | |
import org.apache.harmony.javax.security.auth.callback.PasswordCallback; | |
import org.apache.harmony.javax.security.auth.callback.Callback; | |
/** | |
* Implementation of JEP-0078: Non-SASL Authentication. Follow the following | |
* <a href=http://www.jabber.org/jeps/jep-0078.html>link</a> to obtain more | |
* information about the JEP. | |
* | |
* @author Gaston Dombiak | |
*/ | |
class NonSASLAuthentication implements UserAuthentication { | |
private Connection connection; | |
public NonSASLAuthentication(Connection connection) { | |
super(); | |
this.connection = connection; | |
} | |
public String authenticate(String username, String resource, CallbackHandler cbh) throws XMPPException { | |
//Use the callback handler to determine the password, and continue on. | |
PasswordCallback pcb = new PasswordCallback("Password: ",false); | |
try { | |
cbh.handle(new Callback[]{pcb}); | |
return authenticate(username, String.valueOf(pcb.getPassword()),resource); | |
} catch (Exception e) { | |
throw new XMPPException("Unable to determine password.",e); | |
} | |
} | |
public String authenticate(String username, String password, String resource) throws | |
XMPPException { | |
// If we send an authentication packet in "get" mode with just the username, | |
// the server will return the list of authentication protocols it supports. | |
Authentication discoveryAuth = new Authentication(); | |
discoveryAuth.setType(IQ.Type.GET); | |
discoveryAuth.setUsername(username); | |
PacketCollector collector = | |
connection.createPacketCollector(new PacketIDFilter(discoveryAuth.getPacketID())); | |
// Send the packet | |
connection.sendPacket(discoveryAuth); | |
// Wait up to a certain number of seconds for a response from the server. | |
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); | |
if (response == null) { | |
throw new XMPPException("No response from the server."); | |
} | |
// If the server replied with an error, throw an exception. | |
else if (response.getType() == IQ.Type.ERROR) { | |
throw new XMPPException(response.getError()); | |
} | |
// Otherwise, no error so continue processing. | |
Authentication authTypes = (Authentication) response; | |
collector.cancel(); | |
// Now, create the authentication packet we'll send to the server. | |
Authentication auth = new Authentication(); | |
auth.setUsername(username); | |
// Figure out if we should use digest or plain text authentication. | |
if (authTypes.getDigest() != null) { | |
auth.setDigest(connection.getConnectionID(), password); | |
} | |
else if (authTypes.getPassword() != null) { | |
auth.setPassword(password); | |
} | |
else { | |
throw new XMPPException("Server does not support compatible authentication mechanism."); | |
} | |
auth.setResource(resource); | |
collector = connection.createPacketCollector(new PacketIDFilter(auth.getPacketID())); | |
// Send the packet. | |
connection.sendPacket(auth); | |
// Wait up to a certain number of seconds for a response from the server. | |
response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); | |
if (response == null) { | |
throw new XMPPException("Authentication failed."); | |
} | |
else if (response.getType() == IQ.Type.ERROR) { | |
throw new XMPPException(response.getError()); | |
} | |
// We're done with the collector, so explicitly cancel it. | |
collector.cancel(); | |
return response.getTo(); | |
} | |
public String authenticateAnonymously() throws XMPPException { | |
// Create the authentication packet we'll send to the server. | |
Authentication auth = new Authentication(); | |
PacketCollector collector = | |
connection.createPacketCollector(new PacketIDFilter(auth.getPacketID())); | |
// Send the packet. | |
connection.sendPacket(auth); | |
// Wait up to a certain number of seconds for a response from the server. | |
IQ response = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); | |
if (response == null) { | |
throw new XMPPException("Anonymous login failed."); | |
} | |
else if (response.getType() == IQ.Type.ERROR) { | |
throw new XMPPException(response.getError()); | |
} | |
// We're done with the collector, so explicitly cancel it. | |
collector.cancel(); | |
if (response.getTo() != null) { | |
return response.getTo(); | |
} | |
else { | |
return connection.getServiceName() + "/" + ((Authentication) response).getResource(); | |
} | |
} | |
} |