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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
int noOptimiz = 1;
|
||||
|
||||
/* Do not use mAuthTokenStorage.mAuthorizedTokens.count(token), because
|
||||
* std::string comparison is usually not constant time on content to be
|
||||
* faster, so an attacker may use timings to guess authorized tokens */
|
||||
for(const std::string& vTok : mAuthTokenStorage.mAuthorizedTokens)
|
||||
{
|
||||
if( token.size() == vTok.size() &&
|
||||
( noOptimiz = CRYPTO_memcmp( token.data(), vTok.data(),
|
||||
vTok.size() ) ) == 0 )
|
||||
|
||||
if( passwd.size() == it->second.size() && ( noOptimiz = CRYPTO_memcmp( passwd.data(), it->second.data(), it->second.size() ) ) == 0 )
|
||||
return true;
|
||||
// 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
|
||||
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);
|
||||
return mAuthTokenStorage.mAuthorizedTokens;
|
||||
@ -473,33 +513,57 @@ bool JsonApiServer::revokeAuthToken(const std::string& token)
|
||||
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);
|
||||
if(mAuthTokenStorage.mAuthorizedTokens.insert(token).second)
|
||||
|
||||
std::string& p(mAuthTokenStorage.mAuthorizedTokens[user]);
|
||||
|
||||
if(p != passwd)
|
||||
{
|
||||
p = passwd;
|
||||
IndicateConfigChanged();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*static*/ std::string JsonApiServer::decodeToken(const std::string& token)
|
||||
|
||||
bool JsonApiServer::authorizeToken(const std::string& token)
|
||||
{
|
||||
std::vector<uint8_t> decodedVect(Radix64::decode(token));
|
||||
std::string user,password;
|
||||
|
||||
if(!parseToken(token,user,password))
|
||||
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& radix64_token)
|
||||
{
|
||||
std::vector<uint8_t> decodedVect(Radix64::decode(radix64_token));
|
||||
std::string decodedToken(
|
||||
reinterpret_cast<const char*>(&decodedVect[0]),
|
||||
decodedVect.size() );
|
||||
return decodedToken;
|
||||
}
|
||||
|
||||
/*static*/ std::string JsonApiServer::encondeToken(const std::string& token)
|
||||
/*static*/ std::string JsonApiServer::encodeToken(const std::string& clear_token)
|
||||
{
|
||||
std::string encoded;
|
||||
Radix64::encode( reinterpret_cast<const uint8_t*>(token.c_str()),
|
||||
token.length(), encoded );
|
||||
Radix64::encode( reinterpret_cast<const uint8_t*>(clear_token.c_str()),
|
||||
clear_token.length(), encoded );
|
||||
return encoded;
|
||||
}
|
||||
|
||||
|
@ -120,40 +120,48 @@ struct JsonApiServer : RsSingleJobThread, p3Config
|
||||
* @jsonapi{development}
|
||||
* @return the set of authorized encoded tokens
|
||||
*/
|
||||
std::set<std::string> getAuthorizedTokens();
|
||||
std::map<std::string,std::string> getAuthorizedTokens();
|
||||
|
||||
/**
|
||||
* @brief Revoke given auth token
|
||||
* @jsonapi{development}
|
||||
* @param[in] token decoded
|
||||
* @param[in] user par of the decoded token
|
||||
* @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
|
||||
* @jsonapi{development}
|
||||
* @param[in] token toke to autorize decoded
|
||||
* @return true if the token has been added to authorized, false if error
|
||||
* occurred or if the token was already authorized
|
||||
* @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 occurred (e.g. token format is invalid)
|
||||
*/
|
||||
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
|
||||
* @jsonapi{development,unauthenticated}
|
||||
* @param[in] token encoded
|
||||
* @param[in] radix64_token encoded
|
||||
* @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
|
||||
* @jsonapi{development,unauthenticated}
|
||||
* @param[in] token decoded
|
||||
* @param[in] clear_token decoded
|
||||
* @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
|
||||
|
@ -29,7 +29,7 @@
|
||||
#include "serialiser/rsserializer.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
|
||||
{
|
||||
@ -47,7 +47,7 @@ struct JsonApiServerAuthTokenStorage : RsItem
|
||||
/// @see RsItem
|
||||
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