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

Generated on Fri Apr 30 14:48:53 2010 for pion-net by  doxygen 1.4.7