Support RespondToUnauthenticatedClients PATCH
RespondToUnauthenticatedClients allows users to explicitly select mTLS
as their only authentication mechanism, thus significantly reducing
their code exposure to unauthenticated clients.
From the Redfish specification
```
The RespondToUnauthenticatedClients property within the
ClientCertificate property within the MFA property of the AccountService
resource controls the response behavior when an invalid certificate is
provided by the client.
• If the property contains true or is not
supported by the service, the service shall not fail the TLS handshake.
This is to allow the service to send error messages or unauthenticated
resources to the client.
• If the property contains false , the service
shall fail the TLS handshake.
```
This commit implements that behavior.
This also has some added benefits in that we no longer have to check the
filesystem for every connection, as TLS is controlled explicitly, and
not whether or not a root cert is in place.
Note, this also implements a TODO to disable cookie auth when using
mTLS. Clients can still use IsAuthenticated to determine if they are
authenticated on request.
Tested:
Run scripts/generate_auth_certs.py to set up a root certificate and
client certificate. This verifies that mTLS as optional has not been
broken. Script succeeds.
```
PATCH /redfish/v1/AccountService
{"MultiFactorAuth": {"ClientCertificate": {"RespondToUnauthenticatedClients": false}}}
```
GET /redfish/v1
without a client certificate now fails with an ssl verification error
GET /redfish/v1
with a client certificate returns the result
```
PATCH /redfish/v1/AccountService
{"MultiFactorAuth": {"ClientCertificate": {"RespondToUnauthenticatedClients": false}}}
With certificate returns non mTLS functionality.
```
Change-Id: I5a9d6d6b1698bff83ab62b1f760afed6555849c9
Signed-off-by: Ed Tanous <ed@tanous.net>
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index b3b848f..a0725e6 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -23,6 +23,7 @@
#include "persistent_data.hpp"
#include "query.hpp"
#include "registries/privilege_registry.hpp"
+#include "sessions.hpp"
#include "utils/collection.hpp"
#include "utils/dbus_utils.hpp"
#include "utils/json_utils.hpp"
@@ -1339,7 +1340,8 @@
nlohmann::json::object_t clientCertificate;
clientCertificate["Enabled"] = authMethodsConfig.tls;
- clientCertificate["RespondToUnauthenticatedClients"] = true;
+ clientCertificate["RespondToUnauthenticatedClients"] =
+ !authMethodsConfig.tlsStrict;
using account_service::CertificateMappingAttribute;
@@ -1468,6 +1470,38 @@
authMethodsConfig.mTLSCommonNameParsingMode = parseMode;
}
+inline void handleRespondToUnauthenticatedClientsPatch(
+ App& app, const crow::Request& req, crow::Response& res,
+ bool respondToUnauthenticatedClients)
+{
+ if (req.session != nullptr)
+ {
+ // Sanity check. If the user isn't currently authenticated with mutual
+ // TLS, they very likely are about to permanently lock themselves out.
+ // Make sure they're using mutual TLS before allowing locking.
+ if (req.session->sessionType != persistent_data::SessionType::MutualTLS)
+ {
+ messages::propertyValueExternalConflict(
+ res,
+ "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients",
+ respondToUnauthenticatedClients);
+ return;
+ }
+ }
+
+ persistent_data::AuthConfigMethods& authMethodsConfig =
+ persistent_data::SessionStore::getInstance().getAuthMethodsConfig();
+
+ // Change the settings
+ authMethodsConfig.tlsStrict = !respondToUnauthenticatedClients;
+
+ // Write settings to disk
+ persistent_data::getConfig().writeData();
+
+ // Trigger a reload, to apply the new settings to new connections
+ app.loadCertificate();
+}
+
inline void handleAccountServicePatch(
App& app, const crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
@@ -1482,6 +1516,7 @@
std::optional<uint16_t> maxPasswordLength;
LdapPatchParams ldapObject;
std::optional<std::string> certificateMappingAttribute;
+ std::optional<bool> respondToUnauthenticatedClients;
LdapPatchParams activeDirectoryObject;
AuthMethods auth;
std::optional<std::string> httpBasicAuth;
@@ -1501,6 +1536,7 @@
"ActiveDirectory/ServiceAddresses", activeDirectoryObject.serviceAddressList,
"ActiveDirectory/ServiceEnabled", activeDirectoryObject.serviceEnabled,
"MultiFactorAuth/ClientCertificate/CertificateMappingAttribute", certificateMappingAttribute,
+ "MultiFactorAuth/ClientCertificate/RespondToUnauthenticatedClients", respondToUnauthenticatedClients,
"LDAP/Authentication/AuthenticationType", ldapObject.authType,
"LDAP/Authentication/Password", ldapObject.password,
"LDAP/Authentication/Username", ldapObject.userName,
@@ -1540,6 +1576,12 @@
}
}
+ if (respondToUnauthenticatedClients)
+ {
+ handleRespondToUnauthenticatedClientsPatch(
+ app, req, asyncResp->res, *respondToUnauthenticatedClients);
+ }
+
if (certificateMappingAttribute)
{
handleCertificateMappingAttributePatch(asyncResp->res,