Name | Type | Description
--------------------------|-----------------------|----------------------------------
password | String | **Optional.** Password string. Note: This attribute is hidden in API responses.
- password\_hash | String | **Optional.** A hashed password string in the form of /etc/shadow. Note: This attribute is hidden in API responses.
client\_cn | String | **Optional.** Client Common Name (CN).
permissions | Array | **Required.** Array of permissions. Either as string or dictionary with the keys `permission` and `filter`. The latter must be specified as function.
Supported commands:
* api setup (setup for API)
- * api user (API user creation helper)
* ca list (lists all certificate signing requests)
* ca sign (signs an outstanding certificate request)
* console (Icinga console)
The next chapter provides a quick overview of how you can use the API.
-### Creating ApiUsers <a id="icinga2-api-creating-users"></a>
-
-The CLI command `icinga2 api user` allows you to create an ApiUser object with a hashed password string, ready to be
-added to your configuration. Example:
-
-```
-$ icinga2 api user --user icingaweb2 --password icinga
-object ApiUser "icingaweb2" {
- password_hash ="$5$d5f1a17ea308acb6$9e9fd5d24a9373a16e8811765cc5a5939687faf9ef8ed496db6e7f1d0ae9b2a9"
- // client_cn = ""
-
- permissions = [ "*" ]
-}
-```
-
-Optionally a salt can be provided with `--salt`, otherwise a random value will be used. When ApiUsers are stored this
-way, even somebody able to read the configuration files won't be able to authenticate using this information. There is
-no way to recover your password should you forget it, you'd need to create it anew.
-
## Introduction <a id="icinga2-api-introduction"></a>
The Icinga 2 API allows you to manage configuration objects
The `node setup` parameter `--master_host` was deprecated and replaced with `--parent_host`. This parameter is now optional to allow connection-less client setups similar to the `node wizard` CLI command. The `parent_zone` parameter has been added to modify the parent zone name e.g. for client-to-satellite setups.
+The `api user` command which was released in v2.8.2 turned out to cause huge problems with
+configuration validation, windows restarts and OpenSSL versions. It is therefore removed in 2.9,
+the `password_hash` attribute for the ApiUser object stays intact but has no effect. This is to ensure
+that clients don't break on upgrade. We will revise this feature in future development iterations.
+
## Upgrading to v2.8.2 <a id="upgrading-to-2-8-2"></a>
With version 2.8.2 the location of settings formerly found in `/etc/icinga2/init.conf` has changed. They are now
return "[errinfo_openssl_error]" + tmp.str() + "\n";
}
-bool ComparePassword(const String& hash, const String& password, const String& salt)
-{
- String otherHash = PBKDF2_SHA256(password, salt, 1000);
- VERIFY(otherHash.GetLength() == 64 && hash.GetLength() == 64);
-
- const char *p1 = otherHash.CStr();
- const char *p2 = hash.CStr();
-
- /* By Novelocrat, https://stackoverflow.com/a/25374036 */
- volatile char c = 0;
-
- for (size_t i = 0; i < 64; ++i)
- c |= p1[i] ^ p2[i];
-
- return (c == 0);
-}
-
-/* Returns a String in the format $algorithm$salt$hash or returns an empty string in case of an error */
-String CreateHashedPasswordString(const String& password, const String& salt, int algorithm)
-{
- // We currently only support SHA256
- if (algorithm != 5)
- return String();
-
- if (salt.FindFirstOf('$') != String::NPos)
- return String();
-
- return String("$5$" + salt + "$" + PBKDF2_SHA256(password, salt, 1000));
-}
-
}
String SHA256(const String& s);
String RandomString(int length);
bool VerifyCertificate(const std::shared_ptr<X509>& caCertificate, const std::shared_ptr<X509>& certificate);
-bool ComparePassword(const String& hash, const String& password, const String& Salt);
-String CreateHashedPasswordString(const String& password, const String& salt, int algorithm = 5);
class openssl_error : virtual public std::exception, virtual public boost::exception { };
set(cli_SOURCES
i2-cli.hpp
apisetupcommand.cpp apisetupcommand.hpp
- apiusercommand.cpp apiusercommand.hpp
apisetuputility.cpp apisetuputility.hpp
calistcommand.cpp calistcommand.hpp
casigncommand.cpp casigncommand.hpp
+++ /dev/null
-/******************************************************************************
- * Icinga 2 *
- * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License *
- * as published by the Free Software Foundation; either version 2 *
- * of the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software Foundation *
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
- ******************************************************************************/
-
-#include "cli/apiusercommand.hpp"
-#include "base/logger.hpp"
-#include "base/tlsutility.hpp"
-#include "base/configwriter.hpp"
-#include "remote/apiuser.hpp"
-#include <iostream>
-
-using namespace icinga;
-namespace po = boost::program_options;
-
-REGISTER_CLICOMMAND("api/user", ApiUserCommand);
-
-String ApiUserCommand::GetDescription(void) const
-{
- return "Create a hashed user and password string for the Icinga 2 API";
-}
-
-String ApiUserCommand::GetShortDescription(void) const
-{
- return "API user creation helper";
-}
-
-void ApiUserCommand::InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const
-{
- visibleDesc.add_options()
- ("user", po::value<std::string>(), "API username")
- ("password", po::value<std::string>(), "Password in clear text")
- ("salt", po::value<std::string>(), "Optional salt (default: 8 random chars)")
- ("oneline", "Print only the password hash");
-}
-
-/**
- * The entry point for the "api user" CLI command.
- *
- * @returns An exit status.
- */
-int ApiUserCommand::Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const
-{
- String passwd, salt;
- if (!vm.count("user") && !vm.count("oneline")) {
- Log(LogCritical, "cli", "Username (--user) must be specified.");
- return 1;
- }
-
- if (!vm.count("password")) {
- Log(LogCritical, "cli", "Password (--password) must be specified.");
- return 1;
- }
-
- passwd = vm["password"].as<std::string>();
- salt = vm.count("salt") ? String(vm["salt"].as<std::string>()) : RandomString(8);
-
- if (salt.FindFirstOf('$') != String::NPos) {
- Log(LogCritical, "cli", "Salt (--salt) may not contain '$'");
- return 1;
- }
-
- String hashedPassword = CreateHashedPasswordString(passwd, salt, 5);
- if (hashedPassword == String()) {
- Log(LogCritical, "cli") << "Failed to hash password \"" << passwd << "\" with salt \"" << salt << "\"";
- return 1;
- }
-
- if (vm.count("oneline"))
- std::cout << hashedPassword << std::endl;
- else {
- std::cout << "object ApiUser ";
-
- ConfigWriter::EmitString(std::cout, vm["user"].as<std::string>());
-
- std::cout << "{\n"
- << " password_hash = ";
-
- ConfigWriter::EmitString(std::cout, hashedPassword);
-
- std::cout << "\n"
- << " // client_cn = \"\"\n"
- << "\n"
- << " permissions = [ \"*\" ]\n"
- << "}\n";
- }
-
- return 0;
-}
+++ /dev/null
-/******************************************************************************
- * Icinga 2 *
- * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License *
- * as published by the Free Software Foundation; either version 2 *
- * of the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software Foundation *
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
- ******************************************************************************/
-
-#ifndef APIUSERCOMMAND_H
-#define APIUSERCOMMAND_H
-
-#include "cli/clicommand.hpp"
-
-namespace icinga
-{
-
-/**
- * The "api user" command.
- *
- * @ingroup cli
- */
-class ApiUserCommand : public CLICommand
-{
-public:
- DECLARE_PTR_TYPEDEFS(ApiUserCommand);
-
- virtual String GetDescription(void) const override;
- virtual String GetShortDescription(void) const override;
- virtual void InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const override;
- virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const override;
-};
-
-}
-
-#endif /* APIUSERCOMMAND_H */
REGISTER_TYPE(ApiUser);
-void ApiUser::OnConfigLoaded(void)
-{
- ObjectImpl<ApiUser>::OnConfigLoaded();
-
- if (GetPasswordHash().IsEmpty()) {
- String hashedPassword = CreateHashedPasswordString(GetPassword(), RandomString(8), 5);
- VERIFY(hashedPassword != String());
- SetPasswordHash(hashedPassword);
- SetPassword("********");
- }
-}
-
ApiUser::Ptr ApiUser::GetByClientCN(const String& cn)
{
for (const ApiUser::Ptr& user : ConfigType::GetObjectsByType<ApiUser>()) {
*/
if (!user || password.IsEmpty())
return nullptr;
- else if (user && user->GetPassword() != password) {
- Dictionary::Ptr passwordDict = user->GetPasswordDict();
- if (!passwordDict || !ComparePassword(passwordDict->Get("password"), password, passwordDict->Get("salt")))
- return nullptr;
- }
+ else if (user && user->GetPassword() != password)
+ return nullptr;
return user;
}
-Dictionary::Ptr ApiUser::GetPasswordDict(void) const
-{
- String password = GetPasswordHash();
- if (password.IsEmpty() || password[0] != '$')
- return nullptr;
-
- String::SizeType saltBegin = password.FindFirstOf('$', 1);
- String::SizeType passwordBegin = password.FindFirstOf('$', saltBegin+1);
-
- if (saltBegin == String::NPos || saltBegin == 1 || passwordBegin == String::NPos)
- return nullptr;
-
- Dictionary::Ptr passwordDict = new Dictionary();
- passwordDict->Set("algorithm", password.SubStr(1, saltBegin - 1));
- passwordDict->Set("salt", password.SubStr(saltBegin + 1, passwordBegin - saltBegin - 1));
- passwordDict->Set("password", password.SubStr(passwordBegin + 1));
-
- return passwordDict;
-}
DECLARE_OBJECT(ApiUser);
DECLARE_OBJECTNAME(ApiUser);
- virtual void OnConfigLoaded(void) override;
-
static ApiUser::Ptr GetByClientCN(const String& cn);
static ApiUser::Ptr GetByAuthHeader(const String& auth_header);
-
- Dictionary::Ptr GetPasswordDict(void) const;
};
}
{
/* No show config */
[no_user_view, no_user_modify] String password;
- [config, no_user_view] String password_hash;
+ [deprecated, config, no_user_view] String password_hash;
[config] String client_cn (ClientCN);
[config] array(Value) permissions;
};
icinga-notification.cpp
icinga-perfdata.cpp
remote-url.cpp
- remote-user.cpp
${base_OBJS}
$<TARGET_OBJECTS:config>
$<TARGET_OBJECTS:remote>
remote_url/get_and_set
remote_url/format
remote_url/illegal_legal_strings
- api_user/password
)
if(ICINGA2_WITH_LIVESTATUS)
+++ /dev/null
-/******************************************************************************
- * Icinga 2 *
- * Copyright (C) 2012-2017 Icinga Development Team (https://www.icinga.com/) *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License *
- * as published by the Free Software Foundation; either version 2 *
- * of the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software Foundation *
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
- ******************************************************************************/
-
-#include "remote/apiuser.hpp"
-#include "base/tlsutility.hpp"
-#include <BoostTestTargetConfig.h>
-
-#include <iostream>
-
-using namespace icinga;
-
-BOOST_AUTO_TEST_SUITE(api_user)
-
-BOOST_AUTO_TEST_CASE(password)
-{
- ApiUser::Ptr user = new ApiUser();
- String passwd = RandomString(16);
- String salt = RandomString(8);
- user->SetPasswordHash(CreateHashedPasswordString(passwd, salt));
- user->OnConfigLoaded();
- user->OnAllConfigLoaded();
- user->Start();
-
- BOOST_CHECK(user->GetPasswordHash() != passwd);
-
- Dictionary::Ptr passwdd = user->GetPasswordDict();
-
- BOOST_CHECK(passwdd);
- BOOST_CHECK(passwdd->Get("salt") == salt);
- BOOST_CHECK(ComparePassword(passwdd->Get("password"), passwd, salt));
- BOOST_CHECK(!ComparePassword(passwdd->Get("password"), "wrong password uwu!", salt));
-}
-
-BOOST_AUTO_TEST_SUITE_END()