}
@Override
public IQ handleIQ(IQ packet) throws UnauthorizedException, PacketException {
JID from = packet.getFrom();
LocalClientSession session = (LocalClientSession) sessionManager.getSession(from);
// If no session was found then answer an error (if possible)
if (session == null) {
Log.error("Error during authentication. Session not found in " +
sessionManager.getPreAuthenticatedKeys() +
" for key " +
from);
// This error packet will probably won't make it through
IQ reply = IQ.createResultIQ(packet);
reply.setChildElement(packet.getChildElement().createCopy());
reply.setError(PacketError.Condition.internal_server_error);
return reply;
}
IQ response;
boolean resourceBound = false;
if (JiveGlobals.getBooleanProperty("xmpp.auth.iqauth",true)) {
try {
Element iq = packet.getElement();
Element query = iq.element("query");
Element queryResponse = probeResponse.createCopy();
if (IQ.Type.get == packet.getType()) {
String username = query.elementText("username");
if (username != null) {
queryResponse.element("username").setText(username);
}
response = IQ.createResultIQ(packet);
response.setChildElement(queryResponse);
// This is a workaround. Since we don't want to have an incorrect TO attribute
// value we need to clean up the TO attribute and send directly the response.
// The TO attribute will contain an incorrect value since we are setting a fake
// JID until the user actually authenticates with the server.
if (session.getStatus() != Session.STATUS_AUTHENTICATED) {
response.setTo((JID)null);
}
}
// Otherwise set query
else {
if (query.elements().isEmpty()) {
// Anonymous authentication
response = anonymousLogin(session, packet);
resourceBound = session.getStatus() == Session.STATUS_AUTHENTICATED;
}
else {
String username = query.elementText("username");
// Login authentication
String password = query.elementText("password");
String digest = null;
if (query.element("digest") != null) {
digest = query.elementText("digest").toLowerCase();
}
// If we're already logged in, this is a password reset
if (session.getStatus() == Session.STATUS_AUTHENTICATED) {
// Check that a new password has been specified
if (password == null || password.trim().length() == 0) {
response = IQ.createResultIQ(packet);
response.setError(PacketError.Condition.not_allowed);
response.setType(IQ.Type.error);
}
else {
// Check if a user is trying to change his own password
if (session.getUsername().equalsIgnoreCase(username)) {
response = passwordReset(password, packet, username, session);
}
// Check if an admin is trying to set the password for another user
else if (XMPPServer.getInstance().getAdmins()
.contains(new JID(from.getNode(), from.getDomain(), null, true))) {
response = passwordReset(password, packet, username, session);
}
else {
// User not authorized to change the password of another user
throw new UnauthorizedException();
}
}
}
else {
// it is an auth attempt
response = login(username, query, packet, password, session, digest);
resourceBound = session.getStatus() == Session.STATUS_AUTHENTICATED;
}
}
}
}
catch (UserNotFoundException e) {
response = IQ.createResultIQ(packet);
response.setChildElement(packet.getChildElement().createCopy());
response.setError(PacketError.Condition.not_authorized);
}
catch (UnauthorizedException e) {
response = IQ.createResultIQ(packet);
response.setChildElement(packet.getChildElement().createCopy());
response.setError(PacketError.Condition.not_authorized);
} catch (ConnectionException e) {
response = IQ.createResultIQ(packet);
response.setChildElement(packet.getChildElement().createCopy());
response.setError(PacketError.Condition.internal_server_error);
} catch (InternalUnauthenticatedException e) {
response = IQ.createResultIQ(packet);
response.setChildElement(packet.getChildElement().createCopy());
response.setError(PacketError.Condition.internal_server_error);
}
}
else {
response = IQ.createResultIQ(packet);
response.setChildElement(packet.getChildElement().createCopy());
response.setError(PacketError.Condition.not_authorized);
}
// Send the response directly since we want to be sure that we are sending it back
// to the correct session. Any other session of the same user but with different
// resource is incorrect.
session.process(response);
if (resourceBound) {
// After the client has been informed, inform all listeners as well.
SessionEventDispatcher.dispatchEvent(session, SessionEventDispatcher.EventType.resource_bound);
}
return null;