mirror of
https://github.com/Telecominfraproject/wlan-cloud-ucentralsec.git
synced 2025-11-02 11:47:56 +00:00
Completing sub mfa support.
This commit is contained in:
@@ -98,7 +98,7 @@ add_executable( owsec
|
|||||||
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
|
src/SMS_provider_twilio.cpp src/SMS_provider_twilio.h
|
||||||
src/ActionLinkManager.cpp src/ActionLinkManager.h
|
src/ActionLinkManager.cpp src/ActionLinkManager.h
|
||||||
src/ACLProcessor.h src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h
|
src/ACLProcessor.h src/RESTAPI/RESTAPI_preferences.cpp src/RESTAPI/RESTAPI_preferences.h
|
||||||
src/framework/OpenWifiTypes.h)
|
src/framework/OpenWifiTypes.h src/RESTAPI/RESTAPI_submfa_handler.cpp src/RESTAPI/RESTAPI_submfa_handler.h)
|
||||||
|
|
||||||
if(NOT SMALL_BUILD)
|
if(NOT SMALL_BUILD)
|
||||||
target_link_libraries(owsec PUBLIC
|
target_link_libraries(owsec PUBLIC
|
||||||
|
|||||||
@@ -405,6 +405,24 @@ components:
|
|||||||
answer:
|
answer:
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
SubMfaConfig:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
type:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- disabled
|
||||||
|
- sms
|
||||||
|
- email
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
sms:
|
||||||
|
type: string
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
##
|
##
|
||||||
## These are endpoints that all services in the uCentral stack must provide
|
## These are endpoints that all services in the uCentral stack must provide
|
||||||
@@ -735,7 +753,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Authentication
|
- Authentication
|
||||||
summary: Get access token - to be used as Bearer token header for all other API requests.
|
summary: Get access token - to be used as Bearer token header for all other API requests.
|
||||||
operationId: getAccessToken
|
operationId: getSubAccessToken
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: newPassword
|
name: newPassword
|
||||||
@@ -818,7 +836,7 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Authentication
|
- Authentication
|
||||||
summary: Revoke a token.
|
summary: Revoke a token.
|
||||||
operationId: removeAccessToken
|
operationId: removeSubAccessToken
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: token
|
name: token
|
||||||
@@ -905,9 +923,9 @@ paths:
|
|||||||
/subusers:
|
/subusers:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- User Management
|
- Subscribers
|
||||||
summary: Retrieve a list of existing users as well as some information about them.
|
summary: Retrieve a list of existing users as well as some information about them.
|
||||||
operationId: getUsers
|
operationId: getSubUsers
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: offset
|
name: offset
|
||||||
@@ -1055,8 +1073,8 @@ paths:
|
|||||||
/subuser/{id}:
|
/subuser/{id}:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- User Management
|
- Subscribers
|
||||||
operationId: getUser
|
operationId: getSubUser
|
||||||
summary: Retrieve the information for a single user.
|
summary: Retrieve the information for a single user.
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
@@ -1075,8 +1093,8 @@ paths:
|
|||||||
|
|
||||||
delete:
|
delete:
|
||||||
tags:
|
tags:
|
||||||
- User Management
|
- Subscribers
|
||||||
operationId: deleteUser
|
operationId: deleteSubUser
|
||||||
summary: Delete a single user.
|
summary: Delete a single user.
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
@@ -1095,8 +1113,8 @@ paths:
|
|||||||
|
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- User Management
|
- Subscribers
|
||||||
operationId: createUser
|
operationId: createSubUser
|
||||||
summary: Create a single user.
|
summary: Create a single user.
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
@@ -1127,8 +1145,8 @@ paths:
|
|||||||
|
|
||||||
put:
|
put:
|
||||||
tags:
|
tags:
|
||||||
- User Management
|
- Subscribers
|
||||||
operationId: updateUser
|
operationId: updateSubUser
|
||||||
summary: Modify a single user.
|
summary: Modify a single user.
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
@@ -1354,6 +1372,49 @@ paths:
|
|||||||
400:
|
400:
|
||||||
$ref: '#/components/responses/BadRequest'
|
$ref: '#/components/responses/BadRequest'
|
||||||
|
|
||||||
|
/submfa:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- MFA
|
||||||
|
summary: Retrieve the cyrrent setting for MFA
|
||||||
|
operationId: getMFS
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
$ref: '#/components/schemas/SubMfaConfig'
|
||||||
|
|
||||||
|
put:
|
||||||
|
tags:
|
||||||
|
- MFA
|
||||||
|
summary: Retrieve the cyrrent setting for MFA
|
||||||
|
operationId: modifyMFS
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: startValidation
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
- in: query
|
||||||
|
name: completeValidation
|
||||||
|
schema:
|
||||||
|
type: boolean
|
||||||
|
required: false
|
||||||
|
- in: query
|
||||||
|
name: challengeCode
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
required: false
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SubMfaConfig'
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
$ref: '#/components/schemas/SubMfaConfig'
|
||||||
|
400:
|
||||||
|
$ref: '#/components/responses/BadRequest'
|
||||||
|
|
||||||
|
|
||||||
#########################################################################################
|
#########################################################################################
|
||||||
##
|
##
|
||||||
## These are endpoints that all services in the uCentral stack must provide
|
## These are endpoints that all services in the uCentral stack must provide
|
||||||
@@ -1433,8 +1494,9 @@ paths:
|
|||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Security
|
- Security
|
||||||
|
- Subscribers
|
||||||
summary: Allows any microservice to validate a token and get security policy for a specific user.
|
summary: Allows any microservice to validate a token and get security policy for a specific user.
|
||||||
operationId: validateToken
|
operationId: validateSubToken
|
||||||
parameters:
|
parameters:
|
||||||
- in: query
|
- in: query
|
||||||
name: token
|
name: token
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "RESTAPI/RESTAPI_subuser_handler.h"
|
#include "RESTAPI/RESTAPI_subuser_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_subusers_handler.h"
|
#include "RESTAPI/RESTAPI_subusers_handler.h"
|
||||||
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
|
#include "RESTAPI/RESTAPI_validate_sub_token_handler.h"
|
||||||
|
#include "RESTAPI/RESTAPI_submfa_handler.h"
|
||||||
|
|
||||||
namespace OpenWifi {
|
namespace OpenWifi {
|
||||||
|
|
||||||
@@ -55,7 +56,8 @@ namespace OpenWifi {
|
|||||||
RESTAPI_suboauth2_handler,
|
RESTAPI_suboauth2_handler,
|
||||||
RESTAPI_subuser_handler,
|
RESTAPI_subuser_handler,
|
||||||
RESTAPI_suboauth2_handler,
|
RESTAPI_suboauth2_handler,
|
||||||
RESTAPI_subusers_handler
|
RESTAPI_subusers_handler,
|
||||||
|
RESTAPI_submfa_handler
|
||||||
>(Path, Bindings, L, S);
|
>(Path, Bindings, L, S);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
106
src/RESTAPI/RESTAPI_submfa_handler.cpp
Normal file
106
src/RESTAPI/RESTAPI_submfa_handler.cpp
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "RESTAPI_submfa_handler.h"
|
||||||
|
#include "StorageService.h"
|
||||||
|
#include "SMSSender.h"
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
|
||||||
|
void RESTAPI_submfa_handler::DoGet() {
|
||||||
|
SecurityObjects::UserInfo User;
|
||||||
|
|
||||||
|
if (StorageService()->GetUserById(UserInfo_.userinfo.Id,User)) {
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
SecurityObjects::SubMfaConfig MFC;
|
||||||
|
|
||||||
|
MFC.id = User.Id;
|
||||||
|
if(User.userTypeProprietaryInfo.mfa.enabled) {
|
||||||
|
if(User.userTypeProprietaryInfo.mfa.method == "sms") {
|
||||||
|
MFC.sms = User.userTypeProprietaryInfo.mobiles[0].number;
|
||||||
|
} else if(User.userTypeProprietaryInfo.mfa.method == "email") {
|
||||||
|
MFC.email = User.email;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MFC.type = "disabled";
|
||||||
|
}
|
||||||
|
MFC.to_json(Answer);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
}
|
||||||
|
NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RESTAPI_submfa_handler::DoPut() {
|
||||||
|
auto Body = ParseStream();
|
||||||
|
SecurityObjects::SubMfaConfig MFC;
|
||||||
|
|
||||||
|
if(!MFC.from_json(Body)) {
|
||||||
|
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(MFC.type=="disabled") {
|
||||||
|
SecurityObjects::UserInfo User;
|
||||||
|
StorageService()->GetUserById(UserInfo_.userinfo.Id,User);
|
||||||
|
User.userTypeProprietaryInfo.mfa.enabled = false;
|
||||||
|
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UserInfo_.userinfo.Id,User);
|
||||||
|
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
MFC.to_json(Answer);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
} else if (MFC.type=="email") {
|
||||||
|
SecurityObjects::UserInfo User;
|
||||||
|
|
||||||
|
StorageService()->GetUserById(UserInfo_.userinfo.Id,User);
|
||||||
|
User.userTypeProprietaryInfo.mfa.enabled = true;
|
||||||
|
User.userTypeProprietaryInfo.mfa.method = "email";
|
||||||
|
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UserInfo_.userinfo.Id,User);
|
||||||
|
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
MFC.to_json(Answer);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
} else if (MFC.type=="sms") {
|
||||||
|
if(GetBoolParameter("startValidation",false)) {
|
||||||
|
if(MFC.sms.empty()) {
|
||||||
|
return BadRequest("Missing phone number");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SMSSender()->StartValidation(MFC.sms, UserInfo_.userinfo.email)) {
|
||||||
|
return OK();
|
||||||
|
} else {
|
||||||
|
return InternalError("SMS could not be sent. Verify the number or try again later.");
|
||||||
|
}
|
||||||
|
} else if(GetBoolParameter("completeValidation",false)) {
|
||||||
|
auto ChallengeCode = GetParameter("challengeCode","");
|
||||||
|
if(ChallengeCode.empty()) {
|
||||||
|
return BadRequest("Missing 'challengeCode'");
|
||||||
|
}
|
||||||
|
if(MFC.sms.empty()) {
|
||||||
|
return BadRequest("Missing phone number");
|
||||||
|
}
|
||||||
|
if(SMSSender()->CompleteValidation(MFC.sms, ChallengeCode, UserInfo_.userinfo.email)) {
|
||||||
|
SecurityObjects::UserInfo User;
|
||||||
|
|
||||||
|
StorageService()->GetUserById(UserInfo_.userinfo.Id,User);
|
||||||
|
User.userTypeProprietaryInfo.mfa.method = "sms";
|
||||||
|
SecurityObjects::MobilePhoneNumber PhoneNumber;
|
||||||
|
PhoneNumber.number = MFC.sms;
|
||||||
|
PhoneNumber.primary = true;
|
||||||
|
PhoneNumber.verified = true;
|
||||||
|
User.userTypeProprietaryInfo.mfa.enabled = true;
|
||||||
|
User.userTypeProprietaryInfo.mobiles.clear();
|
||||||
|
User.userTypeProprietaryInfo.mobiles.push_back(PhoneNumber);
|
||||||
|
StorageService()->UpdateUserInfo(UserInfo_.userinfo.email,UserInfo_.userinfo.Id,User);
|
||||||
|
|
||||||
|
Poco::JSON::Object Answer;
|
||||||
|
MFC.to_json(Answer);
|
||||||
|
return ReturnObject(Answer);
|
||||||
|
} else {
|
||||||
|
return InternalError("SMS could not be sent. Verify the number or try again later.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
27
src/RESTAPI/RESTAPI_submfa_handler.h
Normal file
27
src/RESTAPI/RESTAPI_submfa_handler.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// Created by stephane bourque on 2021-12-01.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "framework/MicroService.h"
|
||||||
|
|
||||||
|
namespace OpenWifi {
|
||||||
|
class RESTAPI_submfa_handler : public RESTAPIHandler {
|
||||||
|
public:
|
||||||
|
RESTAPI_submfa_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},
|
||||||
|
true) {}
|
||||||
|
static const std::list<const char *> PathName() { return std::list<const char *>{"/api/v1/submfa"}; };
|
||||||
|
void DoGet() final;
|
||||||
|
void DoPost() final {};
|
||||||
|
void DoDelete() final {};
|
||||||
|
void DoPut() final ;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -531,5 +531,26 @@ namespace OpenWifi::SecurityObjects {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SubMfaConfig::to_json(Poco::JSON::Object &Obj) const {
|
||||||
|
field_to_json(Obj,"id",id);
|
||||||
|
field_to_json(Obj,"type",type);
|
||||||
|
field_to_json(Obj,"sms",sms);
|
||||||
|
field_to_json(Obj,"email",email);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SubMfaConfig::from_json(Poco::JSON::Object::Ptr &Obj) {
|
||||||
|
try {
|
||||||
|
field_from_json(Obj,"id",id);
|
||||||
|
field_from_json(Obj,"type",type);
|
||||||
|
field_from_json(Obj,"sms",sms);
|
||||||
|
field_from_json(Obj,"email",email);
|
||||||
|
return true;
|
||||||
|
} catch(...) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -253,4 +253,15 @@ namespace OpenWifi::SecurityObjects {
|
|||||||
void to_json(Poco::JSON::Object &Obj) const;
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
bool from_json(Poco::JSON::Object::Ptr &Obj);
|
bool from_json(Poco::JSON::Object::Ptr &Obj);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SubMfaConfig {
|
||||||
|
std::string id;
|
||||||
|
std::string type;
|
||||||
|
std::string sms;
|
||||||
|
std::string email;
|
||||||
|
|
||||||
|
void to_json(Poco::JSON::Object &Obj) const;
|
||||||
|
bool from_json(Poco::JSON::Object::Ptr &Obj);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user