Skip to content

Commit

Permalink
https://telecominfraproject.atlassian.net/browse/WIFI-7831
Browse files Browse the repository at this point in the history
Signed-off-by: stephb9959 <[email protected]>
  • Loading branch information
stephb9959 committed Sep 29, 2023
1 parent 26a1d5d commit 9ea65eb
Show file tree
Hide file tree
Showing 10 changed files with 388 additions and 181 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ add_executable(owprov
src/RESTAPI/RESTAPI_radiusendpoint_list_handler.h
src/RESTAPI/RESTAPI_radius_endpoint_handler.cpp
src/RESTAPI/RESTAPI_radius_endpoint_handler.h
src/OrionWifi.h
)

target_link_libraries(owprov PUBLIC
Expand Down
2 changes: 1 addition & 1 deletion build
Original file line number Diff line number Diff line change
@@ -1 +1 @@
44
46
293 changes: 151 additions & 142 deletions src/OpenRoamin_GlobalReach.cpp

Large diffs are not rendered by default.

65 changes: 37 additions & 28 deletions src/OpenRoamin_GlobalReach.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,43 @@

namespace OpenWifi {

class OpenRoaming_GlobalReach : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new OpenRoaming_GlobalReach;
return instance_;
}

int Start() override;
void Stop() override;
bool CreateRADSECCertificate(const std::string &AccountName,
const std::string &Name,
const std::string &CSR,
ProvObjects::GLBLRCertificateInfo &NewCertificate);
bool GetRADSECCertificate(const std::string &AccountName, std::string & CertificateId, ProvObjects::GLBLRCertificateInfo &NewCertificate);
bool VerifyAccount(const std::string &GlobalReachAccountId, const std::string &PrivateKey, std::string &Name);
void InitCache();

private:
std::string MakeToken(const std::string &GlobalReachAccountId, const std::string &PrivateKey="");

std::map<std::string,std::pair<std::string,Poco::SharedPtr<Poco::Crypto::ECKey>>> PrivateKeys_;

OpenRoaming_GlobalReach() noexcept
: SubSystemServer("OpenRoaming_GlobalReach", "GLBL-REACH", "globalreach") {
}
};

inline auto OpenRoaming_GlobalReach() { return OpenRoaming_GlobalReach::instance(); }
namespace GlobalReach {
class OpenRoaming : public SubSystemServer {
public:
static auto instance() {
static auto instance_ = new OpenRoaming;
return instance_;
}

int Start() override;

void Stop() override;

bool CreateRADSECCertificate(const std::string &AccountName,
const std::string &Name,
const std::string &CSR,
ProvObjects::GLBLRCertificateInfo &NewCertificate);

bool GetRADSECCertificate(const std::string &AccountName, std::string &CertificateId,
ProvObjects::GLBLRCertificateInfo &NewCertificate);

bool
VerifyAccount(const std::string &GlobalReachAccountId, const std::string &PrivateKey, std::string &Name);

void InitCache();

private:
std::string MakeToken(const std::string &GlobalReachAccountId, const std::string &PrivateKey = "");

std::map<std::string, std::pair<std::string, Poco::SharedPtr<Poco::Crypto::ECKey>>> PrivateKeys_;

OpenRoaming() noexcept
: SubSystemServer("OpenRoaming_GlobalReach", "GLBL-REACH", "globalreach") {
}
};
}

inline auto OpenRoaming_GlobalReach() { return GlobalReach::OpenRoaming::instance(); }

} // OpenWifi

19 changes: 19 additions & 0 deletions src/OrionWifi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// Created by stephane bourque on 2023-09-28.
//

#pragma once

#include <Poco/Net/IPAddress.h>
#include <Poco/Net/SocketAddress.h>

namespace OpenWifi {

namespace Orion {
inline const std::vector<Poco::Net::SocketAddress> ServerAddresses = {
Poco::Net::SocketAddress("216.239.32.91:2083"),
Poco::Net::SocketAddress("216.239.34.91:2083")
};
}

}
104 changes: 94 additions & 10 deletions src/RESTAPI/RESTAPI_radius_endpoint_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,9 @@
//

#include "RESTAPI_radius_endpoint_handler.h"
#include <storage/storage_orion_accounts.h>

namespace OpenWifi {
static inline bool ValidEndpointTypes(const std::string &T) {
return T=="radius" || T=="radsec" || T=="globalreach" || T=="orion";
}

static inline bool ValidPoolStrategy(const std::string &T) {
return T=="none" || T=="random" || T=="weighted";
}

void RESTAPI_radius_endpoint_handler::DoGet() {
auto id = GetBinding("id");
Expand Down Expand Up @@ -40,6 +34,17 @@ namespace OpenWifi {
return NotFound();
}

static bool ValidPort(std::uint32_t P) {
return P>0 && P<65535;
}

static bool ValidRadiusServer(const ProvObjects::RADIUSServer &S) {
if(S.Hostname.empty() || !ValidPort(S.Port) || !Utils::ValidIP(S.IP) || S.Secret.empty()) {
return false;
}
return true;
}

void RESTAPI_radius_endpoint_handler::DoPost() {
auto id = GetBinding("id");
if(id.empty()) {
Expand All @@ -52,19 +57,98 @@ namespace OpenWifi {
return BadRequest(RESTAPI::Errors::InvalidJSONDocument);
}

if(!ValidEndpointTypes(NewRecord.Type)) {
if(RadiusEndpointDB::EndpointType(NewRecord.Type)!=RadiusEndpointDB::EndpointType::unknown) {
return BadRequest(RESTAPI::Errors::InvalidRadiusTypeEndpoint);
}
if(!ValidPoolStrategy(NewRecord.PoolStrategy)) {
if(RadiusEndpointDB::PoolStrategy(NewRecord.PoolStrategy)!=RadiusEndpointDB::PoolStrategy::unknown) {
return BadRequest(RESTAPI::Errors::InvalidRadiusEndpointPoolStrategy);
}
if(!NewRecord.RadiusServers.empty() && !NewRecord.RadsecServers.empty()) {
return BadRequest(RESTAPI::Errors::EndpointMustHaveOneTypeOfServers);
}
if(NewRecord.Index.empty()) {

auto EndPointType = RadiusEndpointDB::EndpointType(NewRecord.Type);
switch(EndPointType) {
case RadiusEndpointDB::EndpointType::radsec:
case RadiusEndpointDB::EndpointType::orion:
case RadiusEndpointDB::EndpointType::globalreach:
{
if(NewRecord.RadsecServers.empty()) {
return BadRequest(RESTAPI::Errors::EndpointMustHaveOneTypeOfServers);
}
} break;
case RadiusEndpointDB::EndpointType::radius: {
if(NewRecord.RadiusServers.empty()) {
return BadRequest(RESTAPI::Errors::EndpointMustHaveOneTypeOfServers);
}
} break;
default:
return BadRequest(RESTAPI::Errors::EndpointMustHaveOneTypeOfServers);
}

if(NewRecord.Index.empty() || !RadiusEndpointDB::ValidIndex(NewRecord.Index)) {
return BadRequest(RESTAPI::Errors::RadiusEndpointIndexInvalid);
}

// Make sure that nobody is using that index
auto where = fmt::format(" index='{}' ", NewRecord.Index);
if(DB_.Count(where)!=0) {
return BadRequest(RESTAPI::Errors::RadiusEndpointIndexInvalid);
}

if(EndPointType==RadiusEndpointDB::EndpointType::radius) {
for(const auto &Server:NewRecord.RadiusServers) {
if(!ValidRadiusServer(Server.Authentication) ||
!ValidRadiusServer(Server.Accounting) ||
!ValidRadiusServer(Server.CoA)) {
return BadRequest(RESTAPI::Errors::InvalidRadiusServer);
}
}
} else {
switch(EndPointType) {
case RadiusEndpointDB::EndpointType::orion: {
for(const auto &Server:NewRecord.RadsecServers) {
if(!StorageService()->OrionAccountsDB().Exists("id",Server.UseOpenRoamingAccount)) {
return BadRequest(RESTAPI::Errors::OrionAccountMustExist);
}
}
} break;
case RadiusEndpointDB::EndpointType::globalreach: {
for(const auto &Server:NewRecord.RadsecServers) {
if(!StorageService()->GLBLRCertsDB().Exists("id",Server.UseOpenRoamingAccount)) {
return BadRequest(RESTAPI::Errors::GlobalReachCertMustExist);
}
}
} break;
case RadiusEndpointDB::EndpointType::radsec: {
for(const auto &Server:NewRecord.RadsecServers) {
if(Server.Certificate.empty() || !Utils::ValidX509Certificate(Server.Certificate)) {
return BadRequest(RESTAPI::Errors::InvalidRadsecMainCertificate);
}
if(Server.CaCerts.empty() || !Utils::ValidX509Certificate(Server.CaCerts)) {
return BadRequest(RESTAPI::Errors::InvalidRadsecCaCertificate);
}
if(Server.PrivateKey.empty() || !Utils::VerifyPrivateKey(Server.PrivateKey)) {
return BadRequest(RESTAPI::Errors::InvalidRadsecPrivteKey);
}
if(!Utils::ValidIP(Server.IP)) {
return BadRequest(RESTAPI::Errors::InvalidRadsecIPAddress);
}
if(!(Server.Port>0 && Server.Port<65535)) {
return BadRequest(RESTAPI::Errors::InvalidRadsecPort);
}
if(Server.Secret.empty()) {
return BadRequest(RESTAPI::Errors::InvalidRadsecSecret);
}
}

} break;
default: {

}
}
}

ProvObjects::CreateObjectInfo(RawObject,UserInfo_.userinfo,NewRecord.info);
if(DB_.CreateRecord(NewRecord)) {
RecordType AddedRecord;
Expand Down
10 changes: 10 additions & 0 deletions src/framework/ow_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,16 @@ namespace OpenWifi::RESTAPI::Errors {
static const struct msg InvalidRadiusEndpointPoolStrategy { 1179, "Invalid RADIUS Server Endpoint Pool strategy." };
static const struct msg EndpointMustHaveOneTypeOfServers { 1180, "All servers must be either RADIUS or RADSEC." };
static const struct msg RadiusEndpointIndexInvalid { 1181, "Index must be an address between 0.0.1.1 and 0.0.2.254" };
static const struct msg RadiusEndpointIndexMustBeUnique { 1182, "Index must be unique." };
static const struct msg OrionAccountMustExist { 1183, "Orion account must exist." };
static const struct msg GlobalReachCertMustExist { 1184, "Global Reach certificate must exist." };
static const struct msg InvalidRadsecMainCertificate { 1185, "Invalid Radsec main certificate." };
static const struct msg InvalidRadsecCaCertificate { 1186, "Invalid Radsec CA certificates." };
static const struct msg InvalidRadsecPrivteKey { 1187, "Invalid Radsec Private key." };
static const struct msg InvalidRadsecIPAddress { 1188, "Invalid Radsec IP Address." };
static const struct msg InvalidRadsecPort { 1189, "Invalid Radsec Port." };
static const struct msg InvalidRadsecSecret { 1190, "Invalid Radsec Secret." };
static const struct msg InvalidRadiusServer { 1191, "Invalid Radius Server." };

static const struct msg SimulationDoesNotExist {
7000, "Simulation Instance ID does not exist."
Expand Down
4 changes: 4 additions & 0 deletions src/framework/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,10 @@ namespace OpenWifi::Utils {
return false;
}

bool VerifyPrivateKey(const std::string &key) {
return VerifyECKey(key) || VerifyRSAKey(key);
}

bool ValidX509Certificate([[
maybe_unused]] const std::string &Cert) {
try {
Expand Down
19 changes: 19 additions & 0 deletions src/framework/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,24 @@ namespace OpenWifi::Utils {
return count;
}

inline std::uint32_t IPtoInt(const std::string &A) {
Poco::Net::IPAddress IP;
std::uint32_t Result=0;

if(Poco::Net::IPAddress::tryParse(A,IP)) {
for(const auto i:IP.toBytes()) {
Result <<= 8;
Result += i;
}
}
return Result;
}

inline bool ValidIP(const std::string &IPstr) {
Poco::Net::IPAddress IP;
return Poco::Net::IPAddress::tryParse(IPstr,IP);
}

struct CSRCreationParameters {
std::string Country, Province, City,
Organization, CommonName;
Expand All @@ -261,6 +279,7 @@ namespace OpenWifi::Utils {
std::string generateStrongPassword(int minLength, int maxLength, int numDigits, int minLowercase, int minSpecial, int minUppercase);
bool VerifyECKey(const std::string &key);
bool VerifyRSAKey(const std::string &key);
bool VerifyPrivateKey(const std::string &key);
bool ValidX509Certificate(const std::string &Cert);
bool ValidX509Certificate(const std::vector<std::string> &Certs);

Expand Down
52 changes: 52 additions & 0 deletions src/storage/storage_radius_endpoints.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,58 @@ namespace OpenWifi {
RadiusEndpointDB(OpenWifi::DBType T, Poco::Data::SessionPool &P, Poco::Logger &L);
virtual ~RadiusEndpointDB(){};
bool Upgrade(uint32_t from, uint32_t &to) override;

enum class PoolStrategy {
none, random, weighted, unknown
};

enum class EndpointType {
radius, radsec, globalreach, orion, unknown
};

static inline EndpointType EndpointType(const std::string &T) {
if(T=="radius") return EndpointType::radius;
if(T=="radsec") return EndpointType::radsec;
if(T=="globalreach") return EndpointType::globalreach;
if(T=="orion") return EndpointType::orion;
return EndpointType::unknown;
}

static inline PoolStrategy PoolStrategy(const std::string &T) {
if(T=="none") return PoolStrategy::none;
if(T=="random") return PoolStrategy::random;
if(T=="weighted") return PoolStrategy::weighted;
return PoolStrategy::unknown;
}

static inline std::string to_string(enum EndpointType T) {
switch(T) {
case EndpointType::radius: return "radius";
case EndpointType::radsec: return "radsec";
case EndpointType::globalreach: return "globalreach";
case EndpointType::orion: return "orion";
default:
return "unknown";
}
}

static inline std::string to_string(enum PoolStrategy T) {
switch(T) {
case PoolStrategy::none: return "none";
case PoolStrategy::random: return "random";
case PoolStrategy::weighted: return "weighted";
default:
return "unknown";
}
}

static inline bool ValidIndex(const std::string &I) {
static uint32_t Low = Utils::IPtoInt("0.0.1.1");
static uint32_t High = Utils::IPtoInt("0.0.2.254");
auto IP = Utils::IPtoInt(I);
return (IP>=Low) && (IP<=High);
}

private:

};
Expand Down

0 comments on commit 9ea65eb

Please sign in to comment.