moved authentication into seperate method. force close socket before changing status

This commit is contained in:
Daniel Gultsch 2016-04-10 00:18:14 +02:00
parent 83fab06508
commit 607b7d1593

View File

@ -183,16 +183,18 @@ public class XmppConnection implements Runnable {
if (packet.getType() == IqPacket.TYPE.RESULT) { if (packet.getType() == IqPacket.TYPE.RESULT) {
account.setOption(Account.OPTION_REGISTER, account.setOption(Account.OPTION_REGISTER,
false); false);
forceCloseSocket();
changeStatus(Account.State.REGISTRATION_SUCCESSFUL); changeStatus(Account.State.REGISTRATION_SUCCESSFUL);
} else if (packet.hasChild("error") } else if (packet.hasChild("error")
&& (packet.findChild("error") && (packet.findChild("error")
.hasChild("conflict"))) { .hasChild("conflict"))) {
forceCloseSocket();
changeStatus(Account.State.REGISTRATION_CONFLICT); changeStatus(Account.State.REGISTRATION_CONFLICT);
} else { } else {
forceCloseSocket();
changeStatus(Account.State.REGISTRATION_FAILED); changeStatus(Account.State.REGISTRATION_FAILED);
Log.d(Config.LOGTAG, packet.toString()); Log.d(Config.LOGTAG, packet.toString());
} }
disconnect(true);
} }
}; };
} }
@ -739,47 +741,12 @@ public class XmppConnection implements Runnable {
} }
} else if (!this.streamFeatures.hasChild("register") } else if (!this.streamFeatures.hasChild("register")
&& account.isOptionSet(Account.OPTION_REGISTER)) { && account.isOptionSet(Account.OPTION_REGISTER)) {
forceCloseSocket();
changeStatus(Account.State.REGISTRATION_NOT_SUPPORTED); changeStatus(Account.State.REGISTRATION_NOT_SUPPORTED);
disconnect(true);
} else if (this.streamFeatures.hasChild("mechanisms") } else if (this.streamFeatures.hasChild("mechanisms")
&& shouldAuthenticate && shouldAuthenticate
&& (features.encryptionEnabled || Config.ALLOW_NON_TLS_CONNECTIONS)) { && (features.encryptionEnabled || Config.ALLOW_NON_TLS_CONNECTIONS)) {
final List<String> mechanisms = extractMechanisms(streamFeatures authenticate();
.findChild("mechanisms"));
final Element auth = new Element("auth");
auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
if (mechanisms.contains("EXTERNAL") && account.getPrivateKeyAlias() != null) {
saslMechanism = new External(tagWriter, account, mXmppConnectionService.getRNG());
} else if (mechanisms.contains("SCRAM-SHA-1")) {
saslMechanism = new ScramSha1(tagWriter, account, mXmppConnectionService.getRNG());
} else if (mechanisms.contains("PLAIN")) {
saslMechanism = new Plain(tagWriter, account);
} else if (mechanisms.contains("DIGEST-MD5")) {
saslMechanism = new DigestMd5(tagWriter, account, mXmppConnectionService.getRNG());
}
if (saslMechanism != null) {
final JSONObject keys = account.getKeys();
try {
if (keys.has(Account.PINNED_MECHANISM_KEY) &&
keys.getInt(Account.PINNED_MECHANISM_KEY) > saslMechanism.getPriority()) {
Log.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() +
" has lower priority (" + String.valueOf(saslMechanism.getPriority()) +
") than pinned priority (" + keys.getInt(Account.PINNED_MECHANISM_KEY) +
"). Possible downgrade attack?");
throw new SecurityException();
}
} catch (final JSONException e) {
Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism");
}
Log.d(Config.LOGTAG, account.getJid().toString() + ": Authenticating with " + saslMechanism.getMechanism());
auth.setAttribute("mechanism", saslMechanism.getMechanism());
if (!saslMechanism.getClientFirstMessage().isEmpty()) {
auth.setContent(saslMechanism.getClientFirstMessage());
}
tagWriter.writeElement(auth);
} else {
throw new IncompatibleServerException();
}
} else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) { } else if (this.streamFeatures.hasChild("sm", "urn:xmpp:sm:" + smVersion) && streamId != null) {
if (Config.EXTENDED_SM_LOGGING) { if (Config.EXTENDED_SM_LOGGING) {
Log.d(Config.LOGTAG,account.getJid().toBareJid()+": resuming after stanza #"+stanzasReceived); Log.d(Config.LOGTAG,account.getJid().toBareJid()+": resuming after stanza #"+stanzasReceived);
@ -795,6 +762,45 @@ public class XmppConnection implements Runnable {
} }
} }
private void authenticate() throws IOException {
final List<String> mechanisms = extractMechanisms(streamFeatures
.findChild("mechanisms"));
final Element auth = new Element("auth");
auth.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
if (mechanisms.contains("EXTERNAL") && account.getPrivateKeyAlias() != null) {
saslMechanism = new External(tagWriter, account, mXmppConnectionService.getRNG());
} else if (mechanisms.contains("SCRAM-SHA-1")) {
saslMechanism = new ScramSha1(tagWriter, account, mXmppConnectionService.getRNG());
} else if (mechanisms.contains("PLAIN")) {
saslMechanism = new Plain(tagWriter, account);
} else if (mechanisms.contains("DIGEST-MD5")) {
saslMechanism = new DigestMd5(tagWriter, account, mXmppConnectionService.getRNG());
}
if (saslMechanism != null) {
final JSONObject keys = account.getKeys();
try {
if (keys.has(Account.PINNED_MECHANISM_KEY) &&
keys.getInt(Account.PINNED_MECHANISM_KEY) > saslMechanism.getPriority()) {
Log.e(Config.LOGTAG, "Auth failed. Authentication mechanism " + saslMechanism.getMechanism() +
" has lower priority (" + String.valueOf(saslMechanism.getPriority()) +
") than pinned priority (" + keys.getInt(Account.PINNED_MECHANISM_KEY) +
"). Possible downgrade attack?");
throw new SecurityException();
}
} catch (final JSONException e) {
Log.d(Config.LOGTAG, "Parse error while checking pinned auth mechanism");
}
Log.d(Config.LOGTAG, account.getJid().toString() + ": Authenticating with " + saslMechanism.getMechanism());
auth.setAttribute("mechanism", saslMechanism.getMechanism());
if (!saslMechanism.getClientFirstMessage().isEmpty()) {
auth.setContent(saslMechanism.getClientFirstMessage());
}
tagWriter.writeElement(auth);
} else {
throw new IncompatibleServerException();
}
}
private List<String> extractMechanisms(final Element stream) { private List<String> extractMechanisms(final Element stream) {
final ArrayList<String> mechanisms = new ArrayList<>(stream final ArrayList<String> mechanisms = new ArrayList<>(stream
.getChildren().size()); .getChildren().size());