mirror of
https://github.com/RetroShare/RetroShare.git
synced 2024-10-01 02:35:48 -04:00
added user-based token management to jsonApiServer
This commit is contained in:
parent
93376d3461
commit
3b45fc5199
@ -432,31 +432,71 @@ bool JsonApiServer::requestNewTokenAutorization(const std::string& token)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool is_alphanumeric(char c) { return (c>='0' && c<'9') || (c>='a' && c<='z') || (c>='A' && c<='Z') ;}
|
||||||
|
static bool is_alphanumeric(const std::string& s)
|
||||||
|
{
|
||||||
|
for(uint32_t i=0;i<s.size();++i)
|
||||||
|
if(!is_alphanumeric(s[i]))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool parseToken(const std::string& clear_token,std::string& user,std::string& passwd)
|
||||||
|
{
|
||||||
|
uint32_t last_index=0;
|
||||||
|
uint32_t nb_colons=0;
|
||||||
|
|
||||||
|
for(uint32_t i=0;i<clear_token.length();++i)
|
||||||
|
if(clear_token[i]==':')
|
||||||
|
{
|
||||||
|
++nb_colons;
|
||||||
|
last_index = i;
|
||||||
|
}
|
||||||
|
else if(!is_alphanumeric(clear_token[i]))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(nb_colons != 1)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
user = clear_token.substr(0,last_index);
|
||||||
|
passwd = clear_token.substr(last_index+1,(int)clear_token.size()-(int)last_index-2);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool JsonApiServer::isAuthTokenValid(const std::string& token)
|
bool JsonApiServer::isAuthTokenValid(const std::string& token)
|
||||||
{
|
{
|
||||||
RS_STACK_MUTEX(configMutex);
|
RS_STACK_MUTEX(configMutex);
|
||||||
|
|
||||||
|
std::string user,passwd;
|
||||||
|
|
||||||
|
if(!parseToken(token,user,passwd))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto it = mAuthTokenStorage.mAuthorizedTokens.find(user);
|
||||||
|
|
||||||
|
if(it == mAuthTokenStorage.mAuthorizedTokens.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
||||||
int noOptimiz = 1;
|
int noOptimiz = 1;
|
||||||
|
|
||||||
/* Do not use mAuthTokenStorage.mAuthorizedTokens.count(token), because
|
/* Do not use mAuthTokenStorage.mAuthorizedTokens.count(token), because
|
||||||
* std::string comparison is usually not constant time on content to be
|
* std::string comparison is usually not constant time on content to be
|
||||||
* faster, so an attacker may use timings to guess authorized tokens */
|
* faster, so an attacker may use timings to guess authorized tokens */
|
||||||
for(const std::string& vTok : mAuthTokenStorage.mAuthorizedTokens)
|
|
||||||
{
|
if( passwd.size() == it->second.size() && ( noOptimiz = CRYPTO_memcmp( passwd.data(), it->second.data(), it->second.size() ) ) == 0 )
|
||||||
if( token.size() == vTok.size() &&
|
|
||||||
( noOptimiz = CRYPTO_memcmp( token.data(), vTok.data(),
|
|
||||||
vTok.size() ) ) == 0 )
|
|
||||||
return true;
|
return true;
|
||||||
// Make token size guessing harder
|
// Make token size guessing harder
|
||||||
else noOptimiz = CRYPTO_memcmp(token.data(), token.data(), token.size());
|
else
|
||||||
}
|
noOptimiz = CRYPTO_memcmp(passwd.data(), passwd.data(), passwd.size());
|
||||||
|
|
||||||
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
// attempt avoiding +else CRYPTO_memcmp+ being optimized away
|
||||||
return static_cast<uint32_t>(noOptimiz) + 1 == 0;
|
return static_cast<uint32_t>(noOptimiz) + 1 == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<std::string> JsonApiServer::getAuthorizedTokens()
|
std::map<std::string, std::string> JsonApiServer::getAuthorizedTokens()
|
||||||
{
|
{
|
||||||
RS_STACK_MUTEX(configMutex);
|
RS_STACK_MUTEX(configMutex);
|
||||||
return mAuthTokenStorage.mAuthorizedTokens;
|
return mAuthTokenStorage.mAuthorizedTokens;
|
||||||
@ -473,33 +513,57 @@ bool JsonApiServer::revokeAuthToken(const std::string& token)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JsonApiServer::authorizeToken(const std::string& token)
|
bool JsonApiServer::authorizeUser(const std::string& user,const std::string& passwd)
|
||||||
{
|
{
|
||||||
if(token.empty()) return false;
|
if(!is_alphanumeric(user) || !is_alphanumeric(passwd))
|
||||||
|
return false;
|
||||||
|
|
||||||
RS_STACK_MUTEX(configMutex);
|
RS_STACK_MUTEX(configMutex);
|
||||||
if(mAuthTokenStorage.mAuthorizedTokens.insert(token).second)
|
|
||||||
|
std::string& p(mAuthTokenStorage.mAuthorizedTokens[user]);
|
||||||
|
|
||||||
|
if(p != passwd)
|
||||||
{
|
{
|
||||||
|
p = passwd;
|
||||||
IndicateConfigChanged();
|
IndicateConfigChanged();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool JsonApiServer::authorizeToken(const std::string& token)
|
||||||
|
{
|
||||||
|
std::string user,password;
|
||||||
|
|
||||||
|
if(!parseToken(token,user,password))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
RS_STACK_MUTEX(configMutex);
|
||||||
|
|
||||||
|
std::string& p(mAuthTokenStorage.mAuthorizedTokens[user]);
|
||||||
|
|
||||||
|
if(p != password)
|
||||||
|
{
|
||||||
|
p = password;
|
||||||
|
IndicateConfigChanged();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ std::string JsonApiServer::decodeToken(const std::string& token)
|
/*static*/ std::string JsonApiServer::decodeToken(const std::string& radix64_token)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> decodedVect(Radix64::decode(token));
|
std::vector<uint8_t> decodedVect(Radix64::decode(radix64_token));
|
||||||
std::string decodedToken(
|
std::string decodedToken(
|
||||||
reinterpret_cast<const char*>(&decodedVect[0]),
|
reinterpret_cast<const char*>(&decodedVect[0]),
|
||||||
decodedVect.size() );
|
decodedVect.size() );
|
||||||
return decodedToken;
|
return decodedToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*static*/ std::string JsonApiServer::encondeToken(const std::string& token)
|
/*static*/ std::string JsonApiServer::encodeToken(const std::string& clear_token)
|
||||||
{
|
{
|
||||||
std::string encoded;
|
std::string encoded;
|
||||||
Radix64::encode( reinterpret_cast<const uint8_t*>(token.c_str()),
|
Radix64::encode( reinterpret_cast<const uint8_t*>(clear_token.c_str()),
|
||||||
token.length(), encoded );
|
clear_token.length(), encoded );
|
||||||
return encoded;
|
return encoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,40 +120,48 @@ struct JsonApiServer : RsSingleJobThread, p3Config
|
|||||||
* @jsonapi{development}
|
* @jsonapi{development}
|
||||||
* @return the set of authorized encoded tokens
|
* @return the set of authorized encoded tokens
|
||||||
*/
|
*/
|
||||||
std::set<std::string> getAuthorizedTokens();
|
std::map<std::string,std::string> getAuthorizedTokens();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Revoke given auth token
|
* @brief Revoke given auth token
|
||||||
* @jsonapi{development}
|
* @jsonapi{development}
|
||||||
* @param[in] token decoded
|
* @param[in] user par of the decoded token
|
||||||
* @return true if the token has been revoked, false otherwise
|
* @return true if the token has been revoked, false otherwise
|
||||||
*/
|
*/
|
||||||
bool revokeAuthToken(const std::string& token);
|
bool revokeAuthToken(const std::string& user);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add new auth token to the authorized set
|
* @brief Add new auth token to the authorized set
|
||||||
* @jsonapi{development}
|
* @jsonapi{development}
|
||||||
* @param[in] token toke to autorize decoded
|
* @param[in] token token to autorize decoded, in format user:passwd where user and passwd are alphanumeric strings
|
||||||
* @return true if the token has been added to authorized, false if error
|
* @return true if the token has been added to authorized, false if error occurred (e.g. token format is invalid)
|
||||||
* occurred or if the token was already authorized
|
|
||||||
*/
|
*/
|
||||||
bool authorizeToken(const std::string& token);
|
bool authorizeToken(const std::string& token);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add new auth (user,passwd) token to the authorized set, creating the token user:passwd internally.
|
||||||
|
* @jsonapi{development}
|
||||||
|
* @param[in] alphanumeric_user username to autorize decoded
|
||||||
|
* @param[in] alphanumeric_passwd passwd to autorize decoded
|
||||||
|
* @return true if the token has been added to authorized, false if error occurred
|
||||||
|
*/
|
||||||
|
bool authorizeUser(const std::string& alphanumeric_user,const std::string& alphanumeric_passwd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get decoded version of the given encoded token
|
* @brief Get decoded version of the given encoded token
|
||||||
* @jsonapi{development,unauthenticated}
|
* @jsonapi{development,unauthenticated}
|
||||||
* @param[in] token encoded
|
* @param[in] radix64_token encoded
|
||||||
* @return token decoded
|
* @return token decoded
|
||||||
*/
|
*/
|
||||||
static std::string decodeToken(const std::string& token);
|
static std::string decodeToken(const std::string& radix64_token);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get encoded version of the given decoded token
|
* @brief Get encoded version of the given decoded token
|
||||||
* @jsonapi{development,unauthenticated}
|
* @jsonapi{development,unauthenticated}
|
||||||
* @param[in] token decoded
|
* @param[in] clear_token decoded
|
||||||
* @return token encoded
|
* @return token encoded
|
||||||
*/
|
*/
|
||||||
static std::string encondeToken(const std::string& token);
|
static std::string encodeToken(const std::string& clear_token);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Write version information to given paramethers
|
* @brief Write version information to given paramethers
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include "serialiser/rsserializer.h"
|
#include "serialiser/rsserializer.h"
|
||||||
#include "serialiser/rsserializable.h"
|
#include "serialiser/rsserializable.h"
|
||||||
|
|
||||||
enum class JsonApiItemsType : uint8_t { AuthTokenItem = 0 };
|
enum class JsonApiItemsType : uint8_t { AuthTokenItem_deprecated = 0, AuthTokenItem = 1 };
|
||||||
|
|
||||||
struct JsonApiServerAuthTokenStorage : RsItem
|
struct JsonApiServerAuthTokenStorage : RsItem
|
||||||
{
|
{
|
||||||
@ -47,7 +47,7 @@ struct JsonApiServerAuthTokenStorage : RsItem
|
|||||||
/// @see RsItem
|
/// @see RsItem
|
||||||
virtual void clear() { mAuthorizedTokens.clear(); }
|
virtual void clear() { mAuthorizedTokens.clear(); }
|
||||||
|
|
||||||
std::set<std::string> mAuthorizedTokens;
|
std::map<std::string,std::string> mAuthorizedTokens;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user