From cb6863fe1e534666b54cbf1add41e40c20d79a73 Mon Sep 17 00:00:00 2001 From: emeric Date: Tue, 14 Jul 2026 23:51:40 +0200 Subject: [PATCH] Removed not that useful config options --- SUBSONIC.md | 2 - approot/settings-subsonic.xml | 2 - conf/lms.conf | 6 -- src/libs/subsonic/impl/AuthUtils.cpp | 12 +--- src/libs/subsonic/impl/AuthUtils.hpp | 6 +- src/libs/subsonic/impl/SubsonicResource.cpp | 2 +- .../subsonic/impl/SubsonicResourceConfig.cpp | 2 - .../subsonic/impl/SubsonicResourceConfig.hpp | 2 - src/libs/subsonic/impl/SubsonicResponse.hpp | 14 ----- src/libs/subsonic/test/AuthUtils.cpp | 60 +++++-------------- src/lms/ui/settings/SubsonicSettingsView.cpp | 6 -- 11 files changed, 22 insertions(+), 92 deletions(-) diff --git a/SUBSONIC.md b/SUBSONIC.md index 77618cea..1afb1484 100644 --- a/SUBSONIC.md +++ b/SUBSONIC.md @@ -19,8 +19,6 @@ OpenSubsonic is an initiative to patch and extend the legacy Subsonic API. You'l _LMS_ supports the [API Key Authentication](https://opensubsonic.netlify.app/docs/extensions/apikeyauth/) method. Each user has to generate their own API key on the settings page to use the Subsonic API. If a client's login screen has no dedicated API key field, enter the API key as the password instead. -__Note__: the legacy Subsonic authentication methods can be disabled using the `lms.conf` file. - ## Extra fields The following extra fields are implemented: * `Album` response: diff --git a/approot/settings-subsonic.xml b/approot/settings-subsonic.xml index ab36a43f..d22bd7b8 100644 --- a/approot/settings-subsonic.xml +++ b/approot/settings-subsonic.xml @@ -54,11 +54,9 @@
${tr:Lms.Settings.subsonic-token} - ${} - ${}
diff --git a/conf/lms.conf b/conf/lms.conf index db539ab3..7231c04b 100644 --- a/conf/lms.conf +++ b/conf/lms.conf @@ -84,12 +84,6 @@ login-throttler-max-entries = 10000; # API api-subsonic = true; -# Enable or disable user/password authentication (params 'u' and 'p') -api-subsonic-support-password-auth = true; - -# Enable or disable token/salt authentication (params 'u', 's' and 't') -api-subsonic-support-token-auth = true; - # List of clients for whom open subsonic extensions and extra fields are disabled api-open-subsonic-disabled-clients = ("DSub"); diff --git a/src/libs/subsonic/impl/AuthUtils.cpp b/src/libs/subsonic/impl/AuthUtils.cpp index 7e93099f..50b0393d 100644 --- a/src/libs/subsonic/impl/AuthUtils.cpp +++ b/src/libs/subsonic/impl/AuthUtils.cpp @@ -60,7 +60,7 @@ namespace lms::api::subsonic::utils } } // namespace - AuthenticationRequest parseAndValidateAuthenticationRequest(const Wt::Http::ParameterMap& parameters, const SubsonicResourceConfig& config) + AuthenticationRequest parseAndValidateAuthenticationRequest(const Wt::Http::ParameterMap& parameters) { const std::optional user{ getParameterAs(parameters, "u") }; const std::optional password{ getParameterAs(parameters, "p") }; @@ -70,12 +70,6 @@ namespace lms::api::subsonic::utils const bool passwordAuthRequested{ password.has_value() }; const bool tokenAuthRequested{ token.has_value() || salt.has_value() }; - const bool passwordAuthAttempted{ passwordAuthRequested || (user.has_value() && !tokenAuthRequested) }; - - if (!config.supportPasswordAuthentication && passwordAuthAttempted) - throw ProvidedAuthenticationMechanismNotSupportedError{}; - if (!config.supportTokenAuthentication && tokenAuthRequested) - throw ProvidedAuthenticationMechanismNotSupportedError{}; if (passwordAuthRequested && tokenAuthRequested) throw MultipleConflictingAuthenticationMechanismsProvidedError{}; @@ -130,9 +124,9 @@ namespace lms::api::subsonic::utils throw UserNotAuthorizedError{}; } - db::UserId authenticateUser(const Wt::Http::Request& request, db::Session& session, const SubsonicResourceConfig& config) + db::UserId authenticateUser(const Wt::Http::Request& request, db::Session& session) { - const AuthenticationRequest authRequest{ parseAndValidateAuthenticationRequest(request.getParameterMap(), config) }; + const AuthenticationRequest authRequest{ parseAndValidateAuthenticationRequest(request.getParameterMap()) }; const auto clientAddress{ boost::asio::ip::make_address(request.clientAddress()) }; auto& authTokenService{ *core::Service::get() }; diff --git a/src/libs/subsonic/impl/AuthUtils.hpp b/src/libs/subsonic/impl/AuthUtils.hpp index 5b76bb17..adb67220 100644 --- a/src/libs/subsonic/impl/AuthUtils.hpp +++ b/src/libs/subsonic/impl/AuthUtils.hpp @@ -28,8 +28,6 @@ #include "database/objects/User.hpp" #include "database/objects/UserId.hpp" -#include "SubsonicResourceConfig.hpp" - namespace lms::db { class Session; @@ -58,7 +56,7 @@ namespace lms::api::subsonic::utils using AuthenticationRequest = std::variant; // Throws on error - AuthenticationRequest parseAndValidateAuthenticationRequest(const Wt::Http::ParameterMap& parameters, const SubsonicResourceConfig& config); + AuthenticationRequest parseAndValidateAuthenticationRequest(const Wt::Http::ParameterMap& parameters); // Checks token == hex(md5(apiKey + salt)), case insensitive bool checkAuthToken(std::string_view apiKey, std::string_view salt, std::string_view token); @@ -67,5 +65,5 @@ namespace lms::api::subsonic::utils db::User::pointer getUserFromUserId(db::Session& session, db::UserId userId); // Throws on error - db::UserId authenticateUser(const Wt::Http::Request& request, db::Session& session, const SubsonicResourceConfig& config); + db::UserId authenticateUser(const Wt::Http::Request& request, db::Session& session); } // namespace lms::api::subsonic::utils diff --git a/src/libs/subsonic/impl/SubsonicResource.cpp b/src/libs/subsonic/impl/SubsonicResource.cpp index 28ff3117..3c59b584 100644 --- a/src/libs/subsonic/impl/SubsonicResource.cpp +++ b/src/libs/subsonic/impl/SubsonicResource.cpp @@ -415,6 +415,6 @@ namespace lms::api::subsonic db::UserId SubsonicResource::authenticateUser(const Wt::Http::Request& request) { - return utils::authenticateUser(request, _db.getTLSSession(), _config); + return utils::authenticateUser(request, _db.getTLSSession()); } } // namespace lms::api::subsonic diff --git a/src/libs/subsonic/impl/SubsonicResourceConfig.cpp b/src/libs/subsonic/impl/SubsonicResourceConfig.cpp index 576f41df..c1ea001d 100644 --- a/src/libs/subsonic/impl/SubsonicResourceConfig.cpp +++ b/src/libs/subsonic/impl/SubsonicResourceConfig.cpp @@ -43,8 +43,6 @@ namespace lms::api::subsonic { return SubsonicResourceConfig{ .openSubsonicDisabledClients = readOpenSubsonicDisabledClients(config), - .supportPasswordAuthentication = config.getBool("api-subsonic-support-password-auth", true), - .supportTokenAuthentication = config.getBool("api-subsonic-support-token-auth", true) }; } } // namespace lms::api::subsonic \ No newline at end of file diff --git a/src/libs/subsonic/impl/SubsonicResourceConfig.hpp b/src/libs/subsonic/impl/SubsonicResourceConfig.hpp index 2c456ebf..4fbf73b0 100644 --- a/src/libs/subsonic/impl/SubsonicResourceConfig.hpp +++ b/src/libs/subsonic/impl/SubsonicResourceConfig.hpp @@ -32,8 +32,6 @@ namespace lms::api::subsonic struct SubsonicResourceConfig { std::unordered_set openSubsonicDisabledClients; - bool supportPasswordAuthentication; - bool supportTokenAuthentication; }; SubsonicResourceConfig readSubsonicResourceConfig(core::IConfig& _config); diff --git a/src/libs/subsonic/impl/SubsonicResponse.hpp b/src/libs/subsonic/impl/SubsonicResponse.hpp index 070db870..128ce687 100644 --- a/src/libs/subsonic/impl/SubsonicResponse.hpp +++ b/src/libs/subsonic/impl/SubsonicResponse.hpp @@ -47,7 +47,6 @@ namespace lms::api::subsonic ServerMustUpgrade = 30, WrongUsernameOrPassword = 40, TokenAuthenticationNotSupportedForLDAPUsers = 41, - ProvidedAuthenticationMechanismNotSupported = 42, MultipleConflictingAuthenticationMechanismsProvided = 43, InvalidAPIkey = 44, UserNotAuthorized = 50, @@ -131,19 +130,6 @@ namespace lms::api::subsonic std::string getMessage() const override { return "Token authentication not supported for LDAP users."; } }; - class ProvidedAuthenticationMechanismNotSupportedError : public Error - { - public: - ProvidedAuthenticationMechanismNotSupportedError() - : Error{ Code::ProvidedAuthenticationMechanismNotSupported } {} - - private: - std::string getMessage() const override - { - return "Provided authentication mechanism not supported."; - } - }; - class MultipleConflictingAuthenticationMechanismsProvidedError : public Error { public: diff --git a/src/libs/subsonic/test/AuthUtils.cpp b/src/libs/subsonic/test/AuthUtils.cpp index bb2f976f..e8eb3174 100644 --- a/src/libs/subsonic/test/AuthUtils.cpp +++ b/src/libs/subsonic/test/AuthUtils.cpp @@ -24,27 +24,6 @@ namespace lms::api::subsonic::utils::tests { - namespace - { - const SubsonicResourceConfig bothMechanismsSupported{ - .openSubsonicDisabledClients = {}, - .supportPasswordAuthentication = true, - .supportTokenAuthentication = true, - }; - - const SubsonicResourceConfig noneSupported{ - .openSubsonicDisabledClients = {}, - .supportPasswordAuthentication = false, - .supportTokenAuthentication = false, - }; - - const SubsonicResourceConfig passwordUnsupported{ - .openSubsonicDisabledClients = {}, - .supportPasswordAuthentication = false, - .supportTokenAuthentication = true, - }; - } // namespace - // Reference values from the Subsonic API documentation (apiKey = "sesame", salt = "c19b2d") TEST(AuthUtils, checkAuthToken_ValidToken) { @@ -73,66 +52,59 @@ namespace lms::api::subsonic::utils::tests TEST(AuthUtils, parseAndValidateAuthenticationRequest_apiKeyOnly) { - const auto request{ parseAndValidateAuthenticationRequest({ { "apiKey", { "apiKey" } } }, bothMechanismsSupported) }; + const auto request{ parseAndValidateAuthenticationRequest({ { "apiKey", { "apiKey" } } }) }; ASSERT_TRUE(std::holds_alternative(request)); EXPECT_EQ(std::get(request).apiKey, "apiKey"); - EXPECT_THROW(parseAndValidateAuthenticationRequest({}, bothMechanismsSupported), RequiredParameterMissingError); + EXPECT_THROW(parseAndValidateAuthenticationRequest({}), RequiredParameterMissingError); } TEST(AuthUtils, parseAndValidateAuthenticationRequest_password) { - const auto request{ parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "p", { "password" } } }, bothMechanismsSupported) }; + const auto request{ parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "p", { "password" } } }) }; ASSERT_TRUE(std::holds_alternative(request)); EXPECT_EQ(std::get(request).user, "user"); EXPECT_EQ(std::get(request).password, "password"); - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "p", { "password" } } }, bothMechanismsSupported), RequiredParameterMissingError); // missing u - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } } }, bothMechanismsSupported), RequiredParameterMissingError); // missing p + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "p", { "password" } } }), RequiredParameterMissingError); // missing u + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } } }), RequiredParameterMissingError); // missing p } TEST(AuthUtils, parseAndValidateAuthenticationRequest_token) { - const auto request{ parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "t", { "token" } }, { "s", { "salt" } } }, bothMechanismsSupported) }; + const auto request{ parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "t", { "token" } }, { "s", { "salt" } } }) }; ASSERT_TRUE(std::holds_alternative(request)); EXPECT_EQ(std::get(request).user, "user"); EXPECT_EQ(std::get(request).token, "token"); EXPECT_EQ(std::get(request).salt, "salt"); - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "t", { "token" } }, { "s", { "salt" } } }, bothMechanismsSupported), RequiredParameterMissingError); // missing u - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "s", { "salt" } } }, bothMechanismsSupported), RequiredParameterMissingError); // missing t - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "t", { "token" } } }, bothMechanismsSupported), RequiredParameterMissingError); // missing s + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "t", { "token" } }, { "s", { "salt" } } }), RequiredParameterMissingError); // missing u + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "s", { "salt" } } }), RequiredParameterMissingError); // missing t + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "t", { "token" } } }), RequiredParameterMissingError); // missing s } TEST(AuthUtils, parseAndValidateAuthenticationRequest_conflicts) { // password + token - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "p", { "password" } }, { "t", { "token" } }, { "s", { "salt" } } }, bothMechanismsSupported), MultipleConflictingAuthenticationMechanismsProvidedError); + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "p", { "password" } }, { "t", { "token" } }, { "s", { "salt" } } }), MultipleConflictingAuthenticationMechanismsProvidedError); // apiKey + password - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "p", { "password" } }, { "apiKey", { "apiKey" } } }, bothMechanismsSupported), MultipleConflictingAuthenticationMechanismsProvidedError); + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "p", { "password" } }, { "apiKey", { "apiKey" } } }), MultipleConflictingAuthenticationMechanismsProvidedError); // apiKey + token - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "t", { "token" } }, { "s", { "salt" } }, { "apiKey", { "apiKey" } } }, bothMechanismsSupported), MultipleConflictingAuthenticationMechanismsProvidedError); + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "t", { "token" } }, { "s", { "salt" } }, { "apiKey", { "apiKey" } } }), MultipleConflictingAuthenticationMechanismsProvidedError); } - TEST(AuthUtils, parseAndValidateAuthenticationRequest_mechanismNotSupported) + TEST(AuthUtils, parseAndValidateAuthenticationRequest_usernameOnlyRequiresPassword) { - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "p", { "password" } } }, noneSupported), ProvidedAuthenticationMechanismNotSupportedError); - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } }, { "t", { "token" } }, { "s", { "salt" } } }, noneSupported), ProvidedAuthenticationMechanismNotSupportedError); - EXPECT_NO_THROW(parseAndValidateAuthenticationRequest({ { "apiKey", { "apiKey" } } }, noneSupported)); // apiKey is unaffected by these two flags - } - - TEST(AuthUtils, parseAndValidateAuthenticationRequest_usernameOnlyTreatedAsPasswordAttempt) - { - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } } }, passwordUnsupported), ProvidedAuthenticationMechanismNotSupportedError); + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "u", { "user" } } }), RequiredParameterMissingError); // missing p } TEST(AuthUtils, parseAndValidateAuthenticationRequest_apiKeyWithPartialPassword) { - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "p", { "password" } }, { "apiKey", { "apiKey" } } }, bothMechanismsSupported), RequiredParameterMissingError); // missing u + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "p", { "password" } }, { "apiKey", { "apiKey" } } }), RequiredParameterMissingError); // missing u } TEST(AuthUtils, parseAndValidateAuthenticationRequest_apiKeyWithPartialToken) { - EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "s", { "salt" } }, { "apiKey", { "apiKey" } } }, bothMechanismsSupported), RequiredParameterMissingError); // missing u + EXPECT_THROW(parseAndValidateAuthenticationRequest({ { "s", { "salt" } }, { "apiKey", { "apiKey" } } }), RequiredParameterMissingError); // missing u } } // namespace lms::api::subsonic::utils::tests diff --git a/src/lms/ui/settings/SubsonicSettingsView.cpp b/src/lms/ui/settings/SubsonicSettingsView.cpp index efeb51fa..e972ac5e 100644 --- a/src/lms/ui/settings/SubsonicSettingsView.cpp +++ b/src/lms/ui/settings/SubsonicSettingsView.cpp @@ -27,7 +27,6 @@ #include #include -#include "core/IConfig.hpp" #include "core/Service.hpp" #include "core/UUID.hpp" @@ -185,11 +184,6 @@ namespace lms::ui auto* t{ addNew(Wt::WString::tr("Lms.Settings.subsonic.template.key")) }; t->addFunction("tr", &Wt::WTemplate::Functions::tr); - { - core::IConfig& config{ *core::Service::get() }; - t->setCondition("if-has-subsonic-token-usage", config.getBool("api-subsonic-support-password-auth", true) || config.getBool("api-subsonic-support-token-auth", true)); - } - std::string currentToken; { auto transaction{ LmsApp->getDbSession().createReadTransaction() };