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 12e1112
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 8 deletions.
8 changes: 8 additions & 0 deletions src/base/preferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,7 @@ void Preferences::setWebUILocalAuthEnabled(const bool enabled)
if (enabled == isWebUILocalAuthEnabled())
return;

m_authBypassChanged = true;
setValue(u"Preferences/WebUI/LocalHostAuth"_s, enabled);
}

Expand All @@ -670,6 +671,7 @@ void Preferences::setWebUIAuthSubnetWhitelistEnabled(const bool enabled)
if (enabled == isWebUIAuthSubnetWhitelistEnabled())
return;

m_authBypassChanged = true;
setValue(u"Preferences/WebUI/AuthSubnetWhitelistEnabled"_s, enabled);
}

Expand Down Expand Up @@ -763,6 +765,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 +779,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 +1981,9 @@ void Preferences::setAddNewTorrentDialogSavePathHistoryLength(const int value)
void Preferences::apply()
{
if (SettingsStorage::instance()->save())
{
emit changed();
if (m_credentialsChanged || m_authBypassChanged)
emit webAuthConfigChanged(m_credentialsChanged);
}
}
4 changes: 4 additions & 0 deletions src/base/preferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,11 @@ public slots:

signals:
void changed();
void webAuthConfigChanged(bool credentialsChanged);

private:
static Preferences *m_instance;

bool m_credentialsChanged = false;
bool m_authBypassChanged = 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;
};
38 changes: 34 additions & 4 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::webAuthConfigChanged, this, &WebApplication::logoutExistingSessions);

m_sessionCookieName = Preferences::instance()->getWebAPISessionCookieName();
if (!isValidCookieName(m_sessionCookieName))
Expand Down Expand Up @@ -299,6 +300,29 @@ const Http::Environment &WebApplication::env() const
return m_env;
}

void WebApplication::logoutExistingSessions(bool credentialsChanged)
{
if (credentialsChanged)
{
qDeleteAll(m_sessions);
m_sessions.clear();
}
else
{
// remove sessions which bypassed authentication
Algorithm::removeIf(m_sessions, [this](const QString &, const WebSession *session)
{
if (!session->isAuthenticated())
{
delete session;
return true;
}

return false;
});
}
}

void WebApplication::setUsername(const QString &username)
{
m_authController->setUsername(username);
Expand Down Expand Up @@ -677,7 +701,7 @@ void WebApplication::sessionInitialize()
}

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

QString WebApplication::generateSid() const
Expand Down Expand Up @@ -710,7 +734,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 +750,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 +935,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 +960,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 logoutExistingSessions(bool credentialsChanged);

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 12e1112

Please sign in to comment.