pion  5.0.6
include/pion/user.hpp
00001 // ---------------------------------------------------------------------
00002 // pion:  a Boost C++ framework for building lightweight HTTP interfaces
00003 // ---------------------------------------------------------------------
00004 // Copyright (C) 2007-2014 Splunk Inc.  (https://github.com/splunk/pion)
00005 //
00006 // Distributed under the Boost Software License, Version 1.0.
00007 // See http://www.boost.org/LICENSE_1_0.txt
00008 //
00009 
00010 #ifndef __PION_USER_HEADER__
00011 #define __PION_USER_HEADER__
00012 
00013 #include <map>
00014 #include <string>
00015 #include <cstdio>
00016 #include <cstring>
00017 #include <boost/shared_ptr.hpp>
00018 #include <boost/noncopyable.hpp>
00019 #include <boost/thread/mutex.hpp>
00020 #include <boost/numeric/conversion/cast.hpp>
00021 #include <pion/config.hpp>
00022 #include <pion/error.hpp>
00023 
00024 #ifdef PION_HAVE_SSL
00025     #if defined(__APPLE__)
00026         // suppress warnings about OpenSSL being deprecated in OSX
00027         #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00028     #endif
00029     #include <openssl/sha.h>
00030 #endif
00031 
00032 
00033 namespace pion {    // begin namespace pion
00034 
00035 
00039 class user :
00040     private boost::noncopyable
00041 {
00042 public:
00043 
00045     user(std::string const &username) :
00046         m_username(username)
00047 #ifdef PION_HAVE_SSL
00048         , m_password_hash_type(EMPTY)
00049 #endif
00050     {}
00051 
00053     user(std::string const &username, std::string const &password) :
00054         m_username(username)
00055 #ifdef PION_HAVE_SSL
00056         , m_password_hash_type(EMPTY)
00057 #endif
00058     {
00059         set_password(password);
00060     }
00061 
00063     virtual ~user() {}
00064 
00066     std::string const & get_username() const { return m_username; }
00067 
00069     std::string const & get_password() const { return m_password; }
00070 
00076     virtual bool match_password(const std::string& password) const {
00077 #ifdef PION_HAVE_SSL
00078         if (m_password_hash_type == SHA_256) {
00079             unsigned char sha256_hash[SHA256_DIGEST_LENGTH];
00080             SHA256(reinterpret_cast<const unsigned char *>(password.data()), password.size(), sha256_hash);
00081             return (memcmp(sha256_hash, m_password_hash, SHA256_DIGEST_LENGTH) == 0);
00082         } else if (m_password_hash_type == SHA_1) {
00083             unsigned char sha1_hash[SHA_DIGEST_LENGTH];
00084             SHA1(reinterpret_cast<const unsigned char *>(password.data()), password.size(), sha1_hash);
00085             return (memcmp(sha1_hash, m_password_hash, SHA_DIGEST_LENGTH) == 0);
00086         } else
00087             return false;
00088 #else
00089         return m_password == password;
00090 #endif
00091     }
00092 
00094     virtual void set_password(const std::string& password) { 
00095 #ifdef PION_HAVE_SSL
00096         // store encrypted hash value
00097         SHA256((const unsigned char *)password.data(), password.size(), m_password_hash);
00098         m_password_hash_type = SHA_256;
00099 
00100         // update password string (convert binary to hex)
00101         m_password.clear();
00102         char buf[3];
00103         for (unsigned int n = 0; n < SHA256_DIGEST_LENGTH; ++n) {
00104             sprintf(buf, "%.2x", static_cast<unsigned int>(m_password_hash[n]));
00105             m_password += buf;
00106         }
00107 #else
00108         m_password = password; 
00109 #endif
00110     }
00111 
00112 #ifdef PION_HAVE_SSL
00113 
00114     virtual void set_password_hash(const std::string& password_hash) {
00115         // update password string representation
00116         if (password_hash.size() == SHA256_DIGEST_LENGTH * 2) {
00117             m_password_hash_type = SHA_256;
00118         } else if (password_hash.size() == SHA_DIGEST_LENGTH * 2) {
00119             m_password_hash_type = SHA_1;
00120         } else {
00121             BOOST_THROW_EXCEPTION( error::bad_password_hash() );
00122         }
00123         m_password = password_hash;
00124 
00125         // convert string from hex to binary value
00126         char buf[3];
00127         buf[2] = '\0';
00128         unsigned int hash_pos = 0;
00129         std::string::iterator str_it = m_password.begin();
00130         while (str_it != m_password.end()) {
00131             buf[0] = *str_it;
00132             ++str_it;
00133             buf[1] = *str_it;
00134             ++str_it;
00135             m_password_hash[hash_pos++] = boost::numeric_cast<unsigned char>(strtoul(buf, 0, 16));
00136         }
00137     }
00138 #endif
00139 
00140 
00141 protected:
00142 
00144     const std::string   m_username;
00145 
00147     std::string         m_password;
00148 
00149 #ifdef PION_HAVE_SSL
00150     enum password_hash_type_t {EMPTY, SHA_1, SHA_256};
00151 
00153     password_hash_type_t   m_password_hash_type;
00154 
00156     unsigned char          m_password_hash[SHA256_DIGEST_LENGTH];
00157 #endif
00158 };
00159 
00161 typedef boost::shared_ptr<user> user_ptr;
00162 
00163 
00167 class user_manager :
00168     private boost::noncopyable
00169 {
00170 public:
00171 
00173     user_manager(void) {}
00174 
00176     virtual ~user_manager() {}
00177 
00179     inline bool empty(void) const {
00180         boost::mutex::scoped_lock lock(m_mutex);
00181         return m_users.empty();
00182     }
00183 
00192     virtual bool add_user(const std::string &username,
00193         const std::string &password)
00194     {
00195         boost::mutex::scoped_lock lock(m_mutex);
00196         user_map_t::iterator i = m_users.find(username);
00197         if (i!=m_users.end())
00198             return false;
00199         user_ptr user_ptr(new user(username, password));
00200         m_users.insert(std::make_pair(username, user_ptr));
00201         return true;
00202     }
00203 
00212     virtual bool update_user(const std::string &username,
00213         const std::string &password)
00214     {
00215         boost::mutex::scoped_lock lock(m_mutex);
00216         user_map_t::iterator i = m_users.find(username);
00217         if (i==m_users.end())
00218             return false;
00219         i->second->set_password(password);
00220         return true;
00221     }
00222 
00223 #ifdef PION_HAVE_SSL
00224 
00232     virtual bool add_user_hash(const std::string &username,
00233         const std::string &password_hash)
00234     {
00235         boost::mutex::scoped_lock lock(m_mutex);
00236         user_map_t::iterator i = m_users.find(username);
00237         if (i!=m_users.end())
00238             return false;
00239         user_ptr user_ptr(new user(username));
00240         user_ptr->set_password_hash(password_hash);
00241         m_users.insert(std::make_pair(username, user_ptr));
00242         return true;
00243     }
00244 
00253     virtual bool update_user_hash(const std::string &username,
00254         const std::string &password_hash)
00255     {
00256         boost::mutex::scoped_lock lock(m_mutex);
00257         user_map_t::iterator i = m_users.find(username);
00258         if (i==m_users.end())
00259             return false;
00260         i->second->set_password_hash(password_hash);
00261         return true;
00262     }
00263 #endif
00264 
00270     virtual bool remove_user(const std::string &username) {
00271         boost::mutex::scoped_lock lock(m_mutex);
00272         user_map_t::iterator i = m_users.find(username);
00273         if (i==m_users.end())
00274             return false;
00275         m_users.erase(i);
00276         return true;
00277     }
00278 
00282     virtual user_ptr get_user(const std::string &username) {
00283         boost::mutex::scoped_lock lock(m_mutex);
00284         user_map_t::const_iterator i = m_users.find(username);
00285         if (i==m_users.end())
00286             return user_ptr();
00287         else
00288             return i->second;
00289     }
00290 
00294     virtual user_ptr get_user(const std::string& username, const std::string& password) {
00295         boost::mutex::scoped_lock lock(m_mutex);
00296         user_map_t::const_iterator i = m_users.find(username);
00297         if (i==m_users.end() || !i->second->match_password(password))
00298             return user_ptr();
00299         else
00300             return i->second;
00301     }
00302 
00303 
00304 protected:
00305 
00307     typedef std::map<std::string, user_ptr>  user_map_t;
00308 
00309 
00311     mutable boost::mutex    m_mutex;
00312 
00314     user_map_t              m_users;
00315 };
00316 
00318 typedef boost::shared_ptr<user_manager>  user_manager_ptr;
00319 
00320 
00321 }   // end namespace pion
00322 
00323 #endif