user.hpp
// ---------------------------------------------------------------------
// pion: a Boost C++ framework for building lightweight HTTP interfaces
// ---------------------------------------------------------------------
// Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//
#ifndef __PION_USER_HEADER__
#define __PION_USER_HEADER__
#include <map>
#include <string>
#include <cstdio>
#include <cstring>
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <pion/config.hpp>
#include <pion/error.hpp>
#ifdef PION_HAVE_SSL
#if defined(__APPLE__)
// suppress warnings about OpenSSL being deprecated in OSX
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <openssl/sha.h>
#endif
namespace pion { // begin namespace pion
class user :
private boost::noncopyable
{
public:
user(std::string const &username) :
m_username(username)
#ifdef PION_HAVE_SSL
, m_password_hash_type(EMPTY)
#endif
{}
user(std::string const &username, std::string const &password) :
m_username(username)
#ifdef PION_HAVE_SSL
, m_password_hash_type(EMPTY)
#endif
{
set_password(password);
}
virtual ~user() {}
std::string const & get_username() const { return m_username; }
std::string const & get_password() const { return m_password; }
virtual bool match_password(const std::string& password) const {
#ifdef PION_HAVE_SSL
if (m_password_hash_type == SHA_256) {
unsigned char sha256_hash[SHA256_DIGEST_LENGTH];
SHA256(reinterpret_cast<const unsigned char *>(password.data()), password.size(), sha256_hash);
return (memcmp(sha256_hash, m_password_hash, SHA256_DIGEST_LENGTH) == 0);
} else if (m_password_hash_type == SHA_1) {
unsigned char sha1_hash[SHA_DIGEST_LENGTH];
SHA1(reinterpret_cast<const unsigned char *>(password.data()), password.size(), sha1_hash);
return (memcmp(sha1_hash, m_password_hash, SHA_DIGEST_LENGTH) == 0);
} else
return false;
#else
return m_password == password;
#endif
}
virtual void set_password(const std::string& password) {
#ifdef PION_HAVE_SSL
// store encrypted hash value
SHA256((const unsigned char *)password.data(), password.size(), m_password_hash);
m_password_hash_type = SHA_256;
// update password string (convert binary to hex)
m_password.clear();
char buf[3];
for (unsigned int n = 0; n < SHA256_DIGEST_LENGTH; ++n) {
sprintf(buf, "%.2x", static_cast<unsigned int>(m_password_hash[n]));
m_password += buf;
}
#else
m_password = password;
#endif
}
#ifdef PION_HAVE_SSL
virtual void set_password_hash(const std::string& password_hash) {
// update password string representation
if (password_hash.size() == SHA256_DIGEST_LENGTH * 2) {
m_password_hash_type = SHA_256;
} else if (password_hash.size() == SHA_DIGEST_LENGTH * 2) {
m_password_hash_type = SHA_1;
} else {
BOOST_THROW_EXCEPTION( error::bad_password_hash() );
}
m_password = password_hash;
// convert string from hex to binary value
char buf[3];
buf[2] = '\0';
unsigned int hash_pos = 0;
std::string::iterator str_it = m_password.begin();
while (str_it != m_password.end()) {
buf[0] = *str_it;
++str_it;
buf[1] = *str_it;
++str_it;
m_password_hash[hash_pos++] = boost::numeric_cast<unsigned char>(strtoul(buf, 0, 16));
}
}
#endif
protected:
const std::string m_username;
std::string m_password;
#ifdef PION_HAVE_SSL
enum password_hash_type_t {EMPTY, SHA_1, SHA_256};
password_hash_type_t m_password_hash_type;
unsigned char m_password_hash[SHA256_DIGEST_LENGTH];
#endif
};
typedef boost::shared_ptr<user> user_ptr;
class user_manager :
private boost::noncopyable
{
public:
user_manager(void) {}
virtual ~user_manager() {}
inline bool empty(void) const {
boost::mutex::scoped_lock lock(m_mutex);
return m_users.empty();
}
virtual bool add_user(const std::string &username,
const std::string &password)
{
boost::mutex::scoped_lock lock(m_mutex);
user_map_t::iterator i = m_users.find(username);
if (i!=m_users.end())
return false;
user_ptr user_ptr(new user(username, password));
m_users.insert(std::make_pair(username, user_ptr));
return true;
}
virtual bool update_user(const std::string &username,
const std::string &password)
{
boost::mutex::scoped_lock lock(m_mutex);
user_map_t::iterator i = m_users.find(username);
if (i==m_users.end())
return false;
i->second->set_password(password);
return true;
}
#ifdef PION_HAVE_SSL
virtual bool add_user_hash(const std::string &username,
const std::string &password_hash)
{
boost::mutex::scoped_lock lock(m_mutex);
user_map_t::iterator i = m_users.find(username);
if (i!=m_users.end())
return false;
user_ptr user_ptr(new user(username));
user_ptr->set_password_hash(password_hash);
m_users.insert(std::make_pair(username, user_ptr));
return true;
}
virtual bool update_user_hash(const std::string &username,
const std::string &password_hash)
{
boost::mutex::scoped_lock lock(m_mutex);
user_map_t::iterator i = m_users.find(username);
if (i==m_users.end())
return false;
i->second->set_password_hash(password_hash);
return true;
}
#endif
virtual bool remove_user(const std::string &username) {
boost::mutex::scoped_lock lock(m_mutex);
user_map_t::iterator i = m_users.find(username);
if (i==m_users.end())
return false;
m_users.erase(i);
return true;
}
virtual user_ptr get_user(const std::string &username) {
boost::mutex::scoped_lock lock(m_mutex);
user_map_t::const_iterator i = m_users.find(username);
if (i==m_users.end())
return user_ptr();
else
return i->second;
}
virtual user_ptr get_user(const std::string& username, const std::string& password) {
boost::mutex::scoped_lock lock(m_mutex);
user_map_t::const_iterator i = m_users.find(username);
if (i==m_users.end() || !i->second->match_password(password))
return user_ptr();
else
return i->second;
}
protected:
typedef std::map<std::string, user_ptr> user_map_t;
mutable boost::mutex m_mutex;
user_map_t m_users;
};
typedef boost::shared_ptr<user_manager> user_manager_ptr;
} // end namespace pion
#endif
pion::user::m_password
std::string m_password
password string (actual contents depends on implementation)
Definition: user.hpp:147
pion::user_manager::update_user
virtual bool update_user(const std::string &username, const std::string &password)
Definition: user.hpp:212
pion::user_manager::remove_user
virtual bool remove_user(const std::string &username)
Definition: user.hpp:270
pion::user::get_password
std::string const & get_password() const
returns password for the user (encrypted if SSL is enabled)
Definition: user.hpp:69
pion::user::~user
virtual ~user()
virtual destructor
Definition: user.hpp:63
pion::user::get_username
std::string const & get_username() const
returns user name as a string
Definition: user.hpp:66
pion::user_manager::m_mutex
boost::mutex m_mutex
mutex used to protect access to the user list
Definition: user.hpp:311
pion::user_manager
Definition: user.hpp:167
pion::user
Definition: user.hpp:39
pion::user::match_password
virtual bool match_password(const std::string &password) const
Definition: user.hpp:76
pion::user_manager::user_manager
user_manager(void)
construct a new user_manager object
Definition: user.hpp:173
pion::user_manager::add_user
virtual bool add_user(const std::string &username, const std::string &password)
Definition: user.hpp:192
pion::user::user
user(std::string const &username, std::string const &password)
construct a new user object
Definition: user.hpp:53
pion::error::bad_password_hash
exception thrown if a bad password hash is provided
Definition: error.hpp:209
pion
Definition: admin_rights.hpp:19
pion::user_manager::empty
bool empty(void) const
returns true if no users are defined
Definition: user.hpp:179
pion::user_manager::get_user
virtual user_ptr get_user(const std::string &username, const std::string &password)
Definition: user.hpp:294
pion::user_manager::user_map_t
std::map< std::string, user_ptr > user_map_t
data type for a map of usernames to user objects
Definition: user.hpp:307
pion::user::set_password
virtual void set_password(const std::string &password)
sets password credentials for given user
Definition: user.hpp:94
pion::user::user
user(std::string const &username)
construct a new user object
Definition: user.hpp:45
pion::user::m_username
const std::string m_username
username string
Definition: user.hpp:144
pion::user_manager::get_user
virtual user_ptr get_user(const std::string &username)
Definition: user.hpp:282
pion::user_manager::~user_manager
virtual ~user_manager()
virtual destructor
Definition: user.hpp:176
pion::user_manager::m_users
user_map_t m_users
user records container
Definition: user.hpp:314