added user-based token management to jsonApiServer

This commit is contained in:
csoler 2019-11-11 22:48:35 +01:00
parent 93376d3461
commit 3b45fc5199
No known key found for this signature in database
GPG Key ID: 7BCA522266C0804C
3 changed files with 102 additions and 30 deletions

View File

@ -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;
} }

View File

@ -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

View File

@ -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;
}; };