summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZbigniew Kurzynski <zbigniew.kurzynski@intel.com>2019-11-05 14:57:37 +0300
committerZbigniew Kurzynski <zbigniew.kurzynski@intel.com>2019-11-07 09:39:29 +0300
commit78158631aeab5b77ea9a5f566508285cb839fadf (patch)
tree71d49ec71414858c532c121df98c9b6b629e7987
parent1f8c7b5d6a679a38b82261060310b876079d0f8b (diff)
downloadbmcweb-78158631aeab5b77ea9a5f566508285cb839fadf.tar.xz
Auth methods configuration
Added Oem extension for AccountService allowing user to configure which authentication methods should be enabled. User is now able to turn on and off authentication methods like BasicAuth, XToken, etc. User is not allowed to turn off all of the methods at once - at least one method has to be active to prevent lock-out. This configuration is persistent, will be saved on file-system and will be loaded on bmcweb's restart. Tested: No regression found in manual testing. By default everything works as before, and disabling auth method prevents user to authenticate by it. Tested that user is not allowed to disable all the methods - either in one PATCH or by disabling them one at a time. ServiceValidator run with success. This change is a fix for this request: https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/23590/18 which was revert here: https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/26869 Signed-off-by: Zbigniew Kurzynski <zbigniew.kurzynski@intel.com> Change-Id: I66b5ad423746f1992070a14f2983a07b1320190e
-rw-r--r--include/persistent_data_middleware.hpp7
-rw-r--r--include/sessions.hpp61
-rw-r--r--include/token_authorization_middleware.hpp17
-rw-r--r--redfish-core/lib/account_service.hpp109
-rw-r--r--static/redfish/v1/$metadata/index.xml4
-rw-r--r--static/redfish/v1/JsonSchemas/OemAccountService/index.json102
-rw-r--r--static/redfish/v1/schema/OemAccountService_v1.xml71
7 files changed, 359 insertions, 12 deletions
diff --git a/include/persistent_data_middleware.hpp b/include/persistent_data_middleware.hpp
index c368ab21dc..348079ba61 100644
--- a/include/persistent_data_middleware.hpp
+++ b/include/persistent_data_middleware.hpp
@@ -100,6 +100,12 @@ class Middleware
systemUuid = *jSystemUuid;
}
}
+ else if (item.key() == "auth_config")
+ {
+ SessionStore::getInstance()
+ .getAuthMethodsConfig()
+ .fromJson(item.value());
+ }
else if (item.key() == "sessions")
{
for (const auto& elem : item.value())
@@ -163,6 +169,7 @@ class Middleware
nlohmann::json data{
{"sessions", SessionStore::getInstance().authTokens},
+ {"auth_config", SessionStore::getInstance().getAuthMethodsConfig()},
{"system_uuid", systemUuid},
{"revision", jsonRevision}};
persistentFile << data;
diff --git a/include/sessions.hpp b/include/sessions.hpp
index df65d6155d..749349476c 100644
--- a/include/sessions.hpp
+++ b/include/sessions.hpp
@@ -339,6 +339,43 @@ struct UserSession
}
};
+struct AuthConfigMethods
+{
+ bool xtoken = true;
+ bool cookie = true;
+ bool sessionToken = true;
+ bool basic = true;
+
+ void fromJson(const nlohmann::json& j)
+ {
+ for (const auto& element : j.items())
+ {
+ const bool* value = element.value().get_ptr<const bool*>();
+ if (value == nullptr)
+ {
+ continue;
+ }
+
+ if (element.key() == "XToken")
+ {
+ xtoken = *value;
+ }
+ else if (element.key() == "Cookie")
+ {
+ cookie = *value;
+ }
+ else if (element.key() == "SessionToken")
+ {
+ sessionToken = *value;
+ }
+ else if (element.key() == "BasicAuth")
+ {
+ basic = *value;
+ }
+ }
+ }
+};
+
class Middleware;
class SessionStore
@@ -445,6 +482,17 @@ class SessionStore
return ret;
}
+ void updateAuthMethodsConfig(const AuthConfigMethods& config)
+ {
+ authMethodsConfig = config;
+ needWrite = true;
+ }
+
+ AuthConfigMethods& getAuthMethodsConfig()
+ {
+ return authMethodsConfig;
+ }
+
bool needsWrite()
{
return needWrite;
@@ -501,6 +549,7 @@ class SessionStore
std::random_device rd;
bool needWrite{false};
std::chrono::minutes timeoutInMinutes;
+ AuthConfigMethods authMethodsConfig;
};
} // namespace persistent_data
@@ -526,4 +575,16 @@ struct adl_serializer<std::shared_ptr<crow::persistent_data::UserSession>>
}
}
};
+
+template <> struct adl_serializer<crow::persistent_data::AuthConfigMethods>
+{
+ static void to_json(nlohmann::json& j,
+ const crow::persistent_data::AuthConfigMethods& c)
+ {
+ j = nlohmann::json{{"XToken", c.xtoken},
+ {"Cookie", c.cookie},
+ {"SessionToken", c.sessionToken},
+ {"BasicAuth", c.basic}};
+ }
+};
} // namespace nlohmann
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 0a440501e1..7e4e3bb22f 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -31,8 +31,15 @@ class Middleware
return;
}
- req.session = performXtokenAuth(req);
- if (req.session == nullptr)
+ const crow::persistent_data::AuthConfigMethods& authMethodsConfig =
+ crow::persistent_data::SessionStore::getInstance()
+ .getAuthMethodsConfig();
+
+ if (req.session == nullptr && authMethodsConfig.xtoken)
+ {
+ req.session = performXtokenAuth(req);
+ }
+ if (req.session == nullptr && authMethodsConfig.cookie)
{
req.session = performCookieAuth(req);
}
@@ -42,11 +49,13 @@ class Middleware
if (!authHeader.empty())
{
// Reject any kind of auth other than basic or token
- if (boost::starts_with(authHeader, "Token "))
+ if (boost::starts_with(authHeader, "Token ") &&
+ authMethodsConfig.sessionToken)
{
req.session = performTokenAuth(authHeader);
}
- else if (boost::starts_with(authHeader, "Basic "))
+ else if (boost::starts_with(authHeader, "Basic ") &&
+ authMethodsConfig.basic)
{
req.session = performBasicAuth(authHeader);
}
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index 59e2d1cd67..bc8ce771d6 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -553,7 +553,8 @@ inline void getLDAPConfigData(const std::string& ldapType,
class AccountService : public Node
{
public:
- AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
+ AccountService(CrowApp& app) :
+ Node(app, "/redfish/v1/AccountService/"), app(app)
{
entityPrivileges = {
{boost::beast::http::verb::get,
@@ -887,6 +888,65 @@ class AccountService : public Node
ldapEnableInterface, "Enabled", std::variant<bool>(serviceEnabled));
}
+ void handleAuthMethodsPatch(nlohmann::json& input,
+ const std::shared_ptr<AsyncResp>& asyncResp)
+ {
+ std::optional<bool> basicAuth;
+ std::optional<bool> cookie;
+ std::optional<bool> sessionToken;
+ std::optional<bool> xToken;
+
+ if (!json_util::readJson(input, asyncResp->res, "BasicAuth", basicAuth,
+ "Cookie", cookie, "SessionToken", sessionToken,
+ "XToken", xToken))
+ {
+ BMCWEB_LOG_ERROR << "Cannot read values from AuthMethod tag";
+ return;
+ }
+
+ // Make a copy of methods configuration
+ crow::persistent_data::AuthConfigMethods authMethodsConfig =
+ crow::persistent_data::SessionStore::getInstance()
+ .getAuthMethodsConfig();
+
+ if (basicAuth)
+ {
+ authMethodsConfig.basic = *basicAuth;
+ }
+
+ if (cookie)
+ {
+ authMethodsConfig.cookie = *cookie;
+ }
+
+ if (sessionToken)
+ {
+ authMethodsConfig.sessionToken = *sessionToken;
+ }
+
+ if (xToken)
+ {
+ authMethodsConfig.xtoken = *xToken;
+ }
+
+ if (!authMethodsConfig.basic && !authMethodsConfig.cookie &&
+ !authMethodsConfig.sessionToken && !authMethodsConfig.xtoken)
+ {
+ // Do not allow user to disable everything
+ messages::actionNotSupported(asyncResp->res,
+ "of disabling all available methods");
+ return;
+ }
+
+ crow::persistent_data::SessionStore::getInstance()
+ .updateAuthMethodsConfig(authMethodsConfig);
+ // Save configuration immediately
+ app.template getMiddleware<crow::persistent_data::Middleware>()
+ .writeData();
+
+ messages::success(asyncResp->res);
+ }
+
/**
* @brief Get the required values from the given JSON, validates the
* value and create the LDAP config object.
@@ -1063,6 +1123,10 @@ class AccountService : public Node
void doGet(crow::Response& res, const crow::Request& req,
const std::vector<std::string>& params) override
{
+ const crow::persistent_data::AuthConfigMethods& authMethodsConfig =
+ crow::persistent_data::SessionStore::getInstance()
+ .getAuthMethodsConfig();
+
auto asyncResp = std::make_shared<AsyncResp>(res);
res.jsonValue = {
{"@odata.context", "/redfish/v1/"
@@ -1078,6 +1142,16 @@ class AccountService : public Node
{"Accounts",
{{"@odata.id", "/redfish/v1/AccountService/Accounts"}}},
{"Roles", {{"@odata.id", "/redfish/v1/AccountService/Roles"}}},
+ {"Oem",
+ {{"OpenBMC",
+ {{"@odata.type", "#OemAccountService.v1_0_0.AccountService"},
+ {"AuthMethods",
+ {
+ {"BasicAuth", authMethodsConfig.basic},
+ {"SessionToken", authMethodsConfig.sessionToken},
+ {"XToken", authMethodsConfig.xtoken},
+ {"Cookie", authMethodsConfig.cookie},
+ }}}}}},
{"LDAP",
{{"Certificates",
{{"@odata.id",
@@ -1155,13 +1229,14 @@ class AccountService : public Node
std::optional<uint16_t> maxPasswordLength;
std::optional<nlohmann::json> ldapObject;
std::optional<nlohmann::json> activeDirectoryObject;
-
- if (!json_util::readJson(req, res, "AccountLockoutDuration",
- unlockTimeout, "AccountLockoutThreshold",
- lockoutThreshold, "MaxPasswordLength",
- maxPasswordLength, "MinPasswordLength",
- minPasswordLength, "LDAP", ldapObject,
- "ActiveDirectory", activeDirectoryObject))
+ std::optional<nlohmann::json> oemObject;
+
+ if (!json_util::readJson(
+ req, res, "AccountLockoutDuration", unlockTimeout,
+ "AccountLockoutThreshold", lockoutThreshold,
+ "MaxPasswordLength", maxPasswordLength, "MinPasswordLength",
+ minPasswordLength, "LDAP", ldapObject, "ActiveDirectory",
+ activeDirectoryObject, "Oem", oemObject))
{
return;
}
@@ -1181,6 +1256,22 @@ class AccountService : public Node
handleLDAPPatch(*ldapObject, asyncResp, req, params, "LDAP");
}
+ if (std::optional<nlohmann::json> oemOpenBMCObject;
+ oemObject &&
+ json_util::readJson(*oemObject, res, "OpenBMC", oemOpenBMCObject))
+ {
+ if (std::optional<nlohmann::json> authMethodsObject;
+ oemOpenBMCObject &&
+ json_util::readJson(*oemOpenBMCObject, res, "AuthMethods",
+ authMethodsObject))
+ {
+ if (authMethodsObject)
+ {
+ handleAuthMethodsPatch(*authMethodsObject, asyncResp);
+ }
+ }
+ }
+
if (activeDirectoryObject)
{
handleLDAPPatch(*activeDirectoryObject, asyncResp, req, params,
@@ -1221,6 +1312,8 @@ class AccountService : public Node
std::variant<uint16_t>(*lockoutThreshold));
}
}
+
+ CrowApp& app;
};
class AccountsCollection : public Node
diff --git a/static/redfish/v1/$metadata/index.xml b/static/redfish/v1/$metadata/index.xml
index 73833652d7..4804e48024 100644
--- a/static/redfish/v1/$metadata/index.xml
+++ b/static/redfish/v1/$metadata/index.xml
@@ -1045,6 +1045,10 @@
<edmx:Include Namespace="NetworkPort.v1_2_2"/>
<edmx:Include Namespace="NetworkPort.v1_2_3"/>
</edmx:Reference>
+ <edmx:Reference Uri="/redfish/v1/schema/OemAccountService_v1.xml">
+ <edmx:Include Namespace="OemAccountService"/>
+ <edmx:Include Namespace="OemAccountService.v1_0_0"/>
+ </edmx:Reference>
<edmx:Reference Uri="/redfish/v1/schema/NetworkPortCollection_v1.xml">
<edmx:Include Namespace="NetworkPortCollection"/>
</edmx:Reference>
diff --git a/static/redfish/v1/JsonSchemas/OemAccountService/index.json b/static/redfish/v1/JsonSchemas/OemAccountService/index.json
new file mode 100644
index 0000000000..528317086c
--- /dev/null
+++ b/static/redfish/v1/JsonSchemas/OemAccountService/index.json
@@ -0,0 +1,102 @@
+{
+ "$id": "http://redfish.dmtf.org/schemas/v1/OemAccountService.v1_0_0.json",
+ "$schema": "http://redfish.dmtf.org/schemas/v1/redfish-schema-v1.json",
+ "copyright": "Copyright 2014-2019 DMTF. For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright",
+ "definitions": {
+ "AccountService": {
+ "additionalProperties": false,
+ "description": "OEM Extension for AccountService",
+ "longDescription": "OEM Extension for AccountService providing info about TLS Auth.",
+ "patternProperties": {
+ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": {
+ "description": "This property shall specify a valid odata or Redfish property.",
+ "type": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "null",
+ "object",
+ "string"
+ ]
+ }
+ },
+ "properties": {
+ "AuthMethods": {
+ "anyOf": [
+ {
+ "$ref": "#/definitions/AuthMethodsConfig"
+ },
+ {
+ "type": "null"
+ }
+ ],
+ "description": "Authorization Methods configuration.",
+ "longDescription": "Configuration describing which auth methods are enabled."
+ }
+ },
+ "type": "object"
+ },
+ "AuthMethodsConfig": {
+ "additionalProperties": false,
+ "description": "Authorization Methods configuration.",
+ "longDescription": "Configuration describing which auth methods are enabled.",
+ "patternProperties": {
+ "^([a-zA-Z_][a-zA-Z0-9_]*)?@(odata|Redfish|Message)\\.[a-zA-Z_][a-zA-Z0-9_]*$": {
+ "description": "This property shall specify a valid odata or Redfish property.",
+ "type": [
+ "array",
+ "boolean",
+ "integer",
+ "number",
+ "null",
+ "object",
+ "string"
+ ]
+ }
+ },
+ "properties": {
+ "BasicAuth": {
+ "description": "Indicates whether BasicAuth authorization is enabled.",
+ "longDescription": "The value of this property shall be a boolean indicating whether BasicAuth authorization is enabled.",
+ "readonly": false,
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "Cookie": {
+ "description": "Indicates whether Cookie authorization is enabled.",
+ "longDescription": "The value of this property shall be a boolean indicating whether Cookie authorization is enabled.",
+ "readonly": false,
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "SessionToken": {
+ "description": "Indicates whether SessionToken authorization is enabled.",
+ "longDescription": "The value of this property shall be a boolean indicating whether SessionToken authorization is enabled.",
+ "readonly": false,
+ "type": [
+ "boolean",
+ "null"
+ ]
+ },
+ "XToken": {
+ "description": "Indicates whether XToken authorization is enabled.",
+ "longDescription": "The value of this property shall be a boolean indicating whether XToken authorization is enabled.",
+ "readonly": false,
+ "type": [
+ "boolean",
+ "null"
+ ]
+ }
+ },
+ "type": "object"
+ }
+ },
+ "owningEntity": "OpenBMC",
+ "release": "1.0",
+ "title": "#OemAccountService.v1_0_0"
+} \ No newline at end of file
diff --git a/static/redfish/v1/schema/OemAccountService_v1.xml b/static/redfish/v1/schema/OemAccountService_v1.xml
new file mode 100644
index 0000000000..626097b3c8
--- /dev/null
+++ b/static/redfish/v1/schema/OemAccountService_v1.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0">
+
+ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml">
+ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData"/>
+ </edmx:Reference>
+ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Measures.V1.xml">
+ <edmx:Include Namespace="Org.OData.Measures.V1" Alias="Measures"/>
+ </edmx:Reference>
+ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml">
+ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/>
+ </edmx:Reference>
+ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml">
+ <edmx:Include Namespace="Resource"/>
+ <edmx:Include Namespace="Resource.v1_0_0"/>
+ </edmx:Reference>
+
+ <edmx:DataServices>
+
+ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OemAccountService">
+ <Annotation Term="Redfish.OwningEntity" String="OpenBMC"/>
+ </Schema>
+
+ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="OemAccountService.v1_0_0">
+ <Annotation Term="Redfish.OwningEntity" String="OpenBMC"/>
+ <Annotation Term="Redfish.Release" String="1.0"/>
+
+ <ComplexType Name="AuthMethodsConfig">
+ <Annotation Term="OData.AdditionalProperties" Bool="false"/>
+ <Annotation Term="OData.Description" String="Authorization Methods configuration."/>
+ <Annotation Term="OData.LongDescription" String="Configuration describing which auth methods are enabled."/>
+
+ <Property Name="BasicAuth" Type="Edm.Boolean">
+ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/>
+ <Annotation Term="OData.Description" String="Indicates whether BasicAuth authorization is enabled."/>
+ <Annotation Term="OData.LongDescription" String="The value of this property shall be a boolean indicating whether BasicAuth authorization is enabled."/>
+ </Property>
+
+ <Property Name="Cookie" Type="Edm.Boolean">
+ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/>
+ <Annotation Term="OData.Description" String="Indicates whether Cookie authorization is enabled."/>
+ <Annotation Term="OData.LongDescription" String="The value of this property shall be a boolean indicating whether Cookie authorization is enabled."/>
+ </Property>
+
+ <Property Name="SessionToken" Type="Edm.Boolean">
+ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/>
+ <Annotation Term="OData.Description" String="Indicates whether SessionToken authorization is enabled."/>
+ <Annotation Term="OData.LongDescription" String="The value of this property shall be a boolean indicating whether SessionToken authorization is enabled."/>
+ </Property>
+
+ <Property Name="XToken" Type="Edm.Boolean">
+ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/ReadWrite"/>
+ <Annotation Term="OData.Description" String="Indicates whether XToken authorization is enabled."/>
+ <Annotation Term="OData.LongDescription" String="The value of this property shall be a boolean indicating whether XToken authorization is enabled."/>
+ </Property>
+ </ComplexType>
+
+ <!--Base entity type for array members-->
+ <EntityType Name="AccountService" BaseType="Resource.OemObject" Abstract="true">
+ <Annotation Term="OData.Description" String="OEM Extension for AccountService"/>
+ <Annotation Term="OData.LongDescription" String="OEM Extension for AccountService providing info about TLS Auth."/>
+
+ <Property Name="AuthMethods" Type="OemAccountService.v1_0_0.AuthMethodsConfig">
+ <Annotation Term="OData.Description" String="Authorization Methods configuration."/>
+ <Annotation Term="OData.LongDescription" String="Configuration describing which auth methods are enabled."/>
+ </Property>
+ </EntityType>
+ </Schema>
+
+ </edmx:DataServices>
+</edmx:Edmx>