pion
5.0.6
|
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