Add support for SASL EXTERNAL
authorBas Pape <baspape@gmail.com>
Thu, 30 Aug 2012 11:58:24 +0000 (13:58 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Tue, 19 Feb 2013 20:58:03 +0000 (21:58 +0100)
This is a method to identify to nickserv during connection registration,
like SASL PLAIN, but using the fingerprint of the certificate. Currently
the method used is chosen based on the mere presence of a certificate.
SASL PLAIN is not used as fallback (either this works or the certificate
is used as normal, with the race condition).

src/common/quassel.h
src/core/coresessioneventprocessor.cpp
src/qtui/settingspages/networkssettingspage.cpp
src/qtui/settingspages/networkssettingspage.h
src/qtui/settingspages/networkssettingspage.ui

index de19313..6089ac0 100644 (file)
@@ -71,8 +71,9 @@ public:
     enum Feature {
         SynchronizedMarkerLine = 0x0001,
         SaslAuthentication = 0x0002,
+        SaslExternal = 0x0004,
 
-        NumFeatures = 0x0002
+        NumFeatures = 0x0004
     };
     Q_DECLARE_FLAGS(Features, Feature);
 
index 07362b6..e2edd08 100644 (file)
@@ -112,14 +112,22 @@ void CoreSessionEventProcessor::processIrcEventAuthenticate(IrcEvent *e)
 
     CoreNetwork *net = coreNetwork(e);
 
-    QString construct = net->saslAccount();
-    construct.append(QChar(QChar::Null));
-    construct.append(net->saslAccount());
-    construct.append(QChar(QChar::Null));
-    construct.append(net->saslPassword());
-    QByteArray saslData = QByteArray(construct.toAscii().toBase64());
-    saslData.prepend("AUTHENTICATE ");
-    net->putRawLine(saslData);
+#ifdef HAVE_SSL
+    if (net->identityPtr()->sslCert().isNull()) {
+#endif
+        QString construct = net->saslAccount();
+        construct.append(QChar(QChar::Null));
+        construct.append(net->saslAccount());
+        construct.append(QChar(QChar::Null));
+        construct.append(net->saslPassword());
+        QByteArray saslData = QByteArray(construct.toAscii().toBase64());
+        saslData.prepend("AUTHENTICATE ");
+        net->putRawLine(saslData);
+#ifdef HAVE_SSL
+    } else {
+        net->putRawLine("AUTHENTICATE +");
+    }
+#endif
 }
 
 
@@ -131,7 +139,17 @@ void CoreSessionEventProcessor::processIrcEventCap(IrcEvent *e)
     if (e->params().count() == 3) {
         if (e->params().at(2).startsWith("sasl")) { // Freenode (at least) sends "sasl " with a trailing space for some reason!
             // FIXME use event
-            coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN")); // Only working with PLAIN atm, blowfish later
+            // if the current identity has a cert set, use SASL EXTERNAL
+#ifdef HAVE_SSL
+            if (!coreNetwork(e)->identityPtr()->sslCert().isNull()) {
+                coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE EXTERNAL"));
+            } else {
+#endif
+                // Only working with PLAIN atm, blowfish later
+                coreNetwork(e)->putRawLine(coreNetwork(e)->serverEncode("AUTHENTICATE PLAIN"));
+#ifdef HAVE_SSL
+            }
+#endif
         }
     }
 }
index bcaab22..6ae5f51 100644 (file)
 
 NetworksSettingsPage::NetworksSettingsPage(QWidget *parent)
     : SettingsPage(tr("IRC"), tr("Networks"), parent)
+#ifdef HAVE_SSL
+      , _cid(0)
+#endif
 {
     ui.setupUi(this);
 
     // hide SASL options for older cores
     if (!(Client::coreFeatures() & Quassel::SaslAuthentication))
         ui.sasl->hide();
+    if (!(Client::coreFeatures() & Quassel::SaslExternal))
+        ui.label_saslext->hide();
+#ifndef HAVE_SSL
+    ui.label_saslext->hide();
+#endif
 
     // set up icons
     ui.renameNetwork->setIcon(SmallIcon("edit-rename"));
@@ -469,6 +477,20 @@ void NetworksSettingsPage::displayNetwork(NetworkId id)
     _ignoreWidgetChanges = true;
     if (id != 0) {
         NetworkInfo info = networkInfos[id];
+
+#ifdef HAVE_SSL
+        // this is only needed when the core supports SASL EXTERNAL
+        if (Client::coreFeatures() & Quassel::SaslExternal) {
+            if (_cid) {
+                disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
+                delete _cid;
+            }
+            _cid = new CertIdentity(*Client::identity(info.identity), this);
+            _cid->enableEditSsl(true);
+            connect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
+        }
+#endif
+
         ui.identityList->setCurrentIndex(ui.identityList->findData(info.identity.toInt()));
         ui.serverList->clear();
         foreach(Network::Server server, info.serverList) {
@@ -506,6 +528,12 @@ void NetworksSettingsPage::displayNetwork(NetworkId id)
     }
     else {
         // just clear widgets
+#ifdef HAVE_SSL
+        if (_cid) {
+            disconnect(_cid, SIGNAL(sslSettingsUpdated()), this, SLOT(sslUpdated()));
+            delete _cid;
+        }
+#endif
         ui.identityList->setCurrentIndex(-1);
         ui.serverList->clear();
         ui.performEdit->clear();
@@ -549,6 +577,26 @@ void NetworksSettingsPage::saveToNetworkInfo(NetworkInfo &info)
 }
 
 
+#ifdef HAVE_SSL
+void NetworksSettingsPage::sslUpdated()
+{
+    if (_cid && !_cid->sslKey().isNull()) {
+        ui.saslAccount->setDisabled(true);
+        ui.label_10->setDisabled(true);
+        ui.saslPassword->setDisabled(true);
+        ui.label_11->setDisabled(true);
+        ui.label_saslext->setHidden(false);
+    } else {
+        ui.saslAccount->setDisabled(false);
+        ui.label_10->setDisabled(false);
+        ui.saslPassword->setDisabled(false);
+        ui.label_11->setDisabled(false);
+        ui.label_saslext->setHidden(true);
+    }
+}
+#endif
+
+
 /*** Network list ***/
 
 void NetworksSettingsPage::on_networkList_itemSelectionChanged()
index c337325..ef9f883 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "network.h"
 #include "settingspage.h"
+#include "clientidentity.h"
 
 #include "ui_networkssettingspage.h"
 #include "ui_networkadddlg.h"
@@ -65,6 +66,10 @@ private slots:
     void clientIdentityRemoved(IdentityId);
     void clientIdentityUpdated();
 
+#ifdef HAVE_SSL
+    void sslUpdated();
+#endif
+
     void on_networkList_itemSelectionChanged();
     void on_addNetwork_clicked();
     void on_deleteNetwork_clicked();
@@ -86,6 +91,9 @@ private:
     NetworkId currentId;
     QHash<NetworkId, NetworkInfo> networkInfos;
     bool _ignoreWidgetChanges;
+#ifdef HAVE_SSL
+    CertIdentity *_cid;
+#endif
 
     QPixmap connectedIcon, connectingIcon, disconnectedIcon;
 
index 7665e10..e2c106c 100644 (file)
          <string/>
         </property>
         <property name="currentIndex">
-         <number>0</number>
+         <number>3</number>
         </property>
         <widget class="QWidget" name="serversTab">
          <property name="enabled">
@@ -629,6 +629,16 @@ Note that Quassel IRC automatically rejoins channels, so /join will rarely be ne
             </layout>
            </widget>
           </item>
+          <item>
+           <widget class="QLabel" name="label_saslext">
+            <property name="text">
+             <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Note:&lt;/span&gt; because the identity has an ssl certificate set, SASL EXTERNAL will be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+            </property>
+            <property name="wordWrap">
+             <bool>true</bool>
+            </property>
+           </widget>
+          </item>
           <item>
            <spacer name="verticalSpacer_2">
             <property name="orientation">