# net/include/pion/net/PionUser.hpp

    00001 // ------------------------------------------------------------------
    00002 // pion-net: a C++ framework for building lightweight HTTP interfaces
    00003 // ------------------------------------------------------------------
    00004 // Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
    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_PIONUSER_HEADER__
    00011 #define __PION_PIONUSER_HEADER__
    00012
    00013 #include <map>
    00014 #include <string>
    00015 #include <cstring>
    00016 #include <boost/shared_ptr.hpp>
    00017 #include <boost/noncopyable.hpp>
    00018 #include <boost/thread/mutex.hpp>
    00019 #include <boost/numeric/conversion/cast.hpp>
    00020 #include <pion/PionConfig.hpp>
    00021 #include <pion/PionException.hpp>
    00022
    00023 #ifdef PION_HAVE_SSL
    00024     #include <openssl/sha.h>
    00025 #endif
    00026
    00027 namespace pion {    // begin namespace pion
    00028 namespace net {     // begin namespace net (Pion Network Library)
    00029
    00030
    00034 class PionUser :
    00035     private boost::noncopyable
    00036 {
    00037 public:
    00038
    00040     class BadPasswordHash : public std::exception {
    00041     public:
    00042         virtual const char* what() const throw() {
    00043             return "Invalid password hash provided";
    00044         }
    00045     };
    00046
    00047
    00049     PionUser(std::string const &username) :
    00050         m_username(username)
    00051     {}
    00052
    00054     PionUser(std::string const &username, std::string const &password) :
    00055         m_username(username)
    00056     {
    00057         setPassword(password);
    00058     }
    00059
    00061     virtual ~PionUser() {}
    00062
    00064     std::string const & getUsername() const { return m_username; }
    00065
    00067     std::string const & getPassword() const { return m_password; }
    00068
    00074     virtual bool matchPassword(const std::string& password) const {
    00075 #ifdef PION_HAVE_SSL
    00076         unsigned char sha1_hash[SHA_DIGEST_LENGTH];
    00077         SHA1(reinterpret_cast<const unsigned char *>(password.data()), password.size(), sha1_hash);
    00078         return (memcmp(sha1_hash, m_password_hash, SHA_DIGEST_LENGTH) == 0);
    00079 #else
    00080         return m_password == password;
    00081 #endif
    00082     }
    00083
    00085     virtual void setPassword(const std::string& password) {
    00086 #ifdef PION_HAVE_SSL
    00087         // store encrypted hash value
    00088         SHA1((const unsigned char *)password.data(), password.size(), m_password_hash);
    00089
    00090         // update password string (convert binary to hex)
    00091         m_password.clear();
    00092         char buf[3];
    00093         for (unsigned int n = 0; n < SHA_DIGEST_LENGTH; ++n) {
    00094             sprintf(buf, "%.2x", static_cast<unsigned int>(m_password_hash[n]));
    00095             m_password += buf;
    00096         }
    00097 #else
    00098         m_password = password;
    00099 #endif
    00100     }
    00101
    00102 #ifdef PION_HAVE_SSL
    00104     virtual void setPasswordHash(const std::string& password_hash) {
    00105         // update password string representation
    00106         if (password_hash.size() != SHA_DIGEST_LENGTH*2)
    00107             throw BadPasswordHash();
    00108         m_password = password_hash;
    00109
    00110         // convert string from hex to binary value
    00111         char buf[3];
    00112         buf[2] = '\0';
    00113         unsigned int hash_pos = 0;
    00114         std::string::iterator str_it = m_password.begin();
    00115         while (str_it != m_password.end()) {
    00116             buf[0] = *str_it;
    00117             ++str_it;
    00118             buf[1] = *str_it;
    00119             ++str_it;
    00120             m_password_hash[hash_pos++] = boost::numeric_cast<unsigned char>(strtoul(buf, 0, 16));
    00121         }
    00122     }
    00123 #endif
    00124
    00125
    00126 protected:
    00127
    00129     const std::string   m_username;
    00130
    00132     std::string         m_password;
    00133
    00134 #ifdef PION_HAVE_SSL
    00136     unsigned char       m_password_hash[SHA_DIGEST_LENGTH];
    00137 #endif
    00138 };
    00139
    00141 typedef boost::shared_ptr<PionUser> PionUserPtr;
    00142
    00143
    00147 class PionUserManager :
    00148     private boost::noncopyable
    00149 {
    00150 public:
    00151
    00153     PionUserManager(void) {}
    00154
    00156     virtual ~PionUserManager() {}
    00157
    00159     inline bool empty(void) const {
    00160         boost::mutex::scoped_lock lock(m_mutex);
    00161         return m_users.empty();
    00162     }
    00163
    00172     virtual bool addUser(const std::string &username,
    00173         const std::string &password)
    00174     {
    00175         boost::mutex::scoped_lock lock(m_mutex);
    00176         UserMap::iterator i = m_users.find(username);
    00177         if (i!=m_users.end())
    00178             return false;
    00179         PionUserPtr user(new PionUser(username, password));
    00180         m_users.insert(std::make_pair(username, user));
    00181         return true;
    00182     }
    00183
    00192     virtual bool updateUser(const std::string &username,
    00193         const std::string &password)
    00194     {
    00195         boost::mutex::scoped_lock lock(m_mutex);
    00196         UserMap::iterator i = m_users.find(username);
    00197         if (i==m_users.end())
    00198             return false;
    00199         i->second->setPassword(password);
    00200         return true;
    00201     }
    00202
    00203 #ifdef PION_HAVE_SSL
    00204
    00212     virtual bool addUserHash(const std::string &username,
    00213         const std::string &password_hash)
    00214     {
    00215         boost::mutex::scoped_lock lock(m_mutex);
    00216         UserMap::iterator i = m_users.find(username);
    00217         if (i!=m_users.end())
    00218             return false;
    00219         PionUserPtr user(new PionUser(username));
    00220         user->setPasswordHash(password_hash);
    00221         m_users.insert(std::make_pair(username, user));
    00222         return true;
    00223     }
    00224
    00233     virtual bool updateUserHash(const std::string &username,
    00234         const std::string &password_hash)
    00235     {
    00236         boost::mutex::scoped_lock lock(m_mutex);
    00237         UserMap::iterator i = m_users.find(username);
    00238         if (i==m_users.end())
    00239             return false;
    00240         i->second->setPasswordHash(password_hash);
    00241         return true;
    00242     }
    00243 #endif
    00244
    00250     virtual bool removeUser(const std::string &username) {
    00251         boost::mutex::scoped_lock lock(m_mutex);
    00252         UserMap::iterator i = m_users.find(username);
    00253         if (i==m_users.end())
    00254             return false;
    00255         m_users.erase(i);
    00256         return true;
    00257     }
    00258
    00262     virtual PionUserPtr getUser(const std::string &username) {
    00263         boost::mutex::scoped_lock lock(m_mutex);
    00264         UserMap::const_iterator i = m_users.find(username);
    00265         if (i==m_users.end())
    00266             return PionUserPtr();
    00267         else
    00268             return i->second;
    00269     }
    00270
    00274     virtual PionUserPtr getUser(const std::string& username, const std::string& password) {
    00275         boost::mutex::scoped_lock lock(m_mutex);
    00276         UserMap::const_iterator i = m_users.find(username);
    00277         if (i==m_users.end() || !i->second->matchPassword(password))
    00278             return PionUserPtr();
    00279         else
    00280             return i->second;
    00281     }
    00282
    00283
    00284 protected:
    00285
    00287     typedef std::map<std::string, PionUserPtr>  UserMap;
    00288
    00289
    00291     mutable boost::mutex        m_mutex;
    00292
    00294     UserMap                     m_users;
    00295 };
    00296
    00298 typedef boost::shared_ptr<PionUserManager>  PionUserManagerPtr;
    00299
    00300
    00301 }   // end namespace net
    00302 }   // end namespace pion
    00303
    00304 #endif