mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
synced 2026-01-27 02:23:03 +00:00
Adding refresh token processing.
This commit is contained in:
@@ -66,6 +66,7 @@ components:
|
||||
- 11 # BAD_MFA_TRANSACTION
|
||||
- 12 # MFA_FAILURE
|
||||
- 13 # SECURITY_SERVICE_UNREACHABLE
|
||||
- 14 # CANNOT REFRESH TOKEN
|
||||
ErrorDetails:
|
||||
type: string
|
||||
ErrorDescription:
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace OpenWifi {
|
||||
int AuthService::Start() {
|
||||
Logger().notice("Starting...");
|
||||
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
|
||||
RefreshTokenLifeSpan_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.refresh_token.lifespan", 90 * 24 * 60 * 600);
|
||||
HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
|
||||
|
||||
AccessPolicy_ = MicroService::instance().ConfigPath("openwifi.document.policy.access", "/wwwassets/access_policy.html");
|
||||
@@ -62,7 +63,83 @@ namespace OpenWifi {
|
||||
Logger().notice("Stopping...");
|
||||
}
|
||||
|
||||
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
|
||||
bool AuthService::RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) {
|
||||
try {
|
||||
std::string CallToken;
|
||||
Poco::Net::OAuth20Credentials Auth(Request);
|
||||
if (Auth.getScheme() == "Bearer") {
|
||||
CallToken = Auth.getBearerToken();
|
||||
}
|
||||
|
||||
if (CallToken.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t RevocationDate=0;
|
||||
std::string UserId;
|
||||
if(StorageService()->UserTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) {
|
||||
auto now = OpenWifi::Now();
|
||||
|
||||
// Create a new token
|
||||
auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM);
|
||||
auto NewRefreshToken = RefreshToken;
|
||||
if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) {
|
||||
NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM);
|
||||
UI.webtoken.lastRefresh_ = now;
|
||||
}
|
||||
|
||||
StorageService()->UserTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ );
|
||||
UI.webtoken.access_token_ = NewToken;
|
||||
UI.webtoken.refresh_token_ = NewRefreshToken;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI) {
|
||||
try {
|
||||
std::string CallToken;
|
||||
Poco::Net::OAuth20Credentials Auth(Request);
|
||||
if (Auth.getScheme() == "Bearer") {
|
||||
CallToken = Auth.getBearerToken();
|
||||
}
|
||||
|
||||
if (CallToken.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t RevocationDate=0;
|
||||
std::string UserId;
|
||||
if(StorageService()->SubTokenDB().GetToken(CallToken, UI.webtoken, UserId, RevocationDate) && UI.webtoken.refresh_token_==RefreshToken) {
|
||||
auto now = OpenWifi::Now();
|
||||
|
||||
// Create a new token
|
||||
auto NewToken = GenerateTokenHMAC( UI.webtoken.access_token_, CUSTOM);
|
||||
auto NewRefreshToken = RefreshToken;
|
||||
if(now - UI.webtoken.lastRefresh_ < RefreshTokenLifeSpan_) {
|
||||
NewRefreshToken = GenerateTokenHMAC( UI.webtoken.refresh_token_, CUSTOM);
|
||||
UI.webtoken.lastRefresh_ = now;
|
||||
}
|
||||
|
||||
StorageService()->SubTokenDB().RefreshToken(CallToken, NewToken, NewRefreshToken, UI.webtoken.lastRefresh_ );
|
||||
UI.webtoken.access_token_ = NewToken;
|
||||
UI.webtoken.refresh_token_ = NewRefreshToken;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
} catch (...) {
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::IsAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Expired = false;
|
||||
|
||||
@@ -113,6 +113,9 @@ namespace OpenWifi{
|
||||
inline const std::string & GetSubPasswordPolicy() const { return SubPasswordPolicy_; }
|
||||
inline const std::string & GetSubAccessPolicy() const { return SubAccessPolicy_; }
|
||||
|
||||
bool RefreshUserToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
|
||||
bool RefreshSubToken(Poco::Net::HTTPServerRequest & Request, const std::string & RefreshToken, SecurityObjects::UserInfoAndPolicy & UI);
|
||||
|
||||
private:
|
||||
Poco::SHA2Engine SHA2_;
|
||||
|
||||
@@ -125,8 +128,9 @@ namespace OpenWifi{
|
||||
std::regex PasswordValidation_;
|
||||
std::regex SubPasswordValidation_;
|
||||
|
||||
uint64_t TokenAging_ = 30 * 24 * 60 * 60;
|
||||
uint64_t TokenAging_ = 15 * 24 * 60 * 60;
|
||||
uint64_t HowManyOldPassword_=5;
|
||||
uint64_t RefreshTokenLifeSpan_ = 90 * 24 * 60 * 60 ;
|
||||
|
||||
class SHA256Engine : public Poco::Crypto::DigestEngine
|
||||
{
|
||||
|
||||
@@ -60,9 +60,22 @@ namespace OpenWifi {
|
||||
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
|
||||
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
|
||||
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
|
||||
auto refreshToken = GetS("refresh_token", Obj);
|
||||
auto grant_type = GetParameter("grant_type");
|
||||
|
||||
Poco::toLowerInPlace(userId);
|
||||
|
||||
if(!refreshToken.empty() && grant_type == "refresh_token") {
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
if(AuthService()->RefreshUserToken(*Request, refreshToken, UInfo)) {
|
||||
Poco::JSON::Object Answer;
|
||||
UInfo.webtoken.to_json(Answer);
|
||||
return ReturnObject(Answer);
|
||||
} else {
|
||||
return UnAuthorized(RESTAPI::Errors::InvalidCredentials, CANNOT_REFRESH_TOKEN);
|
||||
}
|
||||
}
|
||||
|
||||
if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) {
|
||||
Logger_.information(fmt::format("POLICY-REQUEST({}): Request.", Request->clientAddress().toString()));
|
||||
Poco::JSON::Object Answer;
|
||||
|
||||
@@ -113,6 +113,8 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"userMustChangePassword",userMustChangePassword);
|
||||
field_to_json(Obj,"errorCode", errorCode);
|
||||
Obj.set("aclTemplate",AclTemplateObj);
|
||||
field_to_json(Obj,"errorCode", errorCode);
|
||||
field_to_json(Obj,"lastRefresh", lastRefresh_);
|
||||
}
|
||||
|
||||
bool WebToken::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -129,6 +131,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_from_json(Obj, "created", created_);
|
||||
field_from_json(Obj, "username", username_);
|
||||
field_from_json(Obj, "userMustChangePassword",userMustChangePassword);
|
||||
field_from_json(Obj,"lastRefresh", lastRefresh_);
|
||||
return true;
|
||||
} catch (...) {
|
||||
std::cout << "Cannot parse: WebToken" << std::endl;
|
||||
@@ -588,6 +591,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_to_json(Obj,"expires",expires);
|
||||
field_to_json(Obj,"idleTimeout",idleTimeout);
|
||||
field_to_json(Obj,"revocationDate",revocationDate);
|
||||
field_to_json(Obj,"lastRefresh", lastRefresh);
|
||||
}
|
||||
|
||||
bool Token::from_json(const Poco::JSON::Object::Ptr &Obj) {
|
||||
@@ -600,6 +604,7 @@ namespace OpenWifi::SecurityObjects {
|
||||
field_from_json(Obj,"expires",expires);
|
||||
field_from_json(Obj,"idleTimeout",idleTimeout);
|
||||
field_from_json(Obj,"revocationDate",revocationDate);
|
||||
field_from_json(Obj,"lastRefresh", lastRefresh);
|
||||
return true;
|
||||
} catch(...) {
|
||||
std::cout << "Cannot parse: Token" << std::endl;
|
||||
|
||||
@@ -41,6 +41,7 @@ namespace OpenWifi {
|
||||
uint64_t idle_timeout_=0;
|
||||
AclTemplate acl_template_;
|
||||
uint64_t created_=0;
|
||||
uint64_t lastRefresh_=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
@@ -292,6 +293,7 @@ namespace OpenWifi {
|
||||
uint64_t expires=0;
|
||||
uint64_t idleTimeout=0;
|
||||
uint64_t revocationDate=0;
|
||||
uint64_t lastRefresh=0;
|
||||
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
bool from_json(const Poco::JSON::Object::Ptr &Obj);
|
||||
|
||||
@@ -104,7 +104,8 @@ namespace OpenWifi {
|
||||
RATE_LIMIT_EXCEEDED,
|
||||
BAD_MFA_TRANSACTION,
|
||||
MFA_FAILURE,
|
||||
SECURITY_SERVICE_UNREACHABLE
|
||||
SECURITY_SERVICE_UNREACHABLE,
|
||||
CANNOT_REFRESH_TOKEN
|
||||
};
|
||||
|
||||
class AppServiceRegistry {
|
||||
@@ -652,7 +653,8 @@ namespace OpenWifi::Utils {
|
||||
[[nodiscard]] inline bool ValidUUID(const std::string &UUID) {
|
||||
if(UUID.size()>36)
|
||||
return false;
|
||||
return (std::all_of(UUID.begin(),UUID.end(),[](auto i){return i=='-' || std::isxdigit(i);}));
|
||||
uint dashes=0;
|
||||
return (std::all_of(UUID.begin(),UUID.end(),[&](auto i){ if(i=='-') dashes++; return i=='-' || std::isxdigit(i);})) && (dashes>0);
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::vector<std::string> Split(const std::string &List, char Delimiter=',' ) {
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace OpenWifi {
|
||||
ORM::Field{"created", ORM::FieldType::FT_BIGINT},
|
||||
ORM::Field{"expires", ORM::FieldType::FT_BIGINT},
|
||||
ORM::Field{"idleTimeOut", ORM::FieldType::FT_BIGINT},
|
||||
ORM::Field{"revocationDate", ORM::FieldType::FT_BIGINT}
|
||||
ORM::Field{"revocationDate", ORM::FieldType::FT_BIGINT},
|
||||
ORM::Field{"lastRefresh", ORM::FieldType::FT_BIGINT}
|
||||
};
|
||||
|
||||
static ORM::IndexVec MakeIndices(const std::string &shortname) {
|
||||
@@ -53,6 +54,17 @@ namespace OpenWifi {
|
||||
return CreateRecord(T);
|
||||
}
|
||||
|
||||
bool BaseTokenDB::Upgrade([[maybe_unused]] uint32_t from, uint32_t &to) {
|
||||
std::vector<std::string> Statements{
|
||||
"alter table " + TableName_ + " add column lastRefresh BIGINT default 0;"
|
||||
};
|
||||
RunScript(Statements);
|
||||
to = 1;
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BaseTokenDB::GetToken(std::string &Token, SecurityObjects::WebToken &WT, std::string & UserId, uint64_t &RevocationDate) {
|
||||
SecurityObjects::Token T;
|
||||
|
||||
@@ -64,6 +76,7 @@ namespace OpenWifi {
|
||||
WT.created_ = T.created;
|
||||
WT.expires_in_ = T.expires;
|
||||
WT.idle_timeout_ = T.idleTimeout;
|
||||
WT.lastRefresh_ = T.lastRefresh;
|
||||
RevocationDate = T.revocationDate;
|
||||
UserId = T.userName;
|
||||
return true;
|
||||
@@ -71,6 +84,22 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BaseTokenDB::RefreshToken(const std::string &OldToken, const std::string &NewToken, const std::string &NewRefreshToken, uint64_t LastRefresh ) {
|
||||
SecurityObjects::Token T;
|
||||
|
||||
if(GetRecord("token", OldToken, T)) {
|
||||
T.token = NewToken;
|
||||
T.refreshToken = NewRefreshToken;
|
||||
T.lastRefresh = LastRefresh;
|
||||
T.created = OpenWifi::Now();
|
||||
UpdateRecord("token",OldToken,T);
|
||||
Cache_->Delete("token",OldToken);
|
||||
Cache_->UpdateCache(T);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BaseTokenDB::IsTokenRevoked(std::string &Token) {
|
||||
SecurityObjects::Token T;
|
||||
|
||||
@@ -163,6 +192,7 @@ template<> void ORM::DB<OpenWifi::TokenRecordTuple,
|
||||
U.expires = T.get<5>();
|
||||
U.idleTimeout = T.get<6>();
|
||||
U.revocationDate = T.get<7>();
|
||||
U.lastRefresh = T.get<8>();
|
||||
}
|
||||
|
||||
template<> void ORM::DB< OpenWifi::TokenRecordTuple,
|
||||
@@ -176,4 +206,5 @@ template<> void ORM::DB< OpenWifi::TokenRecordTuple,
|
||||
T.set<5>(U.expires);
|
||||
T.set<6>(U.idleTimeout);
|
||||
T.set<7>(U.revocationDate);
|
||||
T.set<8>(U.lastRefresh);
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ namespace OpenWifi {
|
||||
uint64_t, // Created = 0;
|
||||
uint64_t, // Expires = 0;
|
||||
uint64_t, // IdleTimeOut = 0;
|
||||
uint64_t // RevocationDate = 0;
|
||||
uint64_t, // RevocationDate = 0;
|
||||
uint64_t // lastRefresh
|
||||
> TokenRecordTuple;
|
||||
typedef std::vector <TokenRecordTuple> TokenRecordTupleList;
|
||||
|
||||
@@ -41,7 +42,6 @@ namespace OpenWifi {
|
||||
void Create(const SecurityObjects::Token &R) override;
|
||||
bool GetFromCache(const std::string &FieldName, const std::string &Value, SecurityObjects::Token &R) override;
|
||||
void Delete(const std::string &FieldName, const std::string &Value) override;
|
||||
|
||||
private:
|
||||
std::mutex Mutex_;
|
||||
std::unique_ptr<Poco::ExpireLRUCache<std::string,SecurityObjects::Token>> CacheByToken_;
|
||||
@@ -60,6 +60,10 @@ namespace OpenWifi {
|
||||
bool CleanExpiredTokens();
|
||||
bool RevokeAllTokens( std::string & UserName );
|
||||
bool GetToken(std::string &Token, SecurityObjects::WebToken &WT, std::string & UserId, uint64_t &RevocationDate);
|
||||
bool RefreshToken(const std::string &OldToken, const std::string &NewToken, const std::string &NewRefreshToken, uint64_t LstRefresh );
|
||||
inline uint32_t Version() override { return 1;}
|
||||
bool Upgrade(uint32_t from, uint32_t &to) override;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user