~singpolyma/biboumi

063e6b127ecf92ca5bf8c4ecb137b60e3e7aa216 — louiz’ 2 years ago 4d6fdb0
Handle SASL failures by displaying a message and aborting the connection
3 files changed, 66 insertions(+), 4 deletions(-)

M src/irc/irc_client.cpp
M src/irc/irc_client.hpp
M tests/end_to_end/scenarios/sasl.py
M src/irc/irc_client.cpp => src/irc/irc_client.cpp +24 -1
@@ 85,8 85,14 @@ static const std::unordered_map<std::string,
  {"CAP", {&IrcClient::on_cap, {3, 0}}},
#ifdef WITH_SASL
  {"AUTHENTICATE", {&IrcClient::on_authenticate, {1, 0}}},
  {"903", {&IrcClient::on_sasl_success, {0, 0}}},
  {"900", {&IrcClient::on_sasl_login, {3, 0}}},
  {"902", {&IrcClient::on_sasl_failure, {2, 0}}},
  {"903", {&IrcClient::on_sasl_success, {0, 0}}},
  {"904", {&IrcClient::on_sasl_failure, {2, 0}}},
  {"905", {&IrcClient::on_sasl_failure, {2, 0}}},
  {"906", {&IrcClient::on_sasl_failure, {2, 0}}},
  {"907", {&IrcClient::on_sasl_failure, {2, 0}}},
  {"908", {&IrcClient::on_sasl_failure, {2, 0}}},
#endif
  {"401", {&IrcClient::on_generic_error, {2, 0}}},
  {"402", {&IrcClient::on_generic_error, {2, 0}}},


@@ 238,6 244,7 @@ void IrcClient::on_connection_failed(const std::string& reason)
                                            "cancel", "item-not-found",
                                            "", reason);
        }
      this->channels_to_join.clear();
    }
  else                          // try the next port
    this->start();


@@ 1372,6 1379,22 @@ void IrcClient::on_sasl_success(const IrcMessage &)
  this->cap_end();
}

void IrcClient::on_sasl_failure(const IrcMessage& message)
{
  this->sasl_state = SaslState::failure;
  const auto reason = message.arguments[1];
  // Send an error message for all room that the user wanted to join
  for (const auto& tuple: this->channels_to_join)
  {
    Iid iid(std::get<0>(tuple) + "%" + this->hostname, this->chantypes);
    this->bridge.send_presence_error(iid, this->current_nick,
                                     "cancel", "item-not-found",
                                     "", reason);
  }
  this->channels_to_join.clear();
  this->send_quit_command(reason);
}

void IrcClient::on_sasl_login(const IrcMessage &message)
{
  const auto& login = message.arguments[2];

M src/irc/irc_client.hpp => src/irc/irc_client.hpp +2 -1
@@ 247,8 247,9 @@ private:
public:
#ifdef WITH_SASL
  void on_authenticate(const IrcMessage& message);
  void on_sasl_success(const IrcMessage& message);
  void on_sasl_login(const IrcMessage& message);
  void on_sasl_success(const IrcMessage& message);
  void on_sasl_failure(const IrcMessage& message);
#endif
  /**
   * The channel has been completely joined (self presence, topic, all names

M tests/end_to_end/scenarios/sasl.py => tests/end_to_end/scenarios/sasl.py +40 -2
@@ 26,9 26,47 @@ scenario = (
                "<field var='ports'><value>6667</value></field>"
                "<field var='nick'><value>RegisteredUser</value></field>"
                "<field var='tls_ports'><value>6697</value><value>6670</value></field>"
                "<field var='throttle_limit'><value>9999</value></field>"
                "</x></command></iq>"),
    expect_stanza("/iq[@type='result']/commands:command[@node='configure'][@status='completed']/commands:note[@type='info'][text()='Configuration successfully applied.']"),

    send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/{nick_one}' ><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
    sequences.connection(login="RegisteredUser")
    # Joining a channel with the associated nick will work
    send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/ignored' ><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
    sequences.connection(login="RegisteredUser"),
    expect_stanza("/presence"),
    expect_stanza("/message/subject"),

    # Leave the channel and disconnect from the server to try again differently
    send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/RegisteredUser' type='unavailable' />"),
    expect_stanza("/presence[@type='unavailable']"),

    # Configure an INCORRECT password
    send_stanza("<iq type='set' id='id3' from='{jid_one}/{resource_one}' to='{irc_server_one}'><command xmlns='http://jabber.org/protocol/commands' node='configure' action='execute' /></iq>"),
    expect_stanza("/iq[@type='result']/commands:command[@node='configure'][@sessionid][@status='executing']",
                  "/iq/commands:command/dataform:x[@type='form']/dataform:field[@type='text-private'][@var='sasl_password']",
                  after = save_value("sessionid", extract_attribute("/iq[@type='result']/commands:command[@node='configure']", "sessionid"))),


    send_stanza("<iq type='set' id='id4' from='{jid_one}/{resource_one}' to='{irc_server_one}'>"
                "<command xmlns='http://jabber.org/protocol/commands' node='configure' sessionid='{sessionid}' action='complete'>"
                "<x xmlns='jabber:x:data' type='submit'>"
                "<field var='sasl_password'><value>wrong wrong wrong</value></field>"
                "<field var='ports'><value>6667</value></field>"
                "<field var='nick'><value>RegisteredUser</value></field>"
                "<field var='tls_ports'><value>6697</value><value>6670</value></field>"
                "<field var='throttle_limit'><value>9999</value></field>"
                "</x></command></iq>"),
    expect_stanza("/iq[@type='result']/commands:command[@node='configure'][@status='completed']/commands:note[@type='info'][text()='Configuration successfully applied.']"),

    send_stanza("<presence from='{jid_one}/{resource_one}' to='#foo%{irc_server_one}/ignored' ><x xmlns='http://jabber.org/protocol/muc'/></presence>"),
    # Here, the 6 connecting… connected messages from the connection attempt
    expect_stanza("/message"),
    expect_stanza("/message"),
    expect_stanza("/message"),
    expect_stanza("/message"),
    expect_stanza("/message"),
    expect_stanza("/message"),
    expect_stanza("/presence[@type='error'][@from='#foo%{irc_server_one}/RegisteredUser']"),
    expect_stanza("/message/body[text()='ERROR: Quit: SASL authentication failed: Invalid account credentials']"),
    expect_stanza("/message/body[text()='ERROR: Connection closed.']"),
)