mirror of https://github.com/Icinga/icinga2.git
parent
adc054097d
commit
6504606e23
|
@ -108,8 +108,9 @@ Configuration Attributes:
|
||||||
Name | Type | Description
|
Name | Type | Description
|
||||||
--------------------------|-----------------------|----------------------------------
|
--------------------------|-----------------------|----------------------------------
|
||||||
password | String | **Optional.** Password string. Note: This attribute is hidden in API responses.
|
password | String | **Optional.** Password string. Note: This attribute is hidden in API responses.
|
||||||
|
hashed\_password | 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).
|
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.
|
permissions | Array | **Required.** Array of permissions. Either as string or dictionary with the keys `permission` and `filter`. The latter must be specified as function.
|
||||||
|
|
||||||
Available permissions are explained in the [API permissions](12-icinga2-api.md#icinga2-api-permissions)
|
Available permissions are explained in the [API permissions](12-icinga2-api.md#icinga2-api-permissions)
|
||||||
chapter.
|
chapter.
|
||||||
|
|
|
@ -19,7 +19,8 @@ Usage:
|
||||||
icinga2 <command> [<arguments>]
|
icinga2 <command> [<arguments>]
|
||||||
|
|
||||||
Supported commands:
|
Supported commands:
|
||||||
* api setup (setup for api)
|
* api setup (setup for API)
|
||||||
|
* api user (API user creation helper)
|
||||||
* ca list (lists all certificate signing requests)
|
* ca list (lists all certificate signing requests)
|
||||||
* ca sign (signs an outstanding certificate request)
|
* ca sign (signs an outstanding certificate request)
|
||||||
* console (Icinga console)
|
* console (Icinga console)
|
||||||
|
@ -135,8 +136,9 @@ added.
|
||||||
|
|
||||||
## CLI command: Api <a id="cli-command-api"></a>
|
## CLI command: Api <a id="cli-command-api"></a>
|
||||||
|
|
||||||
Provides the setup CLI command to enable the REST API. More details
|
Provides the helper functions `api setup` and `api user`. The first to enable the REST API, the second to create
|
||||||
in the [Icinga 2 API](12-icinga2-api.md#icinga2-api-setup) chapter.
|
ApiUser objects with hashed password strings.
|
||||||
|
More details in the [Icinga 2 API](12-icinga2-api.md#icinga2-api-setup) chapter.
|
||||||
|
|
||||||
```
|
```
|
||||||
# icinga2 api --help
|
# icinga2 api --help
|
||||||
|
@ -146,7 +148,8 @@ Usage:
|
||||||
icinga2 <command> [<arguments>]
|
icinga2 <command> [<arguments>]
|
||||||
|
|
||||||
Supported commands:
|
Supported commands:
|
||||||
* api setup (setup for api)
|
* api setup (setup for API)
|
||||||
|
* api user (API user creation helper)
|
||||||
|
|
||||||
Global options:
|
Global options:
|
||||||
-h [ --help ] show this help message
|
-h [ --help ] show this help message
|
||||||
|
|
|
@ -21,6 +21,25 @@ If you prefer to set up the API manually, you will have to perform the following
|
||||||
|
|
||||||
The next chapter provides a quick overview of how you can use the API.
|
The next chapter provides a quick overview of how you can use the API.
|
||||||
|
|
||||||
|
### Creating ApiUsers
|
||||||
|
|
||||||
|
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 --passwd 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>
|
## Introduction <a id="icinga2-api-introduction"></a>
|
||||||
|
|
||||||
The Icinga 2 API allows you to manage configuration objects
|
The Icinga 2 API allows you to manage configuration objects
|
||||||
|
|
|
@ -624,6 +624,19 @@ String PBKDF2_SHA1(const String& password, const String& salt, int iterations)
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String PBKDF2_SHA256(const String& password, const String& salt, int iterations)
|
||||||
|
{
|
||||||
|
unsigned char digest[SHA256_DIGEST_LENGTH];
|
||||||
|
PKCS5_PBKDF2_HMAC(password.CStr(), password.GetLength(), reinterpret_cast<const unsigned char *>(salt.CStr()),
|
||||||
|
salt.GetLength(), iterations, EVP_sha256(), SHA256_DIGEST_LENGTH, digest);
|
||||||
|
|
||||||
|
char output[SHA256_DIGEST_LENGTH*2+1];
|
||||||
|
for (int i = 0; i < SHA256_DIGEST_LENGTH; i++)
|
||||||
|
sprintf(output + 2 * i, "%02x", digest[i]);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
String SHA1(const String& s, bool binary)
|
String SHA1(const String& s, bool binary)
|
||||||
{
|
{
|
||||||
char errbuf[120];
|
char errbuf[120];
|
||||||
|
|
|
@ -52,6 +52,7 @@ boost::shared_ptr<X509> I2_BASE_API StringToCertificate(const String& cert);
|
||||||
boost::shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject);
|
boost::shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(EVP_PKEY *pubkey, X509_NAME *subject);
|
||||||
boost::shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(const boost::shared_ptr<X509>& cert);
|
boost::shared_ptr<X509> I2_BASE_API CreateCertIcingaCA(const boost::shared_ptr<X509>& cert);
|
||||||
String I2_BASE_API PBKDF2_SHA1(const String& password, const String& salt, int iterations);
|
String I2_BASE_API PBKDF2_SHA1(const String& password, const String& salt, int iterations);
|
||||||
|
String I2_BASE_API PBKDF2_SHA256(const String& password, const String& salt, int iterations);
|
||||||
String I2_BASE_API SHA1(const String& s, bool binary = false);
|
String I2_BASE_API SHA1(const String& s, bool binary = false);
|
||||||
String I2_BASE_API SHA256(const String& s);
|
String I2_BASE_API SHA256(const String& s);
|
||||||
String I2_BASE_API RandomString(int length);
|
String I2_BASE_API RandomString(int length);
|
||||||
|
|
|
@ -26,7 +26,7 @@ set(cli_SOURCES
|
||||||
objectlistcommand.cpp objectlistutility.cpp
|
objectlistcommand.cpp objectlistutility.cpp
|
||||||
pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkisavecertcommand.cpp pkiticketcommand.cpp
|
pkinewcacommand.cpp pkinewcertcommand.cpp pkisigncsrcommand.cpp pkirequestcommand.cpp pkisavecertcommand.cpp pkiticketcommand.cpp
|
||||||
variablegetcommand.cpp variablelistcommand.cpp variableutility.cpp
|
variablegetcommand.cpp variablelistcommand.cpp variableutility.cpp
|
||||||
troubleshootcommand.cpp
|
apiusercommand.cpp troubleshootcommand.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ICINGA2_UNITY_BUILD)
|
if(ICINGA2_UNITY_BUILD)
|
||||||
|
|
|
@ -36,7 +36,7 @@ String ApiSetupCommand::GetDescription(void) const
|
||||||
|
|
||||||
String ApiSetupCommand::GetShortDescription(void) const
|
String ApiSetupCommand::GetShortDescription(void) const
|
||||||
{
|
{
|
||||||
return "setup for api";
|
return "setup for API";
|
||||||
}
|
}
|
||||||
|
|
||||||
ImpersonationLevel ApiSetupCommand::GetImpersonationLevel(void) const
|
ImpersonationLevel ApiSetupCommand::GetImpersonationLevel(void) const
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* 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 "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")
|
||||||
|
("passwd", po::value<std::string>(), "Password in clear text")
|
||||||
|
("salt", po::value<std::string>(), "Optional salt (default: 8 random chars)");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
{
|
||||||
|
if (!vm.count("user")) {
|
||||||
|
Log(LogCritical, "cli", "Username (--user) must be specified.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!vm.count("passwd")) {
|
||||||
|
Log(LogCritical, "cli", "Password (--passwd) must be specified.");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
String user = vm["user"].as<std::string>();
|
||||||
|
String passwd = vm["passwd"].as<std::string>();
|
||||||
|
String salt = vm.count("salt") ? String(vm["salt"].as<std::string>()) : RandomString(8);
|
||||||
|
|
||||||
|
String hashedPassword = ApiUser::CreateHashedPasswordString(passwd, salt, true);
|
||||||
|
|
||||||
|
std::cout
|
||||||
|
<< "object ApiUser \"" << user << "\" {\n"
|
||||||
|
<< " password_hash =\"" << hashedPassword << "\"\n"
|
||||||
|
<< " // client_cn = \"\"\n"
|
||||||
|
<< "\n"
|
||||||
|
<< " permissions = [ \"*\" ]\n"
|
||||||
|
<< "}\n";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* 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 */
|
|
@ -21,11 +21,20 @@
|
||||||
#include "remote/apiuser.tcpp"
|
#include "remote/apiuser.tcpp"
|
||||||
#include "base/configtype.hpp"
|
#include "base/configtype.hpp"
|
||||||
#include "base/base64.hpp"
|
#include "base/base64.hpp"
|
||||||
|
#include "base/tlsutility.hpp"
|
||||||
|
|
||||||
using namespace icinga;
|
using namespace icinga;
|
||||||
|
|
||||||
REGISTER_TYPE(ApiUser);
|
REGISTER_TYPE(ApiUser);
|
||||||
|
|
||||||
|
void ApiUser::OnConfigLoaded(void)
|
||||||
|
{
|
||||||
|
ObjectImpl<ApiUser>::OnConfigLoaded();
|
||||||
|
|
||||||
|
if (this->GetPasswordHash().IsEmpty())
|
||||||
|
SetPasswordHash(CreateHashedPasswordString(GetPassword(), RandomString(8), true));
|
||||||
|
}
|
||||||
|
|
||||||
ApiUser::Ptr ApiUser::GetByClientCN(const String& cn)
|
ApiUser::Ptr ApiUser::GetByClientCN(const String& cn)
|
||||||
{
|
{
|
||||||
for (const ApiUser::Ptr& user : ConfigType::GetObjectsByType<ApiUser>()) {
|
for (const ApiUser::Ptr& user : ConfigType::GetObjectsByType<ApiUser>()) {
|
||||||
|
@ -63,3 +72,50 @@ ApiUser::Ptr ApiUser::GetByAuthHeader(const String& auth_header)
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ApiUser::ComparePassword(String password) const
|
||||||
|
{
|
||||||
|
Dictionary::Ptr passwordDict = this->GetPasswordDict();
|
||||||
|
String thisPassword = passwordDict->Get("password");
|
||||||
|
String otherPassword = CreateHashedPasswordString(password, passwordDict->Get("salt"), false);
|
||||||
|
|
||||||
|
const char *p1 = otherPassword.CStr();
|
||||||
|
const char *p2 = thisPassword.CStr();
|
||||||
|
|
||||||
|
volatile char c = 0;
|
||||||
|
|
||||||
|
for (size_t i=0; i<64; ++i)
|
||||||
|
c |= p1[i] ^ p2[i];
|
||||||
|
|
||||||
|
return (c == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dictionary::Ptr ApiUser::GetPasswordDict(void) const
|
||||||
|
{
|
||||||
|
String password = this->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;
|
||||||
|
}
|
||||||
|
|
||||||
|
String ApiUser::CreateHashedPasswordString(const String& password, const String& salt, const bool shadow)
|
||||||
|
{
|
||||||
|
if (shadow)
|
||||||
|
//Using /etc/shadow password format. The 5 means SHA256 is being used
|
||||||
|
return String("$5$" + salt + "$" + PBKDF2_SHA256(password, salt, 1000));
|
||||||
|
else
|
||||||
|
return PBKDF2_SHA256(password, salt, 1000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -35,8 +35,14 @@ public:
|
||||||
DECLARE_OBJECT(ApiUser);
|
DECLARE_OBJECT(ApiUser);
|
||||||
DECLARE_OBJECTNAME(ApiUser);
|
DECLARE_OBJECTNAME(ApiUser);
|
||||||
|
|
||||||
|
virtual void OnConfigLoaded(void) override;
|
||||||
|
|
||||||
static ApiUser::Ptr GetByClientCN(const String& cn);
|
static ApiUser::Ptr GetByClientCN(const String& cn);
|
||||||
static ApiUser::Ptr GetByAuthHeader(const String& auth_header);
|
static ApiUser::Ptr GetByAuthHeader(const String& auth_header);
|
||||||
|
static String CreateHashedPasswordString(const String& password, const String& salt, const bool shadow = false);
|
||||||
|
|
||||||
|
Dictionary::Ptr GetPasswordDict(void) const;
|
||||||
|
bool ComparePassword(String password) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,9 @@ namespace icinga
|
||||||
|
|
||||||
class ApiUser : ConfigObject
|
class ApiUser : ConfigObject
|
||||||
{
|
{
|
||||||
[config, no_user_view] String password;
|
/* No show config */
|
||||||
|
[no_user_view, no_user_modify] String password;
|
||||||
|
[config, no_user_view] String password_hash;
|
||||||
[config] String client_cn (ClientCN);
|
[config] String client_cn (ClientCN);
|
||||||
[config] array(Value) permissions;
|
[config] array(Value) permissions;
|
||||||
};
|
};
|
||||||
|
|
|
@ -27,6 +27,7 @@ set(base_test_SOURCES
|
||||||
base-value.cpp config-ops.cpp icinga-checkresult.cpp icinga-macros.cpp
|
base-value.cpp config-ops.cpp icinga-checkresult.cpp icinga-macros.cpp
|
||||||
icinga-notification.cpp
|
icinga-notification.cpp
|
||||||
icinga-perfdata.cpp remote-url.cpp
|
icinga-perfdata.cpp remote-url.cpp
|
||||||
|
remote-user.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ICINGA2_UNITY_BUILD)
|
if(ICINGA2_UNITY_BUILD)
|
||||||
|
@ -118,6 +119,7 @@ add_boost_test(base
|
||||||
remote_url/get_and_set
|
remote_url/get_and_set
|
||||||
remote_url/format
|
remote_url/format
|
||||||
remote_url/illegal_legal_strings
|
remote_url/illegal_legal_strings
|
||||||
|
api_user/password
|
||||||
)
|
)
|
||||||
|
|
||||||
if(ICINGA2_WITH_LIVESTATUS)
|
if(ICINGA2_WITH_LIVESTATUS)
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
#ifndef I2_DEBUG
|
||||||
|
std::cout << "Only enabled in Debug builds..." << std::endl;
|
||||||
|
#else
|
||||||
|
ApiUser::Ptr user = new ApiUser();
|
||||||
|
String passwd = RandomString(16);
|
||||||
|
String salt = RandomString(8);
|
||||||
|
user->SetPassword("ThisShouldBeIgnored");
|
||||||
|
user->SetPasswordHash(ApiUser::CreateHashedPasswordString(passwd, salt, true));
|
||||||
|
|
||||||
|
BOOST_CHECK(user->GetPasswordHash() != passwd);
|
||||||
|
|
||||||
|
Dictionary::Ptr passwdd = user->GetPasswordDict();
|
||||||
|
|
||||||
|
BOOST_CHECK(passwdd);
|
||||||
|
BOOST_CHECK(passwdd->Get("salt") == salt);
|
||||||
|
BOOST_CHECK(user->ComparePassword(passwd));
|
||||||
|
BOOST_CHECK(!user->ComparePassword("wrong password uwu!"));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
Loading…
Reference in New Issue