00001
00002
00003
00004
00005
00006
00007
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 {
00028 namespace net {
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
00088 SHA1((const unsigned char *)password.data(), password.size(), m_password_hash);
00089
00090
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
00106 if (password_hash.size() != SHA_DIGEST_LENGTH*2)
00107 throw BadPasswordHash();
00108 m_password = password_hash;
00109
00110
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 }
00302 }
00303
00304 #endif