Skip to content

Commit 1782c3b

Browse files
committed
Logout existing sessions after an auth config change
Closes qbittorrent#18443.
1 parent 1c43286 commit 1782c3b

File tree

6 files changed

+60
-11
lines changed

6 files changed

+60
-11
lines changed

Diff for: src/base/preferences.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ void Preferences::setWebUIUsername(const QString &username)
764764
return;
765765

766766
setValue(u"Preferences/WebUI/Username"_s, username);
767+
m_credentialsChanged = true;
767768
}
768769

769770
QByteArray Preferences::getWebUIPassword() const
@@ -777,6 +778,7 @@ void Preferences::setWebUIPassword(const QByteArray &password)
777778
return;
778779

779780
setValue(u"Preferences/WebUI/Password_PBKDF2"_s, password);
781+
m_credentialsChanged = true;
780782
}
781783

782784
int Preferences::getWebUIMaxAuthFailCount() const
@@ -1977,5 +1979,11 @@ void Preferences::setAddNewTorrentDialogSavePathHistoryLength(const int value)
19771979
void Preferences::apply()
19781980
{
19791981
if (SettingsStorage::instance()->save())
1982+
{
19801983
emit changed();
1984+
if (m_credentialsChanged) {
1985+
emit webCredentialsChanged();
1986+
m_credentialsChanged = false;
1987+
}
1988+
}
19811989
}

Diff for: src/base/preferences.h

+3
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,10 @@ public slots:
430430

431431
signals:
432432
void changed();
433+
void webCredentialsChanged();
433434

434435
private:
435436
static Preferences *m_instance;
437+
438+
bool m_credentialsChanged = false;
436439
};

Diff for: src/webui/api/authcontroller.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void AuthController::loginAction()
8181
{
8282
m_clientFailedLogins.remove(clientAddr);
8383

84-
m_sessionManager->sessionStart();
84+
m_sessionManager->sessionStart(true);
8585
setResult(u"Ok."_s);
8686
LogMsg(tr("WebAPI login success. IP: %1").arg(clientAddr));
8787
}

Diff for: src/webui/api/isessionmanager.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,6 @@ struct ISessionManager
4343
virtual ~ISessionManager() = default;
4444
virtual QString clientId() const = 0;
4545
virtual ISession *session() = 0;
46-
virtual void sessionStart() = 0;
46+
virtual void sessionStart(const bool authenticated) = 0;
4747
virtual void sessionEnd() = 0;
4848
};

Diff for: src/webui/webapplication.cpp

+40-7
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ WebApplication::WebApplication(IApplication *app, QObject *parent)
170170

171171
configure();
172172
connect(Preferences::instance(), &Preferences::changed, this, &WebApplication::configure);
173+
connect(Preferences::instance(), &Preferences::webCredentialsChanged, this, &WebApplication::logoutAllSessions);
173174

174175
m_sessionCookieName = Preferences::instance()->getWebAPISessionCookieName();
175176
if (!isValidCookieName(m_sessionCookieName))
@@ -435,9 +436,29 @@ void WebApplication::configure()
435436
}
436437
}
437438

438-
m_isLocalAuthEnabled = pref->isWebUILocalAuthEnabled();
439-
m_isAuthSubnetWhitelistEnabled = pref->isWebUIAuthSubnetWhitelistEnabled();
440-
m_authSubnetWhitelist = pref->getWebUIAuthSubnetWhitelist();
439+
const bool isLocalAuthEnabled = pref->isWebUILocalAuthEnabled();
440+
const bool isAuthSubnetWhitelistEnabled = pref->isWebUIAuthSubnetWhitelistEnabled();
441+
const QList<Utils::Net::Subnet> authSubnetWhitelist = pref->getWebUIAuthSubnetWhitelist();
442+
if ((isLocalAuthEnabled && (isLocalAuthEnabled != m_isLocalAuthEnabled))
443+
|| (!isAuthSubnetWhitelistEnabled && (isAuthSubnetWhitelistEnabled != m_isAuthSubnetWhitelistEnabled))
444+
|| (!m_authSubnetWhitelist.isEmpty() && (authSubnetWhitelist != m_authSubnetWhitelist)))
445+
{
446+
// remove sessions which bypassed authentication
447+
Algorithm::removeIf(m_sessions, [](const QString &, const WebSession *session)
448+
{
449+
if (!session->isAuthenticated())
450+
{
451+
delete session;
452+
return true;
453+
}
454+
455+
return false;
456+
});
457+
}
458+
459+
m_isLocalAuthEnabled = isLocalAuthEnabled;
460+
m_isAuthSubnetWhitelistEnabled = isAuthSubnetWhitelistEnabled;
461+
m_authSubnetWhitelist = authSubnetWhitelist;
441462
m_sessionTimeout = pref->getWebUISessionTimeout();
442463

443464
m_domainList = pref->getServerDomains().split(u';', Qt::SkipEmptyParts);
@@ -525,6 +546,12 @@ void WebApplication::configure()
525546
}
526547
}
527548

549+
void WebApplication::logoutAllSessions()
550+
{
551+
qDeleteAll(m_sessions);
552+
m_sessions.clear();
553+
}
554+
528555
void WebApplication::declarePublicAPI(const QString &apiPath)
529556
{
530557
m_publicAPIs << apiPath;
@@ -677,7 +704,7 @@ void WebApplication::sessionInitialize()
677704
}
678705

679706
if (!m_currentSession && !isAuthNeeded())
680-
sessionStart();
707+
sessionStart(false);
681708
}
682709

683710
QString WebApplication::generateSid() const
@@ -710,7 +737,7 @@ bool WebApplication::isPublicAPI(const QString &scope, const QString &action) co
710737
return m_publicAPIs.contains(u"%1/%2"_s.arg(scope, action));
711738
}
712739

713-
void WebApplication::sessionStart()
740+
void WebApplication::sessionStart(const bool authenticated)
714741
{
715742
Q_ASSERT(!m_currentSession);
716743

@@ -726,7 +753,7 @@ void WebApplication::sessionStart()
726753
return false;
727754
});
728755

729-
m_currentSession = new WebSession(generateSid(), app());
756+
m_currentSession = new WebSession(generateSid(), app(), authenticated);
730757
m_sessions[m_currentSession->id()] = m_currentSession;
731758

732759
m_currentSession->registerAPIController(u"app"_s, new AppController(app(), this));
@@ -911,9 +938,10 @@ QHostAddress WebApplication::resolveClientAddress() const
911938

912939
// WebSession
913940

914-
WebSession::WebSession(const QString &sid, IApplication *app)
941+
WebSession::WebSession(const QString &sid, IApplication *app, const bool authenticated)
915942
: ApplicationComponent(app)
916943
, m_sid {sid}
944+
, m_authenticated {authenticated}
917945
{
918946
updateTimestamp();
919947
}
@@ -935,6 +963,11 @@ void WebSession::updateTimestamp()
935963
m_timer.start();
936964
}
937965

966+
bool WebSession::isAuthenticated() const
967+
{
968+
return m_authenticated;
969+
}
970+
938971
void WebSession::registerAPIController(const QString &scope, APIController *controller)
939972
{
940973
Q_ASSERT(controller);

Diff for: src/webui/webapplication.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -71,19 +71,21 @@ namespace BitTorrent
7171
class WebSession final : public ApplicationComponent<QObject>, public ISession
7272
{
7373
public:
74-
explicit WebSession(const QString &sid, IApplication *app);
74+
explicit WebSession(const QString &sid, IApplication *app, const bool authenticated);
7575

7676
QString id() const override;
7777

7878
bool hasExpired(qint64 seconds) const;
7979
void updateTimestamp();
80+
bool isAuthenticated() const;
8081

8182
void registerAPIController(const QString &scope, APIController *controller);
8283
APIController *getAPIController(const QString &scope) const;
8384

8485
private:
8586
const QString m_sid;
8687
QElapsedTimer m_timer; // timestamp
88+
bool m_authenticated = false;
8789
QMap<QString, APIController *> m_apiControllers;
8890
};
8991

@@ -106,10 +108,13 @@ class WebApplication final : public ApplicationComponent<QObject>
106108
void setUsername(const QString &username);
107109
void setPasswordHash(const QByteArray &passwordHash);
108110

111+
public slots:
112+
void logoutAllSessions();
113+
109114
private:
110115
QString clientId() const override;
111116
WebSession *session() override;
112-
void sessionStart() override;
117+
void sessionStart(const bool authenticated) override;
113118
void sessionEnd() override;
114119

115120
void doProcessRequest();

0 commit comments

Comments
 (0)