00001 
00002 
00003 
00004 
00005 
00006 
00007 
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         
00027         #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00028     #endif
00029     #include <openssl/sha.h>
00030 #endif
00031 
00032 
00033 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     {}
00048 
00050     user(std::string const &username, std::string const &password) :
00051         m_username(username)
00052     {
00053         set_password(password);
00054     }
00055 
00057     virtual ~user() {}
00058 
00060     std::string const & get_username() const { return m_username; }
00061 
00063     std::string const & get_password() const { return m_password; }
00064 
00070     virtual bool match_password(const std::string& password) const {
00071 #ifdef PION_HAVE_SSL
00072         unsigned char sha1_hash[SHA_DIGEST_LENGTH];
00073         SHA1(reinterpret_cast<const unsigned char *>(password.data()), password.size(), sha1_hash);
00074         return (memcmp(sha1_hash, m_password_hash, SHA_DIGEST_LENGTH) == 0);
00075 #else
00076         return m_password == password;
00077 #endif
00078     }
00079 
00081     virtual void set_password(const std::string& password) { 
00082 #ifdef PION_HAVE_SSL
00083         
00084         SHA1((const unsigned char *)password.data(), password.size(), m_password_hash);
00085 
00086         
00087         m_password.clear();
00088         char buf[3];
00089         for (unsigned int n = 0; n < SHA_DIGEST_LENGTH; ++n) {
00090             sprintf(buf, "%.2x", static_cast<unsigned int>(m_password_hash[n]));
00091             m_password += buf;
00092         }
00093 #else
00094         m_password = password; 
00095 #endif
00096     }
00097 
00098 #ifdef PION_HAVE_SSL
00100     virtual void set_password_hash(const std::string& password_hash) {
00101         
00102         if (password_hash.size() != SHA_DIGEST_LENGTH*2)
00103             BOOST_THROW_EXCEPTION( error::bad_password_hash() );
00104         m_password = password_hash;
00105 
00106         
00107         char buf[3];
00108         buf[2] = '\0';
00109         unsigned int hash_pos = 0;
00110         std::string::iterator str_it = m_password.begin();
00111         while (str_it != m_password.end()) {
00112             buf[0] = *str_it;
00113             ++str_it;
00114             buf[1] = *str_it;
00115             ++str_it;
00116             m_password_hash[hash_pos++] = boost::numeric_cast<unsigned char>(strtoul(buf, 0, 16));
00117         }
00118     }
00119 #endif
00120 
00121 
00122 protected:
00123 
00125     const std::string   m_username;
00126 
00128     std::string         m_password;
00129 
00130 #ifdef PION_HAVE_SSL
00132     unsigned char       m_password_hash[SHA_DIGEST_LENGTH];
00133 #endif
00134 };
00135 
00137 typedef boost::shared_ptr<user> user_ptr;
00138 
00139 
00143 class user_manager :
00144     private boost::noncopyable
00145 {
00146 public:
00147 
00149     user_manager(void) {}
00150 
00152     virtual ~user_manager() {}
00153 
00155     inline bool empty(void) const {
00156         boost::mutex::scoped_lock lock(m_mutex);
00157         return m_users.empty();
00158     }
00159 
00168     virtual bool add_user(const std::string &username,
00169         const std::string &password)
00170     {
00171         boost::mutex::scoped_lock lock(m_mutex);
00172         user_map_t::iterator i = m_users.find(username);
00173         if (i!=m_users.end())
00174             return false;
00175         user_ptr user_ptr(new user(username, password));
00176         m_users.insert(std::make_pair(username, user_ptr));
00177         return true;
00178     }
00179 
00188     virtual bool update_user(const std::string &username,
00189         const std::string &password)
00190     {
00191         boost::mutex::scoped_lock lock(m_mutex);
00192         user_map_t::iterator i = m_users.find(username);
00193         if (i==m_users.end())
00194             return false;
00195         i->second->set_password(password);
00196         return true;
00197     }
00198 
00199 #ifdef PION_HAVE_SSL
00200 
00208     virtual bool add_user_hash(const std::string &username,
00209         const std::string &password_hash)
00210     {
00211         boost::mutex::scoped_lock lock(m_mutex);
00212         user_map_t::iterator i = m_users.find(username);
00213         if (i!=m_users.end())
00214             return false;
00215         user_ptr user_ptr(new user(username));
00216         user_ptr->set_password_hash(password_hash);
00217         m_users.insert(std::make_pair(username, user_ptr));
00218         return true;
00219     }
00220 
00229     virtual bool update_user_hash(const std::string &username,
00230         const std::string &password_hash)
00231     {
00232         boost::mutex::scoped_lock lock(m_mutex);
00233         user_map_t::iterator i = m_users.find(username);
00234         if (i==m_users.end())
00235             return false;
00236         i->second->set_password_hash(password_hash);
00237         return true;
00238     }
00239 #endif
00240 
00246     virtual bool remove_user(const std::string &username) {
00247         boost::mutex::scoped_lock lock(m_mutex);
00248         user_map_t::iterator i = m_users.find(username);
00249         if (i==m_users.end())
00250             return false;
00251         m_users.erase(i);
00252         return true;
00253     }
00254 
00258     virtual user_ptr get_user(const std::string &username) {
00259         boost::mutex::scoped_lock lock(m_mutex);
00260         user_map_t::const_iterator i = m_users.find(username);
00261         if (i==m_users.end())
00262             return user_ptr();
00263         else
00264             return i->second;
00265     }
00266 
00270     virtual user_ptr get_user(const std::string& username, const std::string& password) {
00271         boost::mutex::scoped_lock lock(m_mutex);
00272         user_map_t::const_iterator i = m_users.find(username);
00273         if (i==m_users.end() || !i->second->match_password(password))
00274             return user_ptr();
00275         else
00276             return i->second;
00277     }
00278 
00279 
00280 protected:
00281 
00283     typedef std::map<std::string, user_ptr>  user_map_t;
00284 
00285 
00287     mutable boost::mutex    m_mutex;
00288 
00290     user_map_t              m_users;
00291 };
00292 
00294 typedef boost::shared_ptr<user_manager>  user_manager_ptr;
00295 
00296 
00297 }   
00298 
00299 #endif