Skip to content

Commit

Permalink
Logout existing sessions after an auth config change
Browse files Browse the repository at this point in the history
Closes #18443.
  • Loading branch information
Func86 committed Sep 17, 2024
1 parent 1c43286 commit 8edda6b
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 11 deletions.
6 changes: 6 additions & 0 deletions src/base/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,6 +763,7 @@ void Preferences::setWebUIUsername(const QString &username)
if (username == getWebUIUsername())
return;

m_credentialsChanged = true;
setValue(u"Preferences/WebUI/Username"_s, username);
}

Expand All @@ -776,6 +777,7 @@ void Preferences::setWebUIPassword(const QByteArray &password)
if (password == getWebUIPassword())
return;

m_credentialsChanged = true;
setValue(u"Preferences/WebUI/Password_PBKDF2"_s, password);
}

Expand Down Expand Up @@ -1977,5 +1979,9 @@ void Preferences::setAddNewTorrentDialogSavePathHistoryLength(const int value)
void Preferences::apply()
{
if (SettingsStorage::instance()->save())
{
emit changed();
if (m_credentialsChanged)
emit webCredentialsChanged();
}
}
3 changes: 3 additions & 0 deletions src/base/preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,10 @@ public slots:

signals:
void changed();
void webCredentialsChanged();

private:
static Preferences *m_instance;

bool m_credentialsChanged = false;
};
2 changes: 1 addition & 1 deletion src/webui/api/authcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ void AuthController::loginAction()
{
m_clientFailedLogins.remove(clientAddr);

m_sessionManager->sessionStart();
m_sessionManager->sessionStart(true);
setResult(u"Ok."_s);
LogMsg(tr("WebAPI login success. IP: %1").arg(clientAddr));
}
Expand Down
2 changes: 1 addition & 1 deletion src/webui/api/isessionmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ struct ISessionManager
virtual ~ISessionManager() = default;
virtual QString clientId() const = 0;
virtual ISession *session() = 0;
virtual void sessionStart() = 0;
virtual void sessionStart(bool authenticated) = 0;
virtual void sessionEnd() = 0;
};
47 changes: 40 additions & 7 deletions src/webui/webapplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ WebApplication::WebApplication(IApplication *app, QObject *parent)

configure();
connect(Preferences::instance(), &Preferences::changed, this, &WebApplication::configure);
connect(Preferences::instance(), &Preferences::webCredentialsChanged, this, &WebApplication::logoutAllSessions);

m_sessionCookieName = Preferences::instance()->getWebAPISessionCookieName();
if (!isValidCookieName(m_sessionCookieName))
Expand Down Expand Up @@ -435,9 +436,29 @@ void WebApplication::configure()
}
}

m_isLocalAuthEnabled = pref->isWebUILocalAuthEnabled();
m_isAuthSubnetWhitelistEnabled = pref->isWebUIAuthSubnetWhitelistEnabled();
m_authSubnetWhitelist = pref->getWebUIAuthSubnetWhitelist();
const bool isLocalAuthEnabled = pref->isWebUILocalAuthEnabled();
const bool isAuthSubnetWhitelistEnabled = pref->isWebUIAuthSubnetWhitelistEnabled();
const auto authSubnetWhitelist = pref->getWebUIAuthSubnetWhitelist();
if (((isLocalAuthEnabled != m_isLocalAuthEnabled) && isLocalAuthEnabled) ||
((isAuthSubnetWhitelistEnabled != m_isAuthSubnetWhitelistEnabled) && !isAuthSubnetWhitelistEnabled) ||
((authSubnetWhitelist != m_authSubnetWhitelist) && !m_authSubnetWhitelist.isEmpty()))
{
// remove sessions which bypassed authentication
Algorithm::removeIf(m_sessions, [](const QString &, const WebSession *session)
{
if (!session->isAuthenticated())
{
delete session;
return true;
}

return false;
});
}

m_isLocalAuthEnabled = isLocalAuthEnabled;
m_isAuthSubnetWhitelistEnabled = isAuthSubnetWhitelistEnabled;
m_authSubnetWhitelist = authSubnetWhitelist;
m_sessionTimeout = pref->getWebUISessionTimeout();

m_domainList = pref->getServerDomains().split(u';', Qt::SkipEmptyParts);
Expand Down Expand Up @@ -525,6 +546,12 @@ void WebApplication::configure()
}
}

void WebApplication::logoutAllSessions()
{
qDeleteAll(m_sessions);
m_sessions.clear();
}

void WebApplication::declarePublicAPI(const QString &apiPath)
{
m_publicAPIs << apiPath;
Expand Down Expand Up @@ -677,7 +704,7 @@ void WebApplication::sessionInitialize()
}

if (!m_currentSession && !isAuthNeeded())
sessionStart();
sessionStart(false);
}

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

void WebApplication::sessionStart()
void WebApplication::sessionStart(bool authenticated)
{
Q_ASSERT(!m_currentSession);

Expand All @@ -726,7 +753,7 @@ void WebApplication::sessionStart()
return false;
});

m_currentSession = new WebSession(generateSid(), app());
m_currentSession = new WebSession(generateSid(), app(), authenticated);
m_sessions[m_currentSession->id()] = m_currentSession;

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

// WebSession

WebSession::WebSession(const QString &sid, IApplication *app)
WebSession::WebSession(const QString &sid, IApplication *app, bool authenticated)
: ApplicationComponent(app)
, m_sid {sid}
, m_authenticated {authenticated}
{
updateTimestamp();
}
Expand All @@ -935,6 +963,11 @@ void WebSession::updateTimestamp()
m_timer.start();
}

bool WebSession::isAuthenticated() const
{
return m_authenticated;
}

void WebSession::registerAPIController(const QString &scope, APIController *controller)
{
Q_ASSERT(controller);
Expand Down
9 changes: 7 additions & 2 deletions src/webui/webapplication.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,19 +71,21 @@ namespace BitTorrent
class WebSession final : public ApplicationComponent<QObject>, public ISession
{
public:
explicit WebSession(const QString &sid, IApplication *app);
explicit WebSession(const QString &sid, IApplication *app, bool authenticated);

QString id() const override;

bool hasExpired(qint64 seconds) const;
void updateTimestamp();
bool isAuthenticated() const;

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

private:
const QString m_sid;
QElapsedTimer m_timer; // timestamp
bool m_authenticated;
QMap<QString, APIController *> m_apiControllers;
};

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

public slots:
void logoutAllSessions();

private:
QString clientId() const override;
WebSession *session() override;
void sessionStart() override;
void sessionStart(bool authenticated) override;
void sessionEnd() override;

void doProcessRequest();
Expand Down

0 comments on commit 8edda6b

Please sign in to comment.