mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
synced 2025-10-30 10:22:22 +00:00
Adding Subscriber DB Support.
This commit is contained in:
@@ -64,18 +64,27 @@ add_executable( owsec
|
||||
src/RESTObjects/RESTAPI_ProvObjects.cpp src/RESTObjects/RESTAPI_ProvObjects.h
|
||||
src/RESTObjects/RESTAPI_GWobjects.h src/RESTObjects/RESTAPI_GWobjects.cpp
|
||||
src/RESTObjects/RESTAPI_FMSObjects.h src/RESTObjects/RESTAPI_FMSObjects.cpp
|
||||
src/RESTAPI/RESTAPI_oauth2Handler.h src/RESTAPI/RESTAPI_oauth2Handler.cpp
|
||||
src/RESTAPI/RESTAPI_oauth2_handler.h src/RESTAPI/RESTAPI_oauth2_handler.cpp
|
||||
src/RESTAPI/RESTAPI_users_handler.cpp src/RESTAPI/RESTAPI_users_handler.h
|
||||
src/RESTAPI/RESTAPI_user_handler.cpp src/RESTAPI/RESTAPI_user_handler.h
|
||||
src/RESTAPI/RESTAPI_action_links.cpp src/RESTAPI/RESTAPI_action_links.h
|
||||
src/RESTAPI/RESTAPI_validateToken_handler.cpp src/RESTAPI/RESTAPI_validateToken_handler.h
|
||||
src/RESTAPI/RESTAPI_systemEndpoints_handler.cpp src/RESTAPI/RESTAPI_systemEndpoints_handler.h
|
||||
src/RESTAPI/RESTAPI_AssetServer.cpp src/RESTAPI/RESTAPI_AssetServer.h
|
||||
src/RESTAPI/RESTAPI_avatarHandler.cpp src/RESTAPI/RESTAPI_avatarHandler.h
|
||||
src/RESTAPI/RESTAPI_validate_token_handler.cpp src/RESTAPI/RESTAPI_validate_token_handler.h
|
||||
src/RESTAPI/RESTAPI_system_endpoints_handler.cpp src/RESTAPI/RESTAPI_system_endpoints_handler.h
|
||||
src/RESTAPI/RESTAPI_asset_server.cpp src/RESTAPI/RESTAPI_asset_server.h
|
||||
src/RESTAPI/RESTAPI_avatar_handler.cpp src/RESTAPI/RESTAPI_avatar_handler.h
|
||||
src/RESTAPI/RESTAPI_email_handler.cpp src/RESTAPI/RESTAPI_email_handler.h
|
||||
src/RESTAPI/RESTAPI_sms_handler.cpp src/RESTAPI/RESTAPI_sms_handler.h
|
||||
src/storage/storage_avatar.cpp src/storage/storage_avatar.h src/storage/storage_users.h
|
||||
src/storage/storage_tables.cpp src/storage/storage_users.cpp src/storage/storage_tokens.cpp
|
||||
src/storage/storage_avatar.cpp src/storage/storage_avatar.h
|
||||
src/storage/storage_users.h src/storage/storage_users.cpp
|
||||
src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h
|
||||
src/storage/storage_tokens.h src/storage/storage_tokens.cpp
|
||||
src/storage/storage_subtokens.h src/storage/storage_subtokens.cpp
|
||||
src/storage/storage_preferences.cpp src/storage/storage_preferences.h
|
||||
src/storage/storage_subscribers.cpp src/storage/storage_subscribers.h
|
||||
src/storage/storage_tables.cpp
|
||||
src/RESTAPI/RESTAPI_suboauth2_handler.h src/RESTAPI/RESTAPI_suboauth2_handler.cpp
|
||||
src/RESTAPI/RESTAPI_subuser_handler.h src/RESTAPI/RESTAPI_subuser_handler.cpp
|
||||
src/RESTAPI/RESTAPI_subusers_handler.h src/RESTAPI/RESTAPI_subusers_handler.cpp
|
||||
src/APIServers.cpp
|
||||
src/Daemon.h src/Daemon.cpp
|
||||
src/AuthService.h src/AuthService.cpp
|
||||
@@ -86,10 +95,9 @@ add_executable( owsec
|
||||
src/SMS_provider_aws.cpp src/SMS_provider_aws.h
|
||||
src/SMS_provider.cpp src/SMS_provider.h
|
||||
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
|
||||
src/storage/storage_actionLinks.cpp src/storage/storage_actionLinks.h
|
||||
src/storage/storage_tokens.h
|
||||
src/ActionLinkManager.cpp src/ActionLinkManager.h
|
||||
src/ACLProcessor.h src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h src/storage/storage_preferences.cpp src/storage/storage_preferences.h src/framework/OpenWifiTypes.h)
|
||||
src/ACLProcessor.h src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h
|
||||
src/framework/OpenWifiTypes.h)
|
||||
|
||||
if(NOT SMALL_BUILD)
|
||||
target_link_libraries(owsec PUBLIC
|
||||
|
||||
@@ -730,6 +730,64 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/suboauth2:
|
||||
post:
|
||||
tags:
|
||||
- Authentication
|
||||
summary: Get access token - to be used as Bearer token header for all other API requests.
|
||||
operationId: getAccessToken
|
||||
parameters:
|
||||
- in: query
|
||||
name: newPassword
|
||||
description: used when a user is trying to change her password. This will be the new password.
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
- in: query
|
||||
name: forgotPassword
|
||||
description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: requirements
|
||||
description: A user forgot her password. She needs to present her e-mail address in the userId and set this to true
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: resendMFACode
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
name: completeMFAChallenge
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
requestBody:
|
||||
description: User id and password
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/WebTokenRequest'
|
||||
- $ref: '#/components/schemas/MFAChallengeResponse'
|
||||
responses:
|
||||
200:
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/WebTokenResult'
|
||||
- $ref: '#/components/schemas/MFAChallengeRequest'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/oauth2/{token}:
|
||||
delete:
|
||||
tags:
|
||||
@@ -755,6 +813,31 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/suboauth2/{token}:
|
||||
delete:
|
||||
tags:
|
||||
- Authentication
|
||||
summary: Revoke a token.
|
||||
operationId: removeAccessToken
|
||||
parameters:
|
||||
- in: path
|
||||
name: token
|
||||
schema:
|
||||
type:
|
||||
string
|
||||
required: true
|
||||
responses:
|
||||
204:
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/systemEndpoints:
|
||||
get:
|
||||
tags:
|
||||
@@ -819,6 +902,52 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/subusers:
|
||||
get:
|
||||
tags:
|
||||
- User Management
|
||||
summary: Retrieve a list of existing users as well as some information about them.
|
||||
operationId: getUsers
|
||||
parameters:
|
||||
- in: query
|
||||
name: offset
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
- in: query
|
||||
name: limit
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
- in: query
|
||||
description: Selecting this option means the newest record will be returned. Use limit to select how many.
|
||||
name: filter
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
- in: query
|
||||
description: Return only the ids.
|
||||
name: idOnly
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
- in: query
|
||||
description: Return only the ids.
|
||||
name: select
|
||||
schema:
|
||||
type: string
|
||||
example: id1,id2,id3,id4,id5
|
||||
required: false
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/UserList'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/user/{id}:
|
||||
get:
|
||||
tags:
|
||||
@@ -923,6 +1052,110 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/subuser/{id}:
|
||||
get:
|
||||
tags:
|
||||
- User Management
|
||||
operationId: getUser
|
||||
summary: Retrieve the information for a single user.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/UserInfo'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
delete:
|
||||
tags:
|
||||
- User Management
|
||||
operationId: deleteUser
|
||||
summary: Delete a single user.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
responses:
|
||||
204:
|
||||
$ref: '#/components/responses/Success'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
post:
|
||||
tags:
|
||||
- User Management
|
||||
operationId: createUser
|
||||
summary: Create a single user.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
#must be set to 0 for user creation
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
- in: query
|
||||
name: email_verification
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
requestBody:
|
||||
description: User details (some fields are ignored during creation)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserInfo'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/UserInfo'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
put:
|
||||
tags:
|
||||
- User Management
|
||||
operationId: updateUser
|
||||
summary: Modify a single user.
|
||||
parameters:
|
||||
- in: path
|
||||
name: id
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: true
|
||||
- in: query
|
||||
name: email_verification
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
requestBody:
|
||||
description: User details (some fields are ignored during update)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UserInfo'
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/UserInfo'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/avatar/{id}:
|
||||
get:
|
||||
tags:
|
||||
@@ -1196,6 +1429,26 @@ paths:
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/validateSubToken:
|
||||
get:
|
||||
tags:
|
||||
- Security
|
||||
summary: Allows any microservice to validate a token and get security policy for a specific user.
|
||||
operationId: validateToken
|
||||
parameters:
|
||||
- in: query
|
||||
name: token
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
responses:
|
||||
200:
|
||||
$ref: '#/components/schemas/TokenValidationResult'
|
||||
403:
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
404:
|
||||
$ref: '#/components/responses/NotFound'
|
||||
|
||||
/system:
|
||||
post:
|
||||
tags:
|
||||
|
||||
@@ -4,34 +4,40 @@
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
#include "RESTAPI/RESTAPI_oauth2Handler.h"
|
||||
#include "RESTAPI/RESTAPI_oauth2_handler.h"
|
||||
#include "RESTAPI/RESTAPI_user_handler.h"
|
||||
#include "RESTAPI/RESTAPI_users_handler.h"
|
||||
#include "RESTAPI/RESTAPI_action_links.h"
|
||||
#include "RESTAPI/RESTAPI_systemEndpoints_handler.h"
|
||||
#include "RESTAPI/RESTAPI_AssetServer.h"
|
||||
#include "RESTAPI/RESTAPI_avatarHandler.h"
|
||||
#include "RESTAPI/RESTAPI_system_endpoints_handler.h"
|
||||
#include "RESTAPI/RESTAPI_asset_server.h"
|
||||
#include "RESTAPI/RESTAPI_avatar_handler.h"
|
||||
#include "RESTAPI/RESTAPI_email_handler.h"
|
||||
#include "RESTAPI/RESTAPI_sms_handler.h"
|
||||
#include "RESTAPI/RESTAPI_validateToken_handler.h"
|
||||
#include "RESTAPI/RESTAPI_validate_token_handler.h"
|
||||
#include "RESTAPI/RESTAPI_preferences.h"
|
||||
#include "RESTAPI/RESTAPI_suboauth2_handler.h"
|
||||
#include "RESTAPI/RESTAPI_subuser_handler.h"
|
||||
#include "RESTAPI/RESTAPI_subusers_handler.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
Poco::Net::HTTPRequestHandler * RESTAPI_external_server(const char *Path, RESTAPIHandler::BindingMap &Bindings,
|
||||
Poco::Logger & L, RESTAPI_GenericServer & S) {
|
||||
return RESTAPI_Router<
|
||||
RESTAPI_oauth2Handler,
|
||||
RESTAPI_oauth2_handler,
|
||||
RESTAPI_users_handler,
|
||||
RESTAPI_user_handler,
|
||||
RESTAPI_system_command,
|
||||
RESTAPI_AssetServer,
|
||||
RESTAPI_systemEndpoints_handler,
|
||||
RESTAPI_asset_server,
|
||||
RESTAPI_system_endpoints_handler,
|
||||
RESTAPI_action_links,
|
||||
RESTAPI_avatarHandler,
|
||||
RESTAPI_avatar_handler,
|
||||
RESTAPI_email_handler,
|
||||
RESTAPI_sms_handler,
|
||||
RESTAPI_preferences
|
||||
RESTAPI_preferences,
|
||||
RESTAPI_suboauth2_handler,
|
||||
RESTAPI_subuser_handler,
|
||||
RESTAPI_subusers_handler
|
||||
>(Path, Bindings, L, S);
|
||||
}
|
||||
|
||||
@@ -42,8 +48,11 @@ namespace OpenWifi {
|
||||
RESTAPI_user_handler,
|
||||
RESTAPI_system_command,
|
||||
RESTAPI_action_links,
|
||||
RESTAPI_validateToken_handler,
|
||||
RESTAPI_sms_handler
|
||||
RESTAPI_validate_token_handler,
|
||||
RESTAPI_sms_handler,
|
||||
RESTAPI_suboauth2_handler,
|
||||
RESTAPI_subuser_handler,
|
||||
RESTAPI_subusers_handler
|
||||
>(Path, Bindings, L, S);
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ namespace OpenWifi {
|
||||
Signer_.addAllAlgorithms();
|
||||
Logger_.notice("Starting...");
|
||||
PasswordValidation_ = PasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.validation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
|
||||
SubPasswordValidation_ = SubPasswordValidationStr_ = MicroService::instance().ConfigGetString("authentication.subvalidation.expression","^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*-]).{8,}$");
|
||||
TokenAging_ = (uint64_t) MicroService::instance().ConfigGetInt("authentication.token.ageing", 30 * 24 * 60 * 60);
|
||||
HowManyOldPassword_ = MicroService::instance().ConfigGetInt("authentication.oldpasswords", 5);
|
||||
return 0;
|
||||
@@ -99,11 +100,59 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::IsSubAuthorized(Poco::Net::HTTPServerRequest & Request, std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired )
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
Expired = false;
|
||||
try {
|
||||
std::string CallToken;
|
||||
Poco::Net::OAuth20Credentials Auth(Request);
|
||||
if (Auth.getScheme() == "Bearer") {
|
||||
CallToken = Auth.getBearerToken();
|
||||
}
|
||||
|
||||
if(!CallToken.empty()) {
|
||||
auto Client = SubUserCache_.get(CallToken);
|
||||
if( Client.isNull() ) {
|
||||
SecurityObjects::UserInfoAndPolicy UInfo2;
|
||||
uint64_t RevocationDate=0;
|
||||
if(StorageService()->GetSubToken(CallToken,UInfo2,RevocationDate)) {
|
||||
if(RevocationDate!=0)
|
||||
return false;
|
||||
Expired = (UInfo2.webtoken.created_ + UInfo2.webtoken.expires_in_) < time(nullptr);
|
||||
if(StorageService()->GetSubUserById(UInfo2.userinfo.Id,UInfo.userinfo)) {
|
||||
UInfo.webtoken = UInfo2.webtoken;
|
||||
SubUserCache_.update(CallToken, UInfo);
|
||||
SessionToken = CallToken;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(!Expired) {
|
||||
SessionToken = CallToken;
|
||||
UInfo = *Client ;
|
||||
return true;
|
||||
}
|
||||
RevokeSubToken(CallToken);
|
||||
return false;
|
||||
}
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void AuthService::RevokeToken(std::string & Token) {
|
||||
UserCache_.remove(Token);
|
||||
StorageService()->RevokeToken(Token);
|
||||
}
|
||||
|
||||
void AuthService::RevokeSubToken(std::string & Token) {
|
||||
UserCache_.remove(Token);
|
||||
StorageService()->RevokeSubToken(Token);
|
||||
}
|
||||
|
||||
bool AuthService::DeleteUserFromCache(const std::string &UserName) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
@@ -121,6 +170,23 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthService::DeleteSubUserFromCache(const std::string &UserName) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
std::vector<std::string> OldTokens;
|
||||
|
||||
SubUserCache_.forEach([&OldTokens,UserName](const std::string &token, const SecurityObjects::UserInfoAndPolicy& O) -> void
|
||||
{ if(O.userinfo.email==UserName)
|
||||
OldTokens.push_back(token);
|
||||
});
|
||||
|
||||
for(const auto &i:OldTokens) {
|
||||
SubLogout(i,false);
|
||||
SubUserCache_.remove(i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthService::RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo) {
|
||||
return (UInfo.userinfo.userTypeProprietaryInfo.mfa.enabled && MFAServer().MethodEnabled(UInfo.userinfo.userTypeProprietaryInfo.mfa.method));
|
||||
}
|
||||
@@ -129,6 +195,10 @@ namespace OpenWifi {
|
||||
return std::regex_match(Password, PasswordValidation_);
|
||||
}
|
||||
|
||||
bool AuthService::ValidateSubPassword(const std::string &Password) {
|
||||
return std::regex_match(Password, SubPasswordValidation_);
|
||||
}
|
||||
|
||||
void AuthService::Logout(const std::string &token, bool EraseFromCache) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
@@ -148,6 +218,25 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
|
||||
void AuthService::SubLogout(const std::string &token, bool EraseFromCache) {
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
try {
|
||||
Poco::JSON::Object Obj;
|
||||
Obj.set("event", "remove-token");
|
||||
Obj.set("id", MicroService::instance().ID());
|
||||
Obj.set("token", token);
|
||||
std::stringstream ResultText;
|
||||
Poco::JSON::Stringifier::stringify(Obj, ResultText);
|
||||
std::string Tmp{token};
|
||||
RevokeSubToken(Tmp);
|
||||
KafkaManager()->PostMessage(KafkaTopics::SERVICE_EVENTS, MicroService::instance().PrivateEndPoint(), ResultText.str(),
|
||||
false);
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string AuthService::GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type) {
|
||||
std::string Identity(UserName + ":" + Poco::format("%d",(int)std::time(nullptr)) + ":" + std::to_string(rand()));
|
||||
HMAC_.update(Identity);
|
||||
@@ -198,6 +287,30 @@ namespace OpenWifi {
|
||||
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
|
||||
}
|
||||
|
||||
void AuthService::CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo)
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
SecurityObjects::AclTemplate ACL;
|
||||
ACL.PortalLogin_ = ACL.Read_ = ACL.ReadWrite_ = ACL.ReadWriteCreate_ = ACL.Delete_ = true;
|
||||
UInfo.webtoken.acl_template_ = ACL;
|
||||
UInfo.webtoken.expires_in_ = TokenAging_ ;
|
||||
UInfo.webtoken.idle_timeout_ = 5 * 60;
|
||||
UInfo.webtoken.token_type_ = "Bearer";
|
||||
UInfo.webtoken.access_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME);
|
||||
UInfo.webtoken.id_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,USERNAME);
|
||||
UInfo.webtoken.refresh_token_ = GenerateTokenHMAC(UInfo.userinfo.Id,CUSTOM);
|
||||
UInfo.webtoken.created_ = time(nullptr);
|
||||
UInfo.webtoken.username_ = UserName;
|
||||
UInfo.webtoken.errorCode = 0;
|
||||
UInfo.webtoken.userMustChangePassword = false;
|
||||
SubUserCache_.update(UInfo.webtoken.access_token_,UInfo);
|
||||
StorageService()->SetSubLastLogin(UInfo.userinfo.Id);
|
||||
StorageService()->AddSubToken(UInfo.userinfo.Id, UInfo.webtoken.access_token_,
|
||||
UInfo.webtoken.refresh_token_, UInfo.webtoken.token_type_,
|
||||
UInfo.webtoken.expires_in_, UInfo.webtoken.idle_timeout_);
|
||||
}
|
||||
|
||||
bool AuthService::SetPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
@@ -232,6 +345,40 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthService::SetSubPassword(const std::string &NewPassword, SecurityObjects::UserInfo & UInfo) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
Poco::toLowerInPlace(UInfo.email);
|
||||
for (const auto &i:UInfo.lastPasswords) {
|
||||
auto Tokens = Poco::StringTokenizer(i,"|");
|
||||
if(Tokens.count()==2) {
|
||||
const auto & Salt = Tokens[0];
|
||||
for(const auto &j:UInfo.lastPasswords) {
|
||||
auto OldTokens = Poco::StringTokenizer(j,"|");
|
||||
if(OldTokens.count()==2) {
|
||||
SHA2_.update(Salt+NewPassword+UInfo.email);
|
||||
if(OldTokens[1]==Utils::ToHex(SHA2_.digest()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
SHA2_.update(NewPassword+UInfo.email);
|
||||
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(UInfo.lastPasswords.size()==HowManyOldPassword_) {
|
||||
UInfo.lastPasswords.erase(UInfo.lastPasswords.begin());
|
||||
}
|
||||
|
||||
auto NewHash = ComputeNewPasswordHash(UInfo.email,NewPassword);
|
||||
UInfo.lastPasswords.push_back(NewHash);
|
||||
UInfo.currentPassword = NewHash;
|
||||
UInfo.changePassword = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string GetMeSomeSalt() {
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
return std::to_string(start.time_since_epoch().count());
|
||||
@@ -261,6 +408,23 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
std::string UName = Poco::trim(Poco::toLower(UserName));
|
||||
auto Tokens = Poco::StringTokenizer(StoredPassword,"|");
|
||||
if(Tokens.count()==1) {
|
||||
SHA2_.update(Password+UName);
|
||||
if(Tokens[0]==Utils::ToHex(SHA2_.digest()))
|
||||
return true;
|
||||
} else if (Tokens.count()==2) {
|
||||
SHA2_.update(Tokens[0]+Password+UName);
|
||||
if(Tokens[1]==Utils::ToHex(SHA2_.digest()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UNAUTHORIZED_REASON AuthService::Authorize( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired )
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
@@ -306,6 +470,51 @@ namespace OpenWifi {
|
||||
return INVALID_CREDENTIALS;
|
||||
}
|
||||
|
||||
UNAUTHORIZED_REASON AuthService::AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired )
|
||||
{
|
||||
std::lock_guard Guard(Mutex_);
|
||||
|
||||
Poco::toLowerInPlace(UserName);
|
||||
|
||||
if(StorageService()->GetSubUserByEmail(UserName,UInfo.userinfo)) {
|
||||
if(UInfo.userinfo.waitingForEmailCheck) {
|
||||
return USERNAME_PENDING_VERIFICATION;
|
||||
}
|
||||
|
||||
if(!ValidateSubPasswordHash(UserName,Password,UInfo.userinfo.currentPassword)) {
|
||||
return INVALID_CREDENTIALS;
|
||||
}
|
||||
|
||||
if(UInfo.userinfo.changePassword && NewPassword.empty()) {
|
||||
UInfo.webtoken.userMustChangePassword = true ;
|
||||
return PASSWORD_CHANGE_REQUIRED;
|
||||
}
|
||||
|
||||
if(!NewPassword.empty() && !ValidateSubPassword(NewPassword)) {
|
||||
return PASSWORD_INVALID;
|
||||
}
|
||||
|
||||
if(UInfo.userinfo.changePassword || !NewPassword.empty()) {
|
||||
if(!SetSubPassword(NewPassword,UInfo.userinfo)) {
|
||||
UInfo.webtoken.errorCode = 1;
|
||||
return PASSWORD_ALREADY_USED;
|
||||
}
|
||||
UInfo.userinfo.lastPasswordChange = std::time(nullptr);
|
||||
UInfo.userinfo.changePassword = false;
|
||||
StorageService()->UpdateSubUserInfo(AUTHENTICATION_SYSTEM, UInfo.userinfo.Id,UInfo.userinfo);
|
||||
}
|
||||
|
||||
// so we have a good password, password up date has taken place if need be, now generate the token.
|
||||
UInfo.userinfo.lastLogin=std::time(nullptr);
|
||||
StorageService()->SetSubLastLogin(UInfo.userinfo.Id);
|
||||
CreateSubToken(UserName, UInfo );
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
return INVALID_CREDENTIALS;
|
||||
}
|
||||
|
||||
bool AuthService::SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
|
||||
@@ -341,6 +550,41 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason) {
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
|
||||
if(StorageService()->GetSubUserByEmail(Email,UInfo)) {
|
||||
switch (Reason) {
|
||||
|
||||
case FORGOT_PASSWORD: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "Password reset link";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=password_reset&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "password_reset.txt", Attrs);
|
||||
}
|
||||
break;
|
||||
|
||||
case EMAIL_VERIFICATION: {
|
||||
MessageAttributes Attrs;
|
||||
Attrs[RECIPIENT_EMAIL] = UInfo.email;
|
||||
Attrs[LOGO] = GetLogoAssetURI();
|
||||
Attrs[SUBJECT] = "EMail Address Verification";
|
||||
Attrs[ACTION_LINK] = MicroService::instance().GetPublicAPIEndPoint() + "/actionLink?action=email_verification&id=" + LinkId ;
|
||||
SMTPMailerService()->SendMessage(UInfo.email, "email_verification.txt", Attrs);
|
||||
UInfo.waitingForEmailCheck = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::VerifyEmail(SecurityObjects::UserInfo &UInfo) {
|
||||
SecurityObjects::ActionLink A;
|
||||
|
||||
@@ -354,6 +598,19 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthService::VerifySubEmail(SecurityObjects::UserInfo &UInfo) {
|
||||
SecurityObjects::ActionLink A;
|
||||
|
||||
A.action = OpenWifi::SecurityObjects::LinkActions::VERIFY_EMAIL;
|
||||
A.userId = UInfo.email;
|
||||
A.id = MicroService::CreateUUID();
|
||||
A.created = std::time(nullptr);
|
||||
A.expires = A.created + 24*60*60;
|
||||
StorageService()->CreateAction(A);
|
||||
UInfo.waitingForEmailCheck = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AuthService::IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
@@ -388,5 +645,38 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AuthService::IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired) {
|
||||
std::lock_guard G(Mutex_);
|
||||
|
||||
Expired = false;
|
||||
|
||||
auto Client = SubUserCache_.get(Token);
|
||||
if(!Client.isNull()) {
|
||||
Expired = (Client->webtoken.created_ + Client->webtoken.expires_in_) < std::time(nullptr);
|
||||
WebToken = Client->webtoken;
|
||||
UserInfo = Client->userinfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string TToken{Token};
|
||||
if(StorageService()->IsSubTokenRevoked(TToken)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get the token from disk...
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
uint64_t RevocationDate=0;
|
||||
if(StorageService()->GetSubToken(TToken, UInfo, RevocationDate)) {
|
||||
if(RevocationDate!=0)
|
||||
return false;
|
||||
Expired = (UInfo.webtoken.created_ + UInfo.webtoken.expires_in_) < std::time(nullptr);
|
||||
if(StorageService()->GetSubUserById(UInfo.userinfo.Id,UInfo.userinfo)) {
|
||||
WebToken = UInfo.webtoken;
|
||||
SubUserCache_.update(UInfo.webtoken.access_token_, UInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
||||
@@ -59,23 +59,42 @@ namespace OpenWifi{
|
||||
[[nodiscard]] const std:: string & PasswordValidationExpression() const { return PasswordValidationStr_;};
|
||||
void Logout(const std::string &token, bool EraseFromCache=true);
|
||||
|
||||
[[nodiscard]] bool IsSubAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired);
|
||||
[[nodiscard]] UNAUTHORIZED_REASON AuthorizeSub( std::string & UserName, const std::string & Password, const std::string & NewPassword, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
|
||||
void CreateSubToken(const std::string & UserName, SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
[[nodiscard]] bool SetSubPassword(const std::string &Password, SecurityObjects::UserInfo & UInfo);
|
||||
[[nodiscard]] const std:: string & SubPasswordValidationExpression() const { return PasswordValidationStr_;};
|
||||
void SubLogout(const std::string &token, bool EraseFromCache=true);
|
||||
|
||||
bool ValidatePassword(const std::string &pwd);
|
||||
bool ValidateSubPassword(const std::string &pwd);
|
||||
|
||||
[[nodiscard]] bool IsValidToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
|
||||
[[nodiscard]] bool IsValidSubToken(const std::string &Token, SecurityObjects::WebToken &WebToken, SecurityObjects::UserInfo &UserInfo, bool & Expired);
|
||||
[[nodiscard]] std::string GenerateTokenJWT(const std::string & UserName, ACCESS_TYPE Type);
|
||||
[[nodiscard]] std::string GenerateTokenHMAC(const std::string & UserName, ACCESS_TYPE Type);
|
||||
|
||||
[[nodiscard]] std::string ComputeNewPasswordHash(const std::string &UserName, const std::string &Password);
|
||||
[[nodiscard]] bool ValidatePasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
|
||||
[[nodiscard]] bool ValidateSubPasswordHash(const std::string & UserName, const std::string & Password, const std::string &StoredPassword);
|
||||
|
||||
[[nodiscard]] bool UpdatePassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
|
||||
[[nodiscard]] std::string ResetPassword(const std::string &Admin, const std::string &UserName);
|
||||
|
||||
[[nodiscard]] bool UpdateSubPassword(const std::string &Admin, const std::string &UserName, const std::string & OldPassword, const std::string &NewPassword);
|
||||
[[nodiscard]] std::string ResetSubPassword(const std::string &Admin, const std::string &UserName);
|
||||
|
||||
[[nodiscard]] static bool VerifyEmail(SecurityObjects::UserInfo &UInfo);
|
||||
[[nodiscard]] static bool VerifySubEmail(SecurityObjects::UserInfo &UInfo);
|
||||
|
||||
[[nodiscard]] static bool SendEmailToUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
|
||||
[[nodiscard]] static bool SendEmailToSubUser(const std::string &LinkId, std::string &Email, EMAIL_REASON Reason);
|
||||
[[nodiscard]] bool DeleteUserFromCache(const std::string &UserName);
|
||||
[[nodiscard]] bool DeleteSubUserFromCache(const std::string &UserName);
|
||||
[[nodiscard]] bool RequiresMFA(const SecurityObjects::UserInfoAndPolicy &UInfo);
|
||||
|
||||
void RevokeToken(std::string & Token);
|
||||
void RevokeSubToken(std::string & Token);
|
||||
|
||||
[[nodiscard]] static inline const std::string GetLogoAssetURI() {
|
||||
return MicroService::instance().PublicEndPoint() + "/wwwassets/the_logo.png";
|
||||
@@ -88,11 +107,16 @@ namespace OpenWifi{
|
||||
private:
|
||||
Poco::JWT::Signer Signer_;
|
||||
Poco::SHA2Engine SHA2_;
|
||||
Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy> UserCache_{2048,1200000};
|
||||
// SecurityObjects::UserInfoCache UserCache_;
|
||||
std::string PasswordValidationStr_;
|
||||
std::regex PasswordValidation_;
|
||||
uint64_t TokenAging_ = 30 * 24 * 60 * 60;
|
||||
|
||||
Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy> UserCache_{256,1200000};
|
||||
Poco::ExpireLRUCache<std::string,SecurityObjects::UserInfoAndPolicy> SubUserCache_{4096,1200000};
|
||||
|
||||
std::string PasswordValidationStr_;
|
||||
std::string SubPasswordValidationStr_;
|
||||
std::regex PasswordValidation_;
|
||||
std::regex SubPasswordValidation_;
|
||||
|
||||
uint64_t TokenAging_ = 30 * 24 * 60 * 60;
|
||||
uint64_t HowManyOldPassword_=5;
|
||||
|
||||
class SHA256Engine : public Poco::Crypto::DigestEngine
|
||||
@@ -121,8 +145,11 @@ namespace OpenWifi{
|
||||
|
||||
inline AuthService * AuthService() { return AuthService::instance(); }
|
||||
|
||||
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired) {
|
||||
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired );
|
||||
[[nodiscard]] inline bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo , bool & Expired, bool Sub ) {
|
||||
if(Sub)
|
||||
return AuthService()->IsSubAuthorized(Request, SessionToken, UInfo, Expired );
|
||||
else
|
||||
return AuthService()->IsAuthorized(Request, SessionToken, UInfo, Expired );
|
||||
}
|
||||
|
||||
} // end of namespace
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
// Created by stephane bourque on 2021-06-22.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_RESTAPI_ACTION_LINKS_H
|
||||
#define UCENTRALSEC_RESTAPI_ACTION_LINKS_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
@@ -33,5 +31,3 @@ namespace OpenWifi {
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRALSEC_RESTAPI_ACTION_LINKS_H
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
// Created by stephane bourque on 2021-07-10.
|
||||
//
|
||||
|
||||
#include "RESTAPI_AssetServer.h"
|
||||
#include "RESTAPI_asset_server.h"
|
||||
#include "Poco/File.h"
|
||||
#include "framework/RESTAPI_protocol.h"
|
||||
#include "Daemon.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_AssetServer::DoGet() {
|
||||
void RESTAPI_asset_server::DoGet() {
|
||||
Poco::File AssetFile;
|
||||
|
||||
if(Request->getURI().find("/favicon.ico") != std::string::npos) {
|
||||
@@ -2,15 +2,14 @@
|
||||
// Created by stephane bourque on 2021-07-10.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_RESTAPI_ASSETSERVER_H
|
||||
#define UCENTRALSEC_RESTAPI_ASSETSERVER_H
|
||||
#pragma once
|
||||
|
||||
#include "../framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_AssetServer : public RESTAPIHandler {
|
||||
class RESTAPI_asset_server : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_AssetServer(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
RESTAPI_asset_server(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_POST,
|
||||
@@ -32,5 +31,3 @@ namespace OpenWifi {
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALSEC_RESTAPI_ASSETSERVER_H
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "RESTAPI_avatarHandler.h"
|
||||
#include "RESTAPI_avatar_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "Poco/Net/HTMLForm.h"
|
||||
#include "framework/RESTAPI_protocol.h"
|
||||
@@ -27,7 +27,7 @@ namespace OpenWifi {
|
||||
Length_ = InputStream.chars();
|
||||
};
|
||||
|
||||
void RESTAPI_avatarHandler::DoPost() {
|
||||
void RESTAPI_avatar_handler::DoPost() {
|
||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
|
||||
@@ -57,7 +57,7 @@ namespace OpenWifi {
|
||||
ReturnObject(Answer);
|
||||
}
|
||||
|
||||
void RESTAPI_avatarHandler::DoGet() {
|
||||
void RESTAPI_avatar_handler::DoGet() {
|
||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||
if (Id.empty()) {
|
||||
return NotFound();
|
||||
@@ -70,7 +70,7 @@ namespace OpenWifi {
|
||||
SendFile(TempAvatar, Type, Name);
|
||||
}
|
||||
|
||||
void RESTAPI_avatarHandler::DoDelete() {
|
||||
void RESTAPI_avatar_handler::DoDelete() {
|
||||
std::string Id = GetBinding(RESTAPI::Protocol::ID, "");
|
||||
if (Id.empty()) {
|
||||
return NotFound();
|
||||
@@ -1,10 +1,7 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-07-15.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_RESTAPI_AVATARHANDLER_H
|
||||
#define UCENTRALSEC_RESTAPI_AVATARHANDLER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
@@ -31,9 +28,9 @@ namespace OpenWifi {
|
||||
Poco::TemporaryFile &TempFile_;
|
||||
};
|
||||
|
||||
class RESTAPI_avatarHandler : public RESTAPIHandler {
|
||||
class RESTAPI_avatar_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_avatarHandler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
RESTAPI_avatar_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{
|
||||
Poco::Net::HTTPRequest::HTTP_GET,
|
||||
@@ -51,4 +48,3 @@ namespace OpenWifi {
|
||||
|
||||
};
|
||||
}
|
||||
#endif //UCENTRALSEC_RESTAPI_AVATARHANDLER_H
|
||||
@@ -2,9 +2,7 @@
|
||||
// Created by stephane bourque on 2021-09-02.
|
||||
//
|
||||
|
||||
#ifndef OWSEC_RESTAPI_EMAIL_HANDLER_H
|
||||
#define OWSEC_RESTAPI_EMAIL_HANDLER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
@@ -24,5 +22,3 @@ namespace OpenWifi {
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OWSEC_RESTAPI_EMAIL_HANDLER_H
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include "Daemon.h"
|
||||
#include "AuthService.h"
|
||||
#include "RESTAPI_oauth2Handler.h"
|
||||
#include "RESTAPI_oauth2_handler.h"
|
||||
#include "MFAServer.h"
|
||||
#include "framework/RESTAPI_protocol.h"
|
||||
#include "framework/MicroService.h"
|
||||
@@ -24,7 +24,7 @@ namespace OpenWifi {
|
||||
U.oauthType.clear();
|
||||
}
|
||||
|
||||
void RESTAPI_oauth2Handler::DoGet() {
|
||||
void RESTAPI_oauth2_handler::DoGet() {
|
||||
bool Expired = false;
|
||||
if (!IsAuthorized(Expired)) {
|
||||
if(Expired)
|
||||
@@ -43,7 +43,7 @@ namespace OpenWifi {
|
||||
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
|
||||
}
|
||||
|
||||
void RESTAPI_oauth2Handler::DoDelete() {
|
||||
void RESTAPI_oauth2_handler::DoDelete() {
|
||||
bool Expired = false;
|
||||
if (!IsAuthorized(Expired)) {
|
||||
if(Expired)
|
||||
@@ -61,7 +61,7 @@ namespace OpenWifi {
|
||||
NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_oauth2Handler::DoPost() {
|
||||
void RESTAPI_oauth2_handler::DoPost() {
|
||||
auto Obj = ParseStream();
|
||||
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
|
||||
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
|
||||
@@ -6,15 +6,13 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRAL_RESTAPI_OAUTH2HANDLER_H
|
||||
#define UCENTRAL_RESTAPI_OAUTH2HANDLER_H
|
||||
|
||||
#pragma once
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_oauth2Handler : public RESTAPIHandler {
|
||||
class RESTAPI_oauth2_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_oauth2Handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
RESTAPI_oauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
@@ -29,4 +27,5 @@ namespace OpenWifi {
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
#endif //UCENTRAL_RESTAPI_OAUTH2HANDLER_H
|
||||
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by stephane bourque on 2021-11-16.
|
||||
//
|
||||
|
||||
#ifndef OWSEC_RESTAPI_PREFERENCES_H
|
||||
#define OWSEC_RESTAPI_PREFERENCES_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
@@ -25,5 +24,3 @@ namespace OpenWifi {
|
||||
void DoDelete() final {};
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OWSEC_RESTAPI_PREFERENCES_H
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
// Created by stephane bourque on 2021-10-09.
|
||||
//
|
||||
|
||||
#ifndef OWSEC_RESTAPI_SMS_HANDLER_H
|
||||
#define OWSEC_RESTAPI_SMS_HANDLER_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
@@ -24,5 +22,3 @@ namespace OpenWifi {
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
#endif //OWSEC_RESTAPI_SMS_HANDLER_H
|
||||
|
||||
157
src/RESTAPI/RESTAPI_suboauth2_handler.cpp
Normal file
157
src/RESTAPI/RESTAPI_suboauth2_handler.cpp
Normal file
@@ -0,0 +1,157 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#include "RESTAPI_suboauth2_handler.h"
|
||||
#include "Daemon.h"
|
||||
#include "AuthService.h"
|
||||
#include "MFAServer.h"
|
||||
#include "framework/RESTAPI_protocol.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static void FilterCredentials(SecurityObjects::UserInfo & U) {
|
||||
U.currentPassword.clear();
|
||||
U.lastPasswords.clear();
|
||||
U.oauthType.clear();
|
||||
}
|
||||
|
||||
void RESTAPI_suboauth2_handler::DoGet() {
|
||||
bool Expired = false;
|
||||
if (!IsAuthorized(Expired, true)) {
|
||||
if(Expired)
|
||||
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
|
||||
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
|
||||
}
|
||||
bool GetMe = GetBoolParameter(RESTAPI::Protocol::ME, false);
|
||||
if(GetMe) {
|
||||
Logger_.information(Poco::format("REQUEST-ME(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
|
||||
Poco::JSON::Object Me;
|
||||
SecurityObjects::UserInfo ReturnedUser = UserInfo_.userinfo;
|
||||
FilterCredentials(ReturnedUser);
|
||||
ReturnedUser.to_json(Me);
|
||||
return ReturnObject(Me);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::UnrecognizedRequest);
|
||||
}
|
||||
|
||||
void RESTAPI_suboauth2_handler::DoDelete() {
|
||||
bool Expired = false;
|
||||
if (!IsAuthorized(Expired, true)) {
|
||||
if(Expired)
|
||||
return UnAuthorized(RESTAPI::Errors::ExpiredToken,EXPIRED_TOKEN);
|
||||
return UnAuthorized(RESTAPI::Errors::MissingAuthenticationInformation);
|
||||
}
|
||||
|
||||
auto Token = GetBinding(RESTAPI::Protocol::TOKEN, "...");
|
||||
if (Token == SessionToken_) {
|
||||
AuthService()->Logout(Token);
|
||||
return ReturnStatus(Poco::Net::HTTPResponse::HTTP_NO_CONTENT, true);
|
||||
}
|
||||
|
||||
Logger_.information(Poco::format("BAD-LOGOUT(%s): Request for %s", Request->clientAddress().toString(), UserInfo_.userinfo.email));
|
||||
NotFound();
|
||||
}
|
||||
|
||||
void RESTAPI_suboauth2_handler::DoPost() {
|
||||
auto Obj = ParseStream();
|
||||
auto userId = GetS(RESTAPI::Protocol::USERID, Obj);
|
||||
auto password = GetS(RESTAPI::Protocol::PASSWORD, Obj);
|
||||
auto newPassword = GetS(RESTAPI::Protocol::NEWPASSWORD, Obj);
|
||||
|
||||
Poco::toLowerInPlace(userId);
|
||||
|
||||
if(GetBoolParameter(RESTAPI::Protocol::REQUIREMENTS, false)) {
|
||||
Logger_.information(Poco::format("POLICY-REQUEST(%s): Request.", Request->clientAddress().toString()));
|
||||
Poco::JSON::Object Answer;
|
||||
Answer.set(RESTAPI::Protocol::PASSWORDPATTERN, AuthService()->SubPasswordValidationExpression());
|
||||
Answer.set(RESTAPI::Protocol::ACCESSPOLICY, Daemon()->GetAccessPolicy());
|
||||
Answer.set(RESTAPI::Protocol::PASSWORDPOLICY, Daemon()->GetPasswordPolicy());
|
||||
return ReturnObject(Answer);
|
||||
}
|
||||
|
||||
if(GetBoolParameter(RESTAPI::Protocol::FORGOTPASSWORD,false)) {
|
||||
SecurityObjects::UserInfo UInfo1;
|
||||
auto UserExists = StorageService()->GetSubUserByEmail(userId,UInfo1);
|
||||
if(UserExists) {
|
||||
Logger_.information(Poco::format("FORGOTTEN-PASSWORD(%s): Request for %s", Request->clientAddress().toString(), userId));
|
||||
SecurityObjects::ActionLink NewLink;
|
||||
|
||||
NewLink.action = OpenWifi::SecurityObjects::LinkActions::FORGOT_PASSWORD;
|
||||
NewLink.id = MicroService::CreateUUID();
|
||||
NewLink.userId = UInfo1.Id;
|
||||
NewLink.created = std::time(nullptr);
|
||||
NewLink.expires = NewLink.created + (24*60*60);
|
||||
StorageService()->CreateAction(NewLink);
|
||||
|
||||
Poco::JSON::Object ReturnObj;
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
UInfo.webtoken.userMustChangePassword = true;
|
||||
UInfo.webtoken.to_json(ReturnObj);
|
||||
return ReturnObject(ReturnObj);
|
||||
} else {
|
||||
Poco::JSON::Object ReturnObj;
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
UInfo.webtoken.userMustChangePassword = true;
|
||||
UInfo.webtoken.to_json(ReturnObj);
|
||||
return ReturnObject(ReturnObj);
|
||||
}
|
||||
}
|
||||
|
||||
if(GetBoolParameter(RESTAPI::Protocol::RESENDMFACODE,false)) {
|
||||
Logger_.information(Poco::format("RESEND-MFA-CODE(%s): Request for %s", Request->clientAddress().toString(), userId));
|
||||
if(Obj->has("uuid")) {
|
||||
auto uuid = Obj->get("uuid").toString();
|
||||
if(MFAServer().ResendCode(uuid))
|
||||
return OK();
|
||||
}
|
||||
return UnAuthorized(RESTAPI::Errors::InvalidCredentials);
|
||||
}
|
||||
|
||||
if(GetBoolParameter(RESTAPI::Protocol::COMPLETEMFACHALLENGE,false)) {
|
||||
Logger_.information(Poco::format("COMPLETE-MFA-CHALLENGE(%s): Request for %s", Request->clientAddress().toString(), userId));
|
||||
if(Obj->has("uuid")) {
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
if(MFAServer().CompleteMFAChallenge(Obj,UInfo)) {
|
||||
Poco::JSON::Object ReturnObj;
|
||||
UInfo.webtoken.to_json(ReturnObj);
|
||||
return ReturnObject(ReturnObj);
|
||||
}
|
||||
}
|
||||
return UnAuthorized(RESTAPI::Errors::InvalidCredentials);
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfoAndPolicy UInfo;
|
||||
bool Expired=false;
|
||||
auto Code=AuthService()->AuthorizeSub(userId, password, newPassword, UInfo, Expired);
|
||||
if (Code==SUCCESS) {
|
||||
Poco::JSON::Object ReturnObj;
|
||||
if(AuthService()->RequiresMFA(UInfo)) {
|
||||
if(MFAServer().StartMFAChallenge(UInfo, ReturnObj)) {
|
||||
return ReturnObject(ReturnObj);
|
||||
}
|
||||
Logger_.warning("MFA Seems to be broken. Please fix. Disabling MFA checking for now.");
|
||||
}
|
||||
UInfo.webtoken.to_json(ReturnObj);
|
||||
return ReturnObject(ReturnObj);
|
||||
} else {
|
||||
switch(Code) {
|
||||
case INVALID_CREDENTIALS:
|
||||
return UnAuthorized(RESTAPI::Errors::InvalidCredentials, Code);
|
||||
case PASSWORD_INVALID:
|
||||
return UnAuthorized(RESTAPI::Errors::InvalidPassword, Code);
|
||||
case PASSWORD_ALREADY_USED:
|
||||
return UnAuthorized(RESTAPI::Errors::PasswordRejected, Code);
|
||||
case USERNAME_PENDING_VERIFICATION:
|
||||
return UnAuthorized(RESTAPI::Errors::UserPendingVerification, Code);
|
||||
case PASSWORD_CHANGE_REQUIRED:
|
||||
return UnAuthorized(RESTAPI::Errors::PasswordMustBeChanged, Code);
|
||||
default:
|
||||
return UnAuthorized(RESTAPI::Errors::InvalidCredentials); break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
26
src/RESTAPI/RESTAPI_suboauth2_handler.h
Normal file
26
src/RESTAPI/RESTAPI_suboauth2_handler.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_suboauth2_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_suboauth2_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal, false, false , RateLimit{.Interval=1000,.MaxCalls=10},
|
||||
false) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/suboauth2/{token}","/api/v1/suboauth2"}; };
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final;
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
239
src/RESTAPI/RESTAPI_subuser_handler.cpp
Normal file
239
src/RESTAPI/RESTAPI_subuser_handler.cpp
Normal file
@@ -0,0 +1,239 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#include "RESTAPI_subuser_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "Poco/JSON/Parser.h"
|
||||
#include "framework/RESTAPI_errors.h"
|
||||
#include "SMSSender.h"
|
||||
#include "ACLProcessor.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static void FilterCredentials(SecurityObjects::UserInfo & U) {
|
||||
U.currentPassword.clear();
|
||||
U.lastPasswords.clear();
|
||||
U.oauthType.clear();
|
||||
}
|
||||
|
||||
void RESTAPI_subuser_handler::DoGet() {
|
||||
std::string Id = GetBinding("id", "");
|
||||
if(Id.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||
}
|
||||
|
||||
Poco::toLowerInPlace(Id);
|
||||
std::string Arg;
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
if(HasParameter("byEmail",Arg) && Arg=="true") {
|
||||
if(!StorageService()->GetSubUserByEmail(Id,UInfo)) {
|
||||
return NotFound();
|
||||
}
|
||||
} else if(!StorageService()->GetSubUserById(Id,UInfo)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
Poco::JSON::Object UserInfoObject;
|
||||
FilterCredentials(UInfo);
|
||||
UInfo.to_json(UserInfoObject);
|
||||
ReturnObject(UserInfoObject);
|
||||
}
|
||||
|
||||
void RESTAPI_subuser_handler::DoDelete() {
|
||||
std::string Id = GetBinding("id", "");
|
||||
if(Id.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
if(!StorageService()->GetUserById(Id,UInfo)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if(!ACLProcessor::Can(UserInfo_.userinfo, UInfo,ACLProcessor::DELETE)) {
|
||||
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
|
||||
}
|
||||
|
||||
if(!StorageService()->DeleteSubUser(UserInfo_.userinfo.email,Id)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if(AuthService()->DeleteSubUserFromCache(UInfo.email)) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
Logger_.information(Poco::format("Remove all tokens for '%s'", UserInfo_.userinfo.email));
|
||||
StorageService()->RevokeAllSubTokens(UInfo.email);
|
||||
Logger_.information(Poco::format("User '%s' deleted by '%s'.",Id,UserInfo_.userinfo.email));
|
||||
OK();
|
||||
}
|
||||
|
||||
void RESTAPI_subuser_handler::DoPost() {
|
||||
std::string Id = GetBinding("id", "");
|
||||
if(Id!="0") {
|
||||
return BadRequest(RESTAPI::Errors::IdMustBe0);
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo NewUser;
|
||||
RESTAPI_utils::from_request(NewUser,*Request);
|
||||
|
||||
if(NewUser.userRole == SecurityObjects::UNKNOWN) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
||||
}
|
||||
|
||||
if(!ACLProcessor::Can(UserInfo_.userinfo,NewUser,ACLProcessor::CREATE)) {
|
||||
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
|
||||
}
|
||||
|
||||
Poco::toLowerInPlace(NewUser.email);
|
||||
if(!Utils::ValidEMailAddress(NewUser.email)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidEmailAddress);
|
||||
}
|
||||
|
||||
if(!NewUser.currentPassword.empty()) {
|
||||
if(!AuthService()->ValidateSubPassword(NewUser.currentPassword)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidPassword);
|
||||
}
|
||||
}
|
||||
|
||||
if(NewUser.name.empty())
|
||||
NewUser.name = NewUser.email;
|
||||
|
||||
if(!StorageService()->CreateSubUser(NewUser.email,NewUser)) {
|
||||
Logger_.information(Poco::format("Could not add user '%s'.",NewUser.email));
|
||||
return BadRequest(RESTAPI::Errors::RecordNotCreated);
|
||||
}
|
||||
|
||||
if(GetParameter("email_verification","false")=="true") {
|
||||
if(AuthService::VerifySubEmail(NewUser))
|
||||
Logger_.information(Poco::format("Verification e-mail requested for %s",NewUser.email));
|
||||
StorageService()->UpdateSubUserInfo(UserInfo_.userinfo.email,NewUser.Id,NewUser);
|
||||
}
|
||||
|
||||
if(!StorageService()->GetSubUserByEmail(NewUser.email, NewUser)) {
|
||||
Logger_.information(Poco::format("User '%s' but not retrieved.",NewUser.email));
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
Poco::JSON::Object UserInfoObject;
|
||||
FilterCredentials(NewUser);
|
||||
NewUser.to_json(UserInfoObject);
|
||||
ReturnObject(UserInfoObject);
|
||||
Logger_.information(Poco::format("User '%s' has been added by '%s')",NewUser.email, UserInfo_.userinfo.email));
|
||||
}
|
||||
|
||||
void RESTAPI_subuser_handler::DoPut() {
|
||||
std::string Id = GetBinding("id", "");
|
||||
if(Id.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::MissingUserID);
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo Existing;
|
||||
if(!StorageService()->GetSubUserById(Id,Existing)) {
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if(!ACLProcessor::Can(UserInfo_.userinfo,Existing,ACLProcessor::MODIFY)) {
|
||||
return UnAuthorized("Insufficient access rights.", ACCESS_DENIED);
|
||||
}
|
||||
|
||||
SecurityObjects::UserInfo NewUser;
|
||||
auto RawObject = ParseStream();
|
||||
if(!NewUser.from_json(RawObject)) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||
}
|
||||
|
||||
// some basic validations
|
||||
if(RawObject->has("userRole") && SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString())==SecurityObjects::UNKNOWN) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidUserRole);
|
||||
}
|
||||
|
||||
// The only valid things to change are: changePassword, name,
|
||||
AssignIfPresent(RawObject,"name", Existing.name);
|
||||
AssignIfPresent(RawObject,"description", Existing.description);
|
||||
AssignIfPresent(RawObject,"owner", Existing.owner);
|
||||
AssignIfPresent(RawObject,"location", Existing.location);
|
||||
AssignIfPresent(RawObject,"locale", Existing.locale);
|
||||
AssignIfPresent(RawObject,"changePassword", Existing.changePassword);
|
||||
AssignIfPresent(RawObject,"suspended", Existing.suspended);
|
||||
AssignIfPresent(RawObject,"blackListed", Existing.blackListed);
|
||||
|
||||
if(RawObject->has("userRole")) {
|
||||
auto NewRole = SecurityObjects::UserTypeFromString(RawObject->get("userRole").toString());
|
||||
if(NewRole!=Existing.userRole) {
|
||||
if(UserInfo_.userinfo.userRole!=SecurityObjects::ROOT && NewRole==SecurityObjects::ROOT) {
|
||||
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
|
||||
}
|
||||
if(Id==UserInfo_.userinfo.Id) {
|
||||
return UnAuthorized(RESTAPI::Errors::InsufficientAccessRights, ACCESS_DENIED);
|
||||
}
|
||||
Existing.userRole = NewRole;
|
||||
}
|
||||
}
|
||||
|
||||
if(RawObject->has("notes")) {
|
||||
SecurityObjects::NoteInfoVec NIV;
|
||||
NIV = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(RawObject->get("notes").toString());
|
||||
for(auto const &i:NIV) {
|
||||
SecurityObjects::NoteInfo ii{.created=(uint64_t)std::time(nullptr), .createdBy=UserInfo_.userinfo.email, .note=i.note};
|
||||
Existing.notes.push_back(ii);
|
||||
}
|
||||
}
|
||||
if(RawObject->has("currentPassword")) {
|
||||
if(!AuthService()->ValidateSubPassword(RawObject->get("currentPassword").toString())) {
|
||||
return BadRequest(RESTAPI::Errors::InvalidPassword);
|
||||
}
|
||||
if(!AuthService()->SetPassword(RawObject->get("currentPassword").toString(),Existing)) {
|
||||
return BadRequest(RESTAPI::Errors::PasswordRejected);
|
||||
}
|
||||
}
|
||||
|
||||
if(GetParameter("email_verification","false")=="true") {
|
||||
if(AuthService::VerifySubEmail(Existing))
|
||||
Logger_.information(Poco::format("Verification e-mail requested for %s",Existing.email));
|
||||
}
|
||||
|
||||
if(RawObject->has("userTypeProprietaryInfo")) {
|
||||
bool ChangingMFA = NewUser.userTypeProprietaryInfo.mfa.enabled && !Existing.userTypeProprietaryInfo.mfa.enabled;
|
||||
|
||||
Existing.userTypeProprietaryInfo.mfa.enabled = NewUser.userTypeProprietaryInfo.mfa.enabled;
|
||||
|
||||
auto PropInfo = RawObject->get("userTypeProprietaryInfo");
|
||||
auto PInfo = PropInfo.extract<Poco::JSON::Object::Ptr>();
|
||||
|
||||
if(PInfo->isArray("mobiles")) {
|
||||
Existing.userTypeProprietaryInfo.mobiles = NewUser.userTypeProprietaryInfo.mobiles;
|
||||
}
|
||||
|
||||
if(ChangingMFA && !NewUser.userTypeProprietaryInfo.mobiles.empty() && !SMSSender()->IsNumberValid(NewUser.userTypeProprietaryInfo.mobiles[0].number,UserInfo_.userinfo.email)){
|
||||
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
|
||||
}
|
||||
|
||||
if(NewUser.userTypeProprietaryInfo.mfa.method=="sms" && Existing.userTypeProprietaryInfo.mobiles.empty()) {
|
||||
return BadRequest(RESTAPI::Errors::NeedMobileNumber);
|
||||
}
|
||||
|
||||
if(!NewUser.userTypeProprietaryInfo.mfa.method.empty()) {
|
||||
if(NewUser.userTypeProprietaryInfo.mfa.method!="email" && NewUser.userTypeProprietaryInfo.mfa.method!="sms" ) {
|
||||
return BadRequest("Unknown MFA method");
|
||||
}
|
||||
Existing.userTypeProprietaryInfo.mfa.method=NewUser.userTypeProprietaryInfo.mfa.method;
|
||||
}
|
||||
|
||||
if(Existing.userTypeProprietaryInfo.mfa.enabled && Existing.userTypeProprietaryInfo.mfa.method.empty()) {
|
||||
return BadRequest("Illegal MFA method");
|
||||
}
|
||||
}
|
||||
|
||||
if(StorageService()->UpdateSubUserInfo(UserInfo_.userinfo.email,Id,Existing)) {
|
||||
SecurityObjects::UserInfo NewUserInfo;
|
||||
StorageService()->GetSubUserByEmail(UserInfo_.userinfo.email,NewUserInfo);
|
||||
Poco::JSON::Object ModifiedObject;
|
||||
FilterCredentials(NewUserInfo);
|
||||
NewUserInfo.to_json(ModifiedObject);
|
||||
return ReturnObject(ModifiedObject);
|
||||
}
|
||||
BadRequest(RESTAPI::Errors::RecordNotUpdated);
|
||||
}
|
||||
}
|
||||
30
src/RESTAPI/RESTAPI_subuser_handler.h
Normal file
30
src/RESTAPI/RESTAPI_subuser_handler.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_subuser_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_subuser_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_POST,
|
||||
Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_PUT,
|
||||
Poco::Net::HTTPRequest::HTTP_DELETE,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subuser/{id}"}; };
|
||||
void DoGet() final;
|
||||
void DoPost() final;
|
||||
void DoDelete() final;
|
||||
void DoPut() final;
|
||||
private:
|
||||
|
||||
};
|
||||
}
|
||||
58
src/RESTAPI/RESTAPI_subusers_handler.cpp
Normal file
58
src/RESTAPI/RESTAPI_subusers_handler.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#include "RESTAPI_subusers_handler.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/RESTAPI_protocol.h"
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_subusers_handler::DoGet() {
|
||||
std::vector<SecurityObjects::UserInfo> Users;
|
||||
bool IdOnly = (GetParameter("idOnly","false")=="true");
|
||||
|
||||
if(QB_.Select.empty()) {
|
||||
Poco::JSON::Array ArrayObj;
|
||||
Poco::JSON::Object Answer;
|
||||
if (StorageService()->GetSubUsers(QB_.Offset, QB_.Limit, Users)) {
|
||||
for (auto &i : Users) {
|
||||
Poco::JSON::Object Obj;
|
||||
if (IdOnly) {
|
||||
ArrayObj.add(i.Id);
|
||||
} else {
|
||||
i.currentPassword.clear();
|
||||
i.lastPasswords.clear();
|
||||
i.oauthType.clear();
|
||||
i.to_json(Obj);
|
||||
ArrayObj.add(Obj);
|
||||
}
|
||||
}
|
||||
Answer.set(RESTAPI::Protocol::USERS, ArrayObj);
|
||||
}
|
||||
return ReturnObject(Answer);
|
||||
} else {
|
||||
Types::StringVec IDs = Utils::Split(QB_.Select);
|
||||
Poco::JSON::Array ArrayObj;
|
||||
for(auto &i:IDs) {
|
||||
SecurityObjects::UserInfo UInfo;
|
||||
if(StorageService()->GetSubUserById(i,UInfo)) {
|
||||
Poco::JSON::Object Obj;
|
||||
if (IdOnly) {
|
||||
ArrayObj.add(UInfo.Id);
|
||||
} else {
|
||||
UInfo.currentPassword.clear();
|
||||
UInfo.lastPasswords.clear();
|
||||
UInfo.oauthType.clear();
|
||||
UInfo.to_json(Obj);
|
||||
ArrayObj.add(Obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
Poco::JSON::Object RetObj;
|
||||
RetObj.set(RESTAPI::Protocol::USERS, ArrayObj);
|
||||
return ReturnObject(RetObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
src/RESTAPI/RESTAPI_subusers_handler.h
Normal file
25
src/RESTAPI/RESTAPI_subusers_handler.h
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_subusers_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_subusers_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {}
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/subusers"}; };
|
||||
void DoGet() final;
|
||||
void DoPost() final {};
|
||||
void DoDelete() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
};
|
||||
@@ -2,12 +2,12 @@
|
||||
// Created by stephane bourque on 2021-07-01.
|
||||
//
|
||||
|
||||
#include "RESTAPI_systemEndpoints_handler.h"
|
||||
#include "RESTAPI_system_endpoints_handler.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
void RESTAPI_systemEndpoints_handler::DoGet() {
|
||||
void RESTAPI_system_endpoints_handler::DoGet() {
|
||||
auto Services = MicroService::instance().GetServices();
|
||||
SecurityObjects::SystemEndpointList L;
|
||||
for(const auto &i:Services) {
|
||||
@@ -2,15 +2,14 @@
|
||||
// Created by stephane bourque on 2021-07-01.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H
|
||||
#define UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H
|
||||
#pragma once
|
||||
|
||||
#include "../framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_systemEndpoints_handler : public RESTAPIHandler {
|
||||
class RESTAPI_system_endpoints_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_systemEndpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
RESTAPI_system_endpoints_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
@@ -23,5 +22,3 @@ namespace OpenWifi {
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRALSEC_RESTAPI_SYSTEMENDPOINTS_HANDLER_H
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by stephane bourque on 2021-06-21.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_RESTAPI_USER_HANDLER_H
|
||||
#define UCENTRALSEC_RESTAPI_USER_HANDLER_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
@@ -29,6 +28,3 @@ namespace OpenWifi {
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //UCENTRALSEC_RESTAPI_USER_HANDLER_H
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
// Created by stephane bourque on 2021-06-21.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_RESTAPI_USERS_HANDLER_H
|
||||
#define UCENTRALSEC_RESTAPI_USERS_HANDLER_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
@@ -25,5 +24,3 @@ namespace OpenWifi {
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
#endif //UCENTRALSEC_RESTAPI_USERS_HANDLER_H
|
||||
|
||||
26
src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp
Normal file
26
src/RESTAPI/RESTAPI_validate_sub_token_handler.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#include "RESTAPI_validate_sub_token_handler.h"
|
||||
#include "AuthService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_validate_sub_token_handler::DoGet() {
|
||||
Poco::URI URI(Request->getURI());
|
||||
auto Parameters = URI.getQueryParameters();
|
||||
for(auto const &i:Parameters) {
|
||||
if (i.first == "token") {
|
||||
// can we find this token?
|
||||
SecurityObjects::UserInfoAndPolicy SecObj;
|
||||
bool Expired = false;
|
||||
if (AuthService()->IsValidSubToken(i.second, SecObj.webtoken, SecObj.userinfo, Expired)) {
|
||||
Poco::JSON::Object Obj;
|
||||
SecObj.to_json(Obj);
|
||||
return ReturnObject(Obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NotFound();
|
||||
}
|
||||
}
|
||||
25
src/RESTAPI/RESTAPI_validate_sub_token_handler.h
Normal file
25
src/RESTAPI/RESTAPI_validate_sub_token_handler.h
Normal file
@@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_validate_sub_token_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_validate_sub_token_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
Poco::Net::HTTPRequest::HTTP_OPTIONS},
|
||||
Server,
|
||||
Internal) {};
|
||||
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/validateSubToken"}; };
|
||||
void DoGet() final;
|
||||
void DoPost() final {};
|
||||
void DoDelete() final {};
|
||||
void DoPut() final {};
|
||||
};
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
// Created by stephane bourque on 2021-07-01.
|
||||
//
|
||||
|
||||
#include "RESTAPI_validateToken_handler.h"
|
||||
#include "RESTAPI_validate_token_handler.h"
|
||||
#include "AuthService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
void RESTAPI_validateToken_handler::DoGet() {
|
||||
void RESTAPI_validate_token_handler::DoGet() {
|
||||
Poco::URI URI(Request->getURI());
|
||||
auto Parameters = URI.getQueryParameters();
|
||||
for(auto const &i:Parameters) {
|
||||
@@ -2,15 +2,14 @@
|
||||
// Created by stephane bourque on 2021-07-01.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H
|
||||
#define UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H
|
||||
#pragma once
|
||||
|
||||
#include "framework/MicroService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
class RESTAPI_validateToken_handler : public RESTAPIHandler {
|
||||
class RESTAPI_validate_token_handler : public RESTAPIHandler {
|
||||
public:
|
||||
RESTAPI_validateToken_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
RESTAPI_validate_token_handler(const RESTAPIHandler::BindingMap &bindings, Poco::Logger &L, RESTAPI_GenericServer &Server, bool Internal)
|
||||
: RESTAPIHandler(bindings, L,
|
||||
std::vector<std::string>
|
||||
{Poco::Net::HTTPRequest::HTTP_GET,
|
||||
@@ -25,4 +24,3 @@ namespace OpenWifi {
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRALSEC_RESTAPI_VALIDATETOKEN_HANDLER_H
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Daemon.h"
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
#include "DeviceRegistry.h"
|
||||
#include "CapabilitiesCache.h"
|
||||
#endif
|
||||
|
||||
#include "RESTAPI_GWobjects.h"
|
||||
@@ -26,7 +27,7 @@ namespace OpenWifi::GWObjects {
|
||||
void Device::to_json(Poco::JSON::Object &Obj) const {
|
||||
field_to_json(Obj,"serialNumber", SerialNumber);
|
||||
#ifdef TIP_GATEWAY_SERVICE
|
||||
field_to_json(Obj,"deviceType", Daemon::instance()->IdentifyDevice(Compatible));
|
||||
field_to_json(Obj,"deviceType", CapabilitiesCache::instance()->Get(Compatible));
|
||||
#endif
|
||||
field_to_json(Obj,"macAddress", MACAddress);
|
||||
field_to_json(Obj,"manufacturer", Manufacturer);
|
||||
|
||||
@@ -6,8 +6,7 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
#ifndef UCENTRAL_RESTAPI_OBJECTS_H
|
||||
#define UCENTRAL_RESTAPI_OBJECTS_H
|
||||
#pragma once
|
||||
|
||||
#include "Poco/JSON/Object.h"
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
@@ -111,7 +110,7 @@ namespace OpenWifi::GWObjects {
|
||||
struct DefaultConfiguration {
|
||||
std::string Name;
|
||||
std::string Configuration;
|
||||
std::string Models;
|
||||
Types::StringVec Models;
|
||||
std::string Description;
|
||||
uint64_t Created;
|
||||
uint64_t LastModified;
|
||||
@@ -191,5 +190,3 @@ namespace OpenWifi::GWObjects {
|
||||
void to_json(Poco::JSON::Object &Obj) const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif //UCENTRAL_RESTAPI_OBJECTS_H
|
||||
|
||||
@@ -6,9 +6,7 @@
|
||||
// Arilia Wireless Inc.
|
||||
//
|
||||
|
||||
|
||||
#ifndef OWPROV_RESTAPI_PROVOBJECTS_H
|
||||
#define OWPROV_RESTAPI_PROVOBJECTS_H
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "RESTAPI_SecurityObjects.h"
|
||||
@@ -380,6 +378,3 @@ namespace OpenWifi::ProvObjects {
|
||||
bool UpdateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
bool CreateObjectInfo(const Poco::JSON::Object::Ptr &O, const SecurityObjects::UserInfo &U, ObjectInfo &I);
|
||||
};
|
||||
|
||||
|
||||
#endif //OWPROV_RESTAPI_PROVOBJECTS_H
|
||||
|
||||
@@ -95,6 +95,7 @@ namespace OpenWifi {
|
||||
* All user management functions
|
||||
*/
|
||||
bool InitializeDefaultUser();
|
||||
|
||||
bool CreateUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false);
|
||||
bool GetUserByEmail(std::string & email, SecurityObjects::UserInfo & User);
|
||||
bool GetUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
|
||||
@@ -108,6 +109,19 @@ namespace OpenWifi {
|
||||
bool GetUsers( uint64_t Offset, uint64_t Limit, SecurityObjects::UserInfoVec & Users);
|
||||
bool SetLastLogin(USER_ID_TYPE & Id);
|
||||
|
||||
bool CreateSubUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready = false);
|
||||
bool GetSubUserByEmail(std::string & email, SecurityObjects::UserInfo & User);
|
||||
bool GetSubUserById(USER_ID_TYPE & Id, SecurityObjects::UserInfo & User);
|
||||
bool DeleteSubUser(const std::string & Admin, USER_ID_TYPE & Id);
|
||||
bool SetSubOwner(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Owner);
|
||||
bool SetSubLocation(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Location);
|
||||
AUTH_ERROR ChangeSubPassword(const std::string & Admin, USER_ID_TYPE & Id, const std::string &OldPassword, const std::string &NewPassword);
|
||||
bool AddSubNotes(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Notes);
|
||||
bool SetSubPolicyChange(const std::string & Admin, USER_ID_TYPE & Id, const std::string &NewPolicy);
|
||||
bool UpdateSubUserInfo(const std::string & Admin, USER_ID_TYPE & Id, SecurityObjects::UserInfo &UInfo);
|
||||
bool GetSubUsers( uint64_t Offset, uint64_t Limit, SecurityObjects::UserInfoVec & Users);
|
||||
bool SetSubLastLogin(USER_ID_TYPE & Id);
|
||||
|
||||
bool SetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name);
|
||||
bool GetAvatar(const std::string & Admin, std::string &Id, Poco::TemporaryFile &FileName, std::string &Type, std::string & Name);
|
||||
bool DeleteAvatar(const std::string & Admin, std::string &Id);
|
||||
@@ -119,6 +133,13 @@ namespace OpenWifi {
|
||||
bool RevokeAllTokens( std::string & UserName );
|
||||
bool GetToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate);
|
||||
|
||||
bool AddSubToken(std::string &UserId, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut);
|
||||
bool RevokeSubToken( std::string & Token );
|
||||
bool IsSubTokenRevoked( std::string & Token );
|
||||
bool CleanExpiredSubTokens();
|
||||
bool RevokeAllSubTokens( std::string & UserName );
|
||||
bool GetSubToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate);
|
||||
|
||||
/*
|
||||
* All ActionLinks functions
|
||||
*/
|
||||
@@ -142,6 +163,8 @@ namespace OpenWifi {
|
||||
int Create_TokensTable();
|
||||
int Create_ActionLinkTable();
|
||||
int Create_Preferences();
|
||||
int Create_SubTokensTable();
|
||||
int Create_SubscriberTable();
|
||||
|
||||
Poco::Timer Timer_;
|
||||
Archiver Archiver_;
|
||||
|
||||
@@ -1522,7 +1522,8 @@ namespace OpenWifi {
|
||||
bool Internal=false,
|
||||
bool AlwaysAuthorize=true,
|
||||
bool RateLimited=false,
|
||||
const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100})
|
||||
const RateLimit & Profile = RateLimit{.Interval=1000,.MaxCalls=100},
|
||||
bool SubscriberOnly=false)
|
||||
: Bindings_(std::move(map)),
|
||||
Logger_(l),
|
||||
Methods_(std::move(Methods)),
|
||||
@@ -1530,7 +1531,8 @@ namespace OpenWifi {
|
||||
Internal_(Internal),
|
||||
AlwaysAuthorize_(AlwaysAuthorize),
|
||||
RateLimited_(RateLimited),
|
||||
MyRates_(Profile){
|
||||
MyRates_(Profile),
|
||||
SubOnlyService_(SubscriberOnly){
|
||||
}
|
||||
|
||||
inline bool RoleIsAuthorized(const std::string & Path, const std::string & Method, std::string & Reason) {
|
||||
@@ -1551,7 +1553,7 @@ namespace OpenWifi {
|
||||
return;
|
||||
|
||||
bool Expired=false;
|
||||
if (AlwaysAuthorize_ && !IsAuthorized(Expired)) {
|
||||
if (AlwaysAuthorize_ && !IsAuthorized(Expired, SubOnlyService_)) {
|
||||
if(Expired)
|
||||
return UnAuthorized(RESTAPI::Errors::ExpiredToken, EXPIRED_TOKEN);
|
||||
return UnAuthorized(RESTAPI::Errors::InvalidCredentials, ACCESS_DENIED);
|
||||
@@ -1897,7 +1899,7 @@ namespace OpenWifi {
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool IsAuthorized(bool & Expired);
|
||||
inline bool IsAuthorized(bool & Expired, bool SubOnly = false );
|
||||
|
||||
inline void ReturnObject(Poco::JSON::Object &Object) {
|
||||
PrepareResponse();
|
||||
@@ -1980,6 +1982,7 @@ namespace OpenWifi {
|
||||
bool Internal_=false;
|
||||
bool RateLimited_=false;
|
||||
bool QueryBlockInitialized_=false;
|
||||
bool SubOnlyService_=false;
|
||||
Poco::Net::HTTPServerRequest *Request= nullptr;
|
||||
Poco::Net::HTTPServerResponse *Response= nullptr;
|
||||
bool AlwaysAuthorize_=true;
|
||||
@@ -2281,12 +2284,12 @@ namespace OpenWifi {
|
||||
return ((T.expires_in_+T.created_)<std::time(nullptr));
|
||||
}
|
||||
|
||||
inline bool RetrieveTokenInformation(const std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) {
|
||||
inline bool RetrieveTokenInformation(const std::string & SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired, bool Sub=false) {
|
||||
try {
|
||||
Types::StringPairVec QueryData;
|
||||
QueryData.push_back(std::make_pair("token",SessionToken));
|
||||
OpenAPIRequestGet Req( uSERVICE_SECURITY,
|
||||
"/api/v1/validateToken",
|
||||
Sub ? "/api/v1/validateSubToken" : "/api/v1/validateToken",
|
||||
QueryData,
|
||||
5000);
|
||||
Poco::JSON::Object::Ptr Response;
|
||||
@@ -2309,7 +2312,7 @@ namespace OpenWifi {
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired) {
|
||||
inline bool IsAuthorized(const std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired, bool Sub = false) {
|
||||
auto User = Cache_.get(SessionToken);
|
||||
if(!User.isNull()) {
|
||||
if(IsTokenExpired(User->webtoken)) {
|
||||
@@ -2320,7 +2323,7 @@ namespace OpenWifi {
|
||||
UInfo = *User;
|
||||
return true;
|
||||
}
|
||||
return RetrieveTokenInformation(SessionToken, UInfo, Expired);
|
||||
return RetrieveTokenInformation(SessionToken, UInfo, Expired, Sub);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -3707,9 +3710,9 @@ namespace OpenWifi {
|
||||
}
|
||||
|
||||
#ifdef TIP_SECURITY_SERVICE
|
||||
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired );
|
||||
[[nodiscard]] bool AuthServiceIsAuthorized(Poco::Net::HTTPServerRequest & Request,std::string &SessionToken, SecurityObjects::UserInfoAndPolicy & UInfo, bool & Expired , bool Sub );
|
||||
#endif
|
||||
inline bool RESTAPIHandler::IsAuthorized( bool & Expired ) {
|
||||
inline bool RESTAPIHandler::IsAuthorized( bool & Expired , bool Sub ) {
|
||||
if(Internal_) {
|
||||
auto Allowed = MicroService::instance().IsValidAPIKEY(*Request);
|
||||
if(!Allowed) {
|
||||
@@ -3739,9 +3742,9 @@ namespace OpenWifi {
|
||||
}
|
||||
}
|
||||
#ifdef TIP_SECURITY_SERVICE
|
||||
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, Expired)) {
|
||||
if (AuthServiceIsAuthorized(*Request, SessionToken_, UserInfo_, Expired, Sub)) {
|
||||
#else
|
||||
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired)) {
|
||||
if (AuthClient()->IsAuthorized( SessionToken_, UserInfo_, Expired, Sub)) {
|
||||
#endif
|
||||
if(Server_.LogIt(Request->getMethod(),true)) {
|
||||
Logger_.debug(Poco::format("X-REQ-ALLOWED(%s): User='%s@%s' Method='%s' Path='%s",
|
||||
|
||||
5
src/storage/storage_conversions.cpp
Normal file
5
src/storage/storage_conversions.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#include "storage_conversions.h"
|
||||
77
src/storage/storage_conversions.h
Normal file
77
src/storage/storage_conversions.h
Normal file
@@ -0,0 +1,77 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#include "framework/MicroService.h"
|
||||
#include "RESTObjects/RESTAPI_SecurityObjects.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
inline bool Convert(const UserInfoRecord &T, SecurityObjects::UserInfo &U) {
|
||||
U.Id = T.get<0>();
|
||||
U.name = T.get<1>();
|
||||
U.description = T.get<2>();
|
||||
U.avatar = T.get<3>();
|
||||
U.email = T.get<4>();
|
||||
U.validated = T.get<5>();
|
||||
U.validationEmail = T.get<6>();
|
||||
U.validationDate = T.get<7>();
|
||||
U.creationDate = T.get<8>();
|
||||
U.validationURI = T.get<9>();
|
||||
U.changePassword = T.get<10>();
|
||||
U.lastLogin = T.get<11>();
|
||||
U.currentLoginURI = T.get<12>();
|
||||
U.lastPasswordChange = T.get<13>();
|
||||
U.lastEmailCheck = T.get<14>();
|
||||
U.waitingForEmailCheck = T.get<15>();
|
||||
U.locale = T.get<16>();
|
||||
U.notes = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(T.get<17>());
|
||||
U.location = T.get<18>();
|
||||
U.owner = T.get<19>();
|
||||
U.suspended = T.get<20>();
|
||||
U.blackListed = T.get<21>();
|
||||
U.userRole = SecurityObjects::UserTypeFromString(T.get<22>());
|
||||
U.userTypeProprietaryInfo = RESTAPI_utils::to_object<SecurityObjects::UserLoginLoginExtensions>(T.get<23>());
|
||||
U.securityPolicy = T.get<24>();
|
||||
U.securityPolicyChange = T.get<25>();
|
||||
U.currentPassword = T.get<26>();
|
||||
U.lastPasswords = RESTAPI_utils::to_object_array(T.get<27>());
|
||||
U.oauthType = T.get<28>();
|
||||
U.oauthUserInfo = T.get<29>();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool Convert(const SecurityObjects::UserInfo &U, UserInfoRecord &T) {
|
||||
T.set<0>(U.Id);
|
||||
T.set<1>(U.name);
|
||||
T.set<2>(U.description);
|
||||
T.set<3>(U.avatar);
|
||||
T.set<4>(U.email);
|
||||
T.set<5>(U.validated);
|
||||
T.set<6>(U.validationEmail);
|
||||
T.set<7>(U.validationDate);
|
||||
T.set<8>(U.creationDate);
|
||||
T.set<9>(U.validationURI);
|
||||
T.set<10>(U.changePassword);
|
||||
T.set<11>(U.lastLogin);
|
||||
T.set<12>(U.currentLoginURI);
|
||||
T.set<13>(U.lastPasswordChange);
|
||||
T.set<14>(U.lastEmailCheck);
|
||||
T.set<15>(U.waitingForEmailCheck);
|
||||
T.set<16>(U.locale);
|
||||
T.set<17>(RESTAPI_utils::to_string(U.notes));
|
||||
T.set<18>(U.location);
|
||||
T.set<19>(U.owner);
|
||||
T.set<20>(U.suspended);
|
||||
T.set<21>(U.blackListed);
|
||||
T.set<22>(SecurityObjects::UserTypeToString(U.userRole));
|
||||
T.set<23>(RESTAPI_utils::to_string(U.userTypeProprietaryInfo));
|
||||
T.set<24>(U.securityPolicy);
|
||||
T.set<25>(U.securityPolicyChange);
|
||||
T.set<26>(U.currentPassword);
|
||||
T.set<27>(RESTAPI_utils::to_string(U.lastPasswords));
|
||||
T.set<28>(U.oauthType);
|
||||
T.set<29>(U.oauthUserInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
283
src/storage/storage_subscribers.cpp
Normal file
283
src/storage/storage_subscribers.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "Poco/Tuple.h"
|
||||
|
||||
#include "storage_subscribers.h"
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "storage/storage_conversions.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
bool Storage::CreateSubUser(const std::string & Admin, SecurityObjects::UserInfo & NewUser, bool PasswordHashedAlready ) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
Poco::toLowerInPlace(NewUser.email);
|
||||
|
||||
// if the user exists, must return an error
|
||||
std::string St1{"select " + AllSubUsersFieldsForSelect + " from Subscribers where email=?"};
|
||||
UserInfoRecordList Records;
|
||||
|
||||
try {
|
||||
Poco::Data::Statement Statement(Sess);
|
||||
Statement << ConvertParams(St1),
|
||||
Poco::Data::Keywords::into(Records),
|
||||
Poco::Data::Keywords::use(NewUser.email);
|
||||
Statement.execute();
|
||||
} catch (const Poco::Exception &E) {
|
||||
|
||||
}
|
||||
|
||||
if(!Records.empty())
|
||||
return false;
|
||||
|
||||
if(!PasswordHashedAlready) {
|
||||
NewUser.Id = MicroService::CreateUUID();
|
||||
NewUser.creationDate = std::time(nullptr);
|
||||
}
|
||||
|
||||
// if there is a password, we assume that we do not want email verification,
|
||||
// if there is no password, we will do email verification
|
||||
if(NewUser.currentPassword.empty()) {
|
||||
|
||||
} else {
|
||||
if(!PasswordHashedAlready) {
|
||||
NewUser.currentPassword = AuthService()->ComputeNewPasswordHash(NewUser.email,NewUser.currentPassword);
|
||||
NewUser.lastPasswords.clear();
|
||||
NewUser.lastPasswords.push_back(NewUser.currentPassword);
|
||||
NewUser.lastPasswordChange = std::time(nullptr);
|
||||
NewUser.validated = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto Notes = RESTAPI_utils::to_string(NewUser.notes);
|
||||
auto UserType = SecurityObjects::UserTypeToString(NewUser.userRole);
|
||||
auto OldPasswords = RESTAPI_utils::to_string(NewUser.lastPasswords);
|
||||
auto userTypeProprietaryInfo = RESTAPI_utils::to_string(NewUser.userTypeProprietaryInfo);
|
||||
|
||||
St1 = "INSERT INTO Subscribers (" + AllSubUsersFieldsForSelect + ") VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
|
||||
Poco::Data::Statement Statement(Sess);
|
||||
|
||||
UserInfoRecord R;
|
||||
Convert(NewUser, R);
|
||||
|
||||
Statement << ConvertParams(St1),
|
||||
Poco::Data::Keywords::use(R);
|
||||
Statement.execute();
|
||||
return true;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
std::cout << "What: " << E.what() << " name: " << E.name() << std::endl;
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetSubUserByEmail(std::string & email, SecurityObjects::UserInfo & User) {
|
||||
std::string St1;
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
Poco::toLowerInPlace(email);
|
||||
|
||||
// if the user exists, must return an error
|
||||
St1 = "select " + AllSubUsersFieldsForSelect + " from Subscribers where email=?";
|
||||
UserInfoRecordList Records;
|
||||
|
||||
Select << ConvertParams(St1) ,
|
||||
Poco::Data::Keywords::into(Records),
|
||||
Poco::Data::Keywords::use(email);
|
||||
Select.execute();
|
||||
|
||||
if(Records.empty())
|
||||
return false;
|
||||
|
||||
Convert(Records[0],User);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
std::cout << "Statement: " << St1 << std::endl;
|
||||
std::cout << "What:" << E.what() << " name: " << E.name() << std::endl;
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetSubUserById(std::string &Id, SecurityObjects::UserInfo &User) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
// if the user exists, must return an error
|
||||
std::string St1{"select " + AllSubUsersFieldsForSelect + " from Subscribers where id=?"};
|
||||
UserInfoRecordList Records;
|
||||
|
||||
Select << ConvertParams(St1) ,
|
||||
Poco::Data::Keywords::into(Records),
|
||||
Poco::Data::Keywords::use(Id);
|
||||
Select.execute();
|
||||
|
||||
if(Records.empty())
|
||||
return false;
|
||||
|
||||
Convert(Records[0],User);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetSubUsers( uint64_t Offset, uint64_t HowMany, SecurityObjects::UserInfoVec & Users) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
UserInfoRecordList Records;
|
||||
|
||||
std::string St1{"select " + AllSubUsersFieldsForSelect + " from Subscribers order by id ASC "};
|
||||
|
||||
Select << ConvertParams(St1) + ComputeRange(Offset, HowMany),
|
||||
Poco::Data::Keywords::into(Records);
|
||||
Select.execute();
|
||||
|
||||
for(const auto &R:Records) {
|
||||
SecurityObjects::UserInfo U;
|
||||
Convert(R,U);
|
||||
Users.push_back(U);
|
||||
}
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::UpdateSubUserInfo(const std::string & Admin, USER_ID_TYPE & Id, SecurityObjects::UserInfo &UInfo) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string St1{"update Subscribers set " + AllSubUsersFieldsForUpdate + " where id=?"};
|
||||
auto Notes = RESTAPI_utils::to_string(UInfo.notes);
|
||||
auto UserType = SecurityObjects::UserTypeToString(UInfo.userRole);
|
||||
auto OldPasswords = RESTAPI_utils::to_string(UInfo.lastPasswords);
|
||||
auto userTypeProprietaryInfo = RESTAPI_utils::to_string(UInfo.userTypeProprietaryInfo);
|
||||
UserInfoRecord R;
|
||||
Convert(UInfo, R);
|
||||
Update << ConvertParams(St1),
|
||||
Poco::Data::Keywords::use(R),
|
||||
Poco::Data::Keywords::use(UInfo.Id);
|
||||
Update.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
std::cout << " Exception: " << E.what() << " name: " << E.name() << std::endl;
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::DeleteSubUser(const std::string & Admin, USER_ID_TYPE & Id) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St1{"delete from Subscribers where id=?"};
|
||||
|
||||
Delete << ConvertParams(St1),
|
||||
Poco::Data::Keywords::use(Id);
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetSubOwner(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Owner) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetSubLocation(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Location) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetSubLastLogin(std::string &Id) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
std::string St1{"update Subscribers set lastLogin=? where id=?"};
|
||||
uint64_t Now=std::time(nullptr);
|
||||
Update << ConvertParams(St1),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Id);
|
||||
Update.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Storage::AUTH_ERROR Storage::ChangeSubPassword(const std::string & Admin, USER_ID_TYPE & Id, const std::string &OldPassword, const std::string &NewPassword) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
return SUCCESS;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
bool Storage::AddSubNotes(const std::string & Admin, USER_ID_TYPE & Id, const std::string &Notes) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::SetSubPolicyChange(const std::string & Admin, USER_ID_TYPE & Id, const std::string &NewPolicy) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
142
src/storage/storage_subscribers.h
Normal file
142
src/storage/storage_subscribers.h
Normal file
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Poco/Tuple.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
static const std::string AllSubUsersFieldsForCreation{
|
||||
" Id varchar(36) UNIQUE PRIMARY KEY,"
|
||||
"name varchar,"
|
||||
"description varchar,"
|
||||
"avatar varchar,"
|
||||
"email varchar,"
|
||||
"validated int,"
|
||||
"validationEmail varchar,"
|
||||
"validationDate bigint,"
|
||||
"creationDate bigint,"
|
||||
"validationURI varchar,"
|
||||
"changePassword int,"
|
||||
"lastLogin bigint,"
|
||||
"currentLoginURI varchar,"
|
||||
"lastPasswordChange bigint,"
|
||||
"lastEmailCheck bigint,"
|
||||
"waitingForEmailCheck int,"
|
||||
"locale varchar,"
|
||||
"notes text,"
|
||||
"location varchar,"
|
||||
"owner varchar,"
|
||||
"suspended int,"
|
||||
"blackListed int,"
|
||||
"userRole varchar,"
|
||||
"userTypeProprietaryInfo text,"
|
||||
"securityPolicy text,"
|
||||
"securityPolicyChange bigint,"
|
||||
"currentPassword varchar,"
|
||||
"lastPasswords varchar,"
|
||||
"oauthType varchar,"
|
||||
"oauthUserInfo text"};
|
||||
|
||||
static const std::string AllSubUsersFieldsForSelect{
|
||||
"Id,"
|
||||
"name,"
|
||||
"description,"
|
||||
"avatar,"
|
||||
"email,"
|
||||
"validated,"
|
||||
"validationEmail,"
|
||||
"validationDate,"
|
||||
"creationDate,"
|
||||
"validationURI,"
|
||||
"changePassword,"
|
||||
"lastLogin,"
|
||||
"currentLoginURI,"
|
||||
"lastPasswordChange,"
|
||||
"lastEmailCheck,"
|
||||
"waitingForEmailCheck,"
|
||||
"locale,"
|
||||
"notes,"
|
||||
"location,"
|
||||
"owner,"
|
||||
"suspended,"
|
||||
"blackListed,"
|
||||
"userRole,"
|
||||
"userTypeProprietaryInfo,"
|
||||
"securityPolicy,"
|
||||
"securityPolicyChange,"
|
||||
"currentPassword,"
|
||||
"lastPasswords,"
|
||||
"oauthType,"
|
||||
"oauthUserInfo"};
|
||||
|
||||
static const std::string AllSubUsersFieldsForUpdate{
|
||||
" Id=?, "
|
||||
"name=?, "
|
||||
"description=?, "
|
||||
"avatar=?, "
|
||||
"email=?, "
|
||||
"validated=?, "
|
||||
"validationEmail=?, "
|
||||
"validationDate=?, "
|
||||
"creationDate=?, "
|
||||
"validationURI=?, "
|
||||
"changePassword=?, "
|
||||
"lastLogin=?, "
|
||||
"currentLoginURI=?, "
|
||||
"lastPasswordChange=?, "
|
||||
"lastEmailCheck=?, "
|
||||
"waitingForEmailCheck=?, "
|
||||
"locale=?, "
|
||||
"notes=?, "
|
||||
"location=?, "
|
||||
"owner=?, "
|
||||
"suspended=?, "
|
||||
"blackListed=?, "
|
||||
"userRole=?, "
|
||||
"userTypeProprietaryInfo=?, "
|
||||
"securityPolicy=?, "
|
||||
"securityPolicyChange=?, "
|
||||
"currentPassword=?, "
|
||||
"lastPasswords=?, "
|
||||
"oauthType=?, "
|
||||
"oauthUserInfo=? "};
|
||||
|
||||
typedef Poco::Tuple <
|
||||
std::string, // Id = 0;
|
||||
std::string, // name;
|
||||
std::string, // description;
|
||||
std::string, // avatar;
|
||||
std::string, // email;
|
||||
uint64_t, // bool validated = false;
|
||||
std::string, // validationEmail;
|
||||
uint64_t, // validationDate = 0;
|
||||
uint64_t, // creationDate = 0;
|
||||
std::string, // validationURI;
|
||||
uint64_t, // bool changePassword = true;
|
||||
uint64_t, // lastLogin = 0;
|
||||
std::string, // currentLoginURI;
|
||||
uint64_t, // lastPasswordChange = 0;
|
||||
uint64_t, // lastEmailCheck = 0;
|
||||
uint64_t, // bool waitingForEmailCheck = false;
|
||||
std::string, // locale;
|
||||
std::string, // notes;
|
||||
std::string, // location;
|
||||
std::string, // owner;
|
||||
uint64_t, // bool suspended = false;
|
||||
uint64_t, // bool blackListed = false;
|
||||
std::string, // userRole;
|
||||
std::string, // userTypeProprietaryInfo;
|
||||
std::string, // securityPolicy;
|
||||
uint64_t, // securityPolicyChange;
|
||||
std::string, // currentPassword;
|
||||
std::string, // lastPasswords;
|
||||
std::string, // oauthType;
|
||||
std::string // oauthUserInfo;
|
||||
> UserInfoRecord;
|
||||
|
||||
typedef std::vector <UserInfoRecord> UserInfoRecordList;
|
||||
}
|
||||
150
src/storage/storage_subtokens.cpp
Normal file
150
src/storage/storage_subtokens.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#include "storage/storage_subtokens.h"
|
||||
#include "StorageService.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
/*
|
||||
"Token TEXT PRIMARY KEY, "
|
||||
"RefreshToken TEXT, "
|
||||
"TokenType TEXT, "
|
||||
"UserName TEXT, "
|
||||
"Created BIGINT, "
|
||||
"Expires BIGINT, "
|
||||
"IdleTimeOut BIGINT, "
|
||||
"RevocationDate BIGINT "
|
||||
*/
|
||||
|
||||
bool Storage::AddSubToken(std::string &UserID, std::string &Token, std::string &RefreshToken, std::string & TokenType, uint64_t Expires, uint64_t TimeOut) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Insert(Sess);
|
||||
uint64_t Now = std::time(nullptr);
|
||||
uint64_t Z = 0;
|
||||
|
||||
std::string St2{
|
||||
"INSERT INTO SubTokens (" + AllSubTokensFieldsForSelect + ") VALUES(" + AllSubTokensValuesForSelect + ")"};
|
||||
|
||||
Insert << ConvertParams(St2),
|
||||
Poco::Data::Keywords::use(Token),
|
||||
Poco::Data::Keywords::use(RefreshToken),
|
||||
Poco::Data::Keywords::use(TokenType),
|
||||
Poco::Data::Keywords::use(UserID),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Expires),
|
||||
Poco::Data::Keywords::use(TimeOut),
|
||||
Poco::Data::Keywords::use(Z);
|
||||
Insert.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::GetSubToken(std::string &Token, SecurityObjects::UserInfoAndPolicy &UInfo, uint64_t &RevocationDate) {
|
||||
try {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
RevocationDate = 0 ;
|
||||
std::string St2{"SELECT " + AllSubTokensFieldsForSelect + " From SubTokens WHERE Token=?"};
|
||||
Select << ConvertParams(St2),
|
||||
Poco::Data::Keywords::into(UInfo.webtoken.access_token_),
|
||||
Poco::Data::Keywords::into(UInfo.webtoken.refresh_token_),
|
||||
Poco::Data::Keywords::into(UInfo.webtoken.token_type_),
|
||||
Poco::Data::Keywords::into(UInfo.userinfo.Id),
|
||||
Poco::Data::Keywords::into(UInfo.webtoken.created_),
|
||||
Poco::Data::Keywords::into(UInfo.webtoken.expires_in_),
|
||||
Poco::Data::Keywords::into(UInfo.webtoken.idle_timeout_),
|
||||
Poco::Data::Keywords::into(RevocationDate),
|
||||
Poco::Data::Keywords::use(Token);
|
||||
Select.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::IsSubTokenRevoked(std::string &Token) {
|
||||
try {
|
||||
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Select(Sess);
|
||||
|
||||
uint32_t RevocationDate = 0 ;
|
||||
|
||||
std::string St2{"SELECT RevocationDate From SubTokens WHERE Token=?"};
|
||||
Select << ConvertParams(St2),
|
||||
Poco::Data::Keywords::into(RevocationDate),
|
||||
Poco::Data::Keywords::use(Token);
|
||||
Select.execute();
|
||||
|
||||
if(Select.columnsExtracted()==0)
|
||||
return false;
|
||||
return RevocationDate>0 ;
|
||||
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::RevokeSubToken(std::string &Token) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Update(Sess);
|
||||
|
||||
uint64_t Now = std::time(nullptr);
|
||||
|
||||
// update users set lastLogin=? where id=?
|
||||
std::string St2{"UPDATE SubTokens Set RevocationDate=? WHERE Token=?"};
|
||||
Update << ConvertParams(St2),
|
||||
Poco::Data::Keywords::use(Now),
|
||||
Poco::Data::Keywords::use(Token);
|
||||
Update.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::CleanExpiredSubTokens() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
uint64_t Now = std::time(nullptr);
|
||||
|
||||
std::string St2{"DELETE From SubTokens WHERE (Created+Expires) <= ?"};
|
||||
Delete << ConvertParams(St2),
|
||||
Poco::Data::Keywords::use(Now);
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Storage::RevokeAllSubTokens(std::string & UserId) {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Poco::Data::Statement Delete(Sess);
|
||||
|
||||
std::string St2{"DELETE SubFrom Tokens WHERE Username=?"};
|
||||
Delete << ConvertParams(St2),
|
||||
Poco::Data::Keywords::use(UserId);
|
||||
Delete.execute();
|
||||
return true;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
27
src/storage/storage_subtokens.h
Normal file
27
src/storage/storage_subtokens.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by stephane bourque on 2021-11-30.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Poco/Tuple.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
static std::string AllSubTokensFieldsForCreation{ "Token TEXT PRIMARY KEY, "
|
||||
"RefreshToken TEXT, "
|
||||
"TokenType TEXT, "
|
||||
"UserName TEXT, "
|
||||
"Created BIGINT, "
|
||||
"Expires BIGINT, "
|
||||
"IdleTimeOut BIGINT, "
|
||||
"RevocationDate BIGINT "
|
||||
};
|
||||
static std::string AllSubTokensFieldsForSelect {"Token, RefreshToken, TokenType, Username, Created, Expires, IdleTimeOut, RevocationDate"};
|
||||
static std::string AllSubTokensValuesForSelect{"?,?,?,?,?,?,?,?"};
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -17,6 +17,8 @@ namespace OpenWifi {
|
||||
Create_TokensTable();
|
||||
Create_ActionLinkTable();
|
||||
Create_Preferences();
|
||||
Create_SubTokensTable();
|
||||
Create_SubscriberTable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -45,6 +47,31 @@ namespace OpenWifi {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Storage::Create_SubscriberTable() {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
try {
|
||||
if (dbType_ == mysql) {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS Subscribers (" +
|
||||
AllUsersFieldsForCreation +
|
||||
" ,INDEX emailindex (email ASC)"
|
||||
" ,INDEX nameindex (name ASC))",
|
||||
Poco::Data::Keywords::now;
|
||||
} else {
|
||||
Sess << "CREATE TABLE IF NOT EXISTS Subscribers (" +
|
||||
AllUsersFieldsForCreation +
|
||||
")",
|
||||
Poco::Data::Keywords::now;
|
||||
Sess << "CREATE INDEX IF NOT EXISTS emailindex ON Subscribers (email ASC)", Poco::Data::Keywords::now;
|
||||
Sess << "CREATE INDEX IF NOT EXISTS nameindex ON Subscribers (name ASC)", Poco::Data::Keywords::now;
|
||||
}
|
||||
return 0;
|
||||
} catch (const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Storage::Create_ActionLinkTable() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
@@ -93,6 +120,19 @@ namespace OpenWifi {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Storage::Create_SubTokensTable() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
Sess << "CREATE TABLE IF NOT EXISTS SubTokens (" +
|
||||
AllTokensFieldsForCreation +
|
||||
") ", Poco::Data::Keywords::now;
|
||||
return 0;
|
||||
} catch(const Poco::Exception &E) {
|
||||
Logger_.log(E);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Storage::Create_Preferences() {
|
||||
try {
|
||||
Poco::Data::Session Sess = Pool_->get();
|
||||
|
||||
@@ -9,77 +9,10 @@
|
||||
|
||||
#include "StorageService.h"
|
||||
#include "framework/MicroService.h"
|
||||
#include "storage/storage_conversions.h"
|
||||
|
||||
namespace OpenWifi {
|
||||
|
||||
bool Convert(const UserInfoRecord &T, SecurityObjects::UserInfo &U) {
|
||||
U.Id = T.get<0>();
|
||||
U.name = T.get<1>();
|
||||
U.description = T.get<2>();
|
||||
U.avatar = T.get<3>();
|
||||
U.email = T.get<4>();
|
||||
U.validated = T.get<5>();
|
||||
U.validationEmail = T.get<6>();
|
||||
U.validationDate = T.get<7>();
|
||||
U.creationDate = T.get<8>();
|
||||
U.validationURI = T.get<9>();
|
||||
U.changePassword = T.get<10>();
|
||||
U.lastLogin = T.get<11>();
|
||||
U.currentLoginURI = T.get<12>();
|
||||
U.lastPasswordChange = T.get<13>();
|
||||
U.lastEmailCheck = T.get<14>();
|
||||
U.waitingForEmailCheck = T.get<15>();
|
||||
U.locale = T.get<16>();
|
||||
U.notes = RESTAPI_utils::to_object_array<SecurityObjects::NoteInfo>(T.get<17>());
|
||||
U.location = T.get<18>();
|
||||
U.owner = T.get<19>();
|
||||
U.suspended = T.get<20>();
|
||||
U.blackListed = T.get<21>();
|
||||
U.userRole = SecurityObjects::UserTypeFromString(T.get<22>());
|
||||
U.userTypeProprietaryInfo = RESTAPI_utils::to_object<SecurityObjects::UserLoginLoginExtensions>(T.get<23>());
|
||||
U.securityPolicy = T.get<24>();
|
||||
U.securityPolicyChange = T.get<25>();
|
||||
U.currentPassword = T.get<26>();
|
||||
U.lastPasswords = RESTAPI_utils::to_object_array(T.get<27>());
|
||||
U.oauthType = T.get<28>();
|
||||
U.oauthUserInfo = T.get<29>();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Convert(const SecurityObjects::UserInfo &U, UserInfoRecord &T) {
|
||||
T.set<0>(U.Id);
|
||||
T.set<1>(U.name);
|
||||
T.set<2>(U.description);
|
||||
T.set<3>(U.avatar);
|
||||
T.set<4>(U.email);
|
||||
T.set<5>(U.validated);
|
||||
T.set<6>(U.validationEmail);
|
||||
T.set<7>(U.validationDate);
|
||||
T.set<8>(U.creationDate);
|
||||
T.set<9>(U.validationURI);
|
||||
T.set<10>(U.changePassword);
|
||||
T.set<11>(U.lastLogin);
|
||||
T.set<12>(U.currentLoginURI);
|
||||
T.set<13>(U.lastPasswordChange);
|
||||
T.set<14>(U.lastEmailCheck);
|
||||
T.set<15>(U.waitingForEmailCheck);
|
||||
T.set<16>(U.locale);
|
||||
T.set<17>(RESTAPI_utils::to_string(U.notes));
|
||||
T.set<18>(U.location);
|
||||
T.set<19>(U.owner);
|
||||
T.set<20>(U.suspended);
|
||||
T.set<21>(U.blackListed);
|
||||
T.set<22>(SecurityObjects::UserTypeToString(U.userRole));
|
||||
T.set<23>(RESTAPI_utils::to_string(U.userTypeProprietaryInfo));
|
||||
T.set<24>(U.securityPolicy);
|
||||
T.set<25>(U.securityPolicyChange);
|
||||
T.set<26>(U.currentPassword);
|
||||
T.set<27>(RESTAPI_utils::to_string(U.lastPasswords));
|
||||
T.set<28>(U.oauthType);
|
||||
T.set<29>(U.oauthUserInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string OldDefaultUseridStockUUID{"DEFAULT-USER-UUID-SHOULD-BE-DELETED!!!"};
|
||||
std::string NewDefaultUseridStockUUID{"11111111-0000-0000-6666-999999999999"};
|
||||
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
// Created by stephane bourque on 2021-07-15.
|
||||
//
|
||||
|
||||
#ifndef UCENTRALSEC_STORAGE_USERS_H
|
||||
#define UCENTRALSEC_STORAGE_USERS_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#pragma once
|
||||
|
||||
namespace OpenWifi {
|
||||
static const std::string AllUsersFieldsForCreation{
|
||||
@@ -140,4 +136,3 @@ namespace OpenWifi {
|
||||
typedef std::vector <UserInfoRecord> UserInfoRecordList;
|
||||
}
|
||||
|
||||
#endif //UCENTRALSEC_STORAGE_USERS_H
|
||||
|
||||
Reference in New Issue
Block a user