Commit 02e9fb5b authored by Tien-Thinh Nguyen's avatar Tien-Thinh Nguyen
Browse files

Generate signature for OAuth2 authorization

parent 011c9ac8
......@@ -34,7 +34,7 @@ void AccessTokenRequestApi::init() {
void AccessTokenRequestApi::setupRoutes() {
using namespace Pistache::Rest;
Routes::Post(*router, base + nrf_cfg.sbi_api_version + "/oauth2/token", Routes::bind(&AccessTokenRequestApi::access_token_request_handler, this));
Routes::Post(*router, base + "/oauth2/token", Routes::bind(&AccessTokenRequestApi::access_token_request_handler, this));
// Default handler, called when a route is not found
router->addCustomHandler(Routes::bind(&AccessTokenRequestApi::access_token_request_api_default_handler, this));
......
/**
* NRF OAuth2
* NRF OAuth2 Authorization. © 2019, 3GPP Organizational Partners (ARIB, ATIS, CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved.
* NRF OAuth2 Authorization. © 2019, 3GPP Organizational Partners (ARIB, ATIS,
* CCSA, ETSI, TSDSI, TTA, TTC). All rights reserved.
*
* The version of the OpenAPI document: 1.0.2
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
* NOTE: This class is auto generated by OpenAPI Generator
* (https://openapi-generator.tech). https://openapi-generator.tech Do not edit
* the class manually.
*/
#include "AccessTokenRequestApiImpl.h"
#include "3gpp_29.500.h"
#include "AccessTokenRsp.h"
#include "Helpers.h"
#include "logger.hpp"
namespace oai {
namespace nrf {
......@@ -18,23 +23,44 @@ namespace api {
using namespace oai::nrf::model;
using namespace oai::nrf::app;
using namespace oai::nrf::helpers;
AccessTokenRequestApiImpl::AccessTokenRequestApiImpl(
std::shared_ptr<Pistache::Rest::Router> rtr, nrf_app *nrf_app_inst,
std::string address)
:
AccessTokenRequestApi(rtr),
m_nrf_app(nrf_app_inst),
m_address(address) {
}
: AccessTokenRequestApi(rtr), m_nrf_app(nrf_app_inst), m_address(address) {}
void AccessTokenRequestApiImpl::access_token_request(
const Pistache::Rest::Request &request,
Pistache::Http::ResponseWriter &response) {
response.send(Pistache::Http::Code::Ok, "Do some magic\n");
}
Logger::nrf_sbi().info(
"Got a request to request an OAuth2 access token from the authorization "
"server (NRF)");
}
}
Logger::nrf_sbi().info("request body %s", request.body().c_str());
int http_code = 0;
ProblemDetails problem_details = {};
AccessTokenRsp access_token_rsp = {};
m_nrf_app->handle_access_token_request(request.body(), access_token_rsp,
http_code, 1, problem_details);
nlohmann::json json_data = {};
std::string content_type = "application/json";
if (http_code != HTTP_STATUS_CODE_200_OK) {
to_json(json_data, problem_details);
content_type = "application/problem+json";
} else {
to_json(json_data, access_token_rsp);
}
// content type
response.headers().add<Pistache::Http::Header::ContentType>(
Pistache::Http::Mime::MediaType(content_type));
response.send(Pistache::Http::Code(http_code), json_data.dump().c_str());
}
} // namespace api
} // namespace nrf
} // namespace oai
......@@ -29,6 +29,9 @@
#include "nrf_app.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/date_time/posix_time/time_formatters.hpp>
#include <chrono>
......@@ -40,8 +43,8 @@
#include "logger.hpp"
#include "nrf_client.hpp"
#include "nrf_config.hpp"
#include "nrf_search_result.hpp"
#include "nrf_jwt.hpp"
#include "nrf_search_result.hpp"
using namespace oai::nrf::app;
using namespace oai::nrf::model;
......@@ -54,11 +57,10 @@ nrf_jwt *nrf_jwt_inst = nullptr;
//------------------------------------------------------------------------------
nrf_app::nrf_app(const std::string &config_file, nrf_event &ev)
:
m_event_sub(ev),
m_instance_id2nrf_profile(),
m_subscription_id2nrf_subscription(),
m_search_id2search_result() {
: m_event_sub(ev),
m_instance_id2nrf_profile(),
m_subscription_id2nrf_subscription(),
m_search_id2search_result() {
Logger::nrf_app().startup("Starting...");
try {
......@@ -101,21 +103,17 @@ void nrf_app::handle_register_nf_instance(
nf_instance_id.c_str(),
nf_profile.getNfType().c_str());
std::shared_ptr<nrf_profile> sn = { };
std::shared_ptr<nrf_profile> sn = {};
switch (type) {
case NF_TYPE_AMF: {
sn = std::make_shared < amf_profile > (m_event_sub);
}
break;
sn = std::make_shared<amf_profile>(m_event_sub);
} break;
case NF_TYPE_SMF: {
sn = std::make_shared < smf_profile > (m_event_sub);
}
break;
sn = std::make_shared<smf_profile>(m_event_sub);
} break;
default: {
sn = std::make_shared < nrf_profile > (m_event_sub);
}
default: { sn = std::make_shared<nrf_profile>(m_event_sub); }
}
// convert to nrf_profile
......@@ -132,8 +130,9 @@ void nrf_app::handle_register_nf_instance(
// Heartbeart management for this NF profile
// get current time
uint64_t ms = std::chrono::duration_cast < std::chrono::milliseconds
> (std::chrono::system_clock::now().time_since_epoch()).count();
uint64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
sn.get()->subscribe_task_tick(ms);
// Notify NF status change event
......@@ -162,7 +161,7 @@ void nrf_app::handle_update_nf_instance(
http_version);
// Find the profile corresponding to the instance ID
std::shared_ptr<nrf_profile> sn = { };
std::shared_ptr<nrf_profile> sn = {};
sn = find_nf_profile(nf_instance_id);
bool op_success = true;
bool is_heartbeart_procedure = false;
......@@ -171,8 +170,8 @@ void nrf_app::handle_update_nf_instance(
for (auto p : patchItem) {
patch_op_type_t op = api_conv::string_to_patch_operation(p.getOp());
// Verify Path
if ((p.getPath().substr(0, 1).compare("/") != 0)
or (p.getPath().length() < 2)) {
if ((p.getPath().substr(0, 1).compare("/") != 0) or
(p.getPath().length() < 2)) {
Logger::nrf_app().warn("Bad value for operation path: %s ",
p.getPath().c_str());
http_code = HTTP_STATUS_CODE_400_BAD_REQUEST;
......@@ -185,16 +184,14 @@ void nrf_app::handle_update_nf_instance(
switch (op) {
case PATCH_OP_REPLACE: {
if (path.compare("nfStatus") == 0)
is_heartbeart_procedure = true;
if (path.compare("nfStatus") == 0) is_heartbeart_procedure = true;
if (sn.get()->replace_profile_info(path, p.getValue())) {
update_nf_profile(nf_instance_id, sn);
http_code = HTTP_STATUS_CODE_200_OK;
} else {
op_success = false;
}
}
break;
} break;
case PATCH_OP_ADD: {
if (sn.get()->add_profile_info(path, p.getValue())) {
......@@ -203,8 +200,7 @@ void nrf_app::handle_update_nf_instance(
} else {
op_success = false;
}
}
break;
} break;
case PATCH_OP_REMOVE: {
if (sn.get()->remove_profile_info(path)) {
......@@ -213,8 +209,7 @@ void nrf_app::handle_update_nf_instance(
} else {
op_success = false;
}
}
break;
} break;
default: {
Logger::nrf_app().warn("Requested operation is not valid!");
......@@ -258,7 +253,7 @@ void nrf_app::handle_get_nf_instances(
// TODO: verify if the NF Service Consumer is allowed to retrieve the
// registered NF instances
std::vector < std::shared_ptr < nrf_profile >> profiles = { };
std::vector<std::shared_ptr<nrf_profile>> profiles = {};
nf_type_t type = api_conv::string_to_nf_type(nf_type);
if (type == NF_TYPE_UNKNOWN) {
Logger::nrf_app().debug("Unknown requested nf_type: %s", nf_type.c_str());
......@@ -276,11 +271,11 @@ void nrf_app::handle_get_nf_instances(
}
for (auto profile : profiles) {
std::string instance_uri = std::string(
inet_ntoa(*((struct in_addr*) &nrf_cfg.sbi.addr4))) + ":"
+ std::to_string(nrf_cfg.sbi.port) + NNRF_NFM_BASE
+ nrf_cfg.sbi_api_version + NNRF_NFM_NF_INSTANCE
+ profile.get()->get_nf_instance_id();
std::string instance_uri =
std::string(inet_ntoa(*((struct in_addr *)&nrf_cfg.sbi.addr4))) + ":" +
std::to_string(nrf_cfg.sbi.port) + NNRF_NFM_BASE +
nrf_cfg.sbi_api_version + NNRF_NFM_NF_INSTANCE +
profile.get()->get_nf_instance_id();
uris.push_back(instance_uri);
profile.get()->display();
......@@ -356,8 +351,8 @@ void nrf_app::handle_create_subscription(
Logger::nrf_app().info("Handle Create a new subscription (HTTP version %d)",
http_version);
std::shared_ptr<nrf_subscription> ss = std::make_shared < nrf_subscription
> (m_event_sub);
std::shared_ptr<nrf_subscription> ss =
std::make_shared<nrf_subscription>(m_event_sub);
// convert to nrf_subscription
if (api_conv::subscription_api_to_nrf_subscription(subscription_data, ss)) {
......@@ -425,7 +420,7 @@ void nrf_app::handle_update_subscription(
http_version);
// Find the existing subscription
std::shared_ptr<nrf_subscription> ss = { };
std::shared_ptr<nrf_subscription> ss = {};
ss = find_subscription(sub_id);
bool op_success = false;
......@@ -435,8 +430,8 @@ void nrf_app::handle_update_subscription(
for (auto p : patchItem) {
patch_op_type_t op = api_conv::string_to_patch_operation(p.getOp());
// Verify Path
if ((p.getPath().substr(0, 1).compare("/") != 0)
or (p.getPath().length() < 2)) {
if ((p.getPath().substr(0, 1).compare("/") != 0) or
(p.getPath().length() < 2)) {
Logger::nrf_app().warn("Bad value for operation path: %s ",
p.getPath().c_str());
http_code = HTTP_STATUS_CODE_400_BAD_REQUEST;
......@@ -471,8 +466,7 @@ void nrf_app::handle_update_subscription(
std::cout << " Exception: " << e.what() << std::endl;
}
}
}
break;
} break;
default: {
Logger::nrf_app().warn("Requested operation is not valid!");
......@@ -539,7 +533,7 @@ void nrf_app::handle_search_nf_instances(
ss.get()->set_search_id(search_id);
// set search result
std::vector < std::shared_ptr < nrf_profile >> profiles = { };
std::vector<std::shared_ptr<nrf_profile>> profiles = {};
find_nf_profiles(target_type, profiles);
if (profiles.size() > 0) {
ss.get()->set_nf_instances(profiles);
......@@ -561,6 +555,64 @@ void nrf_app::handle_search_nf_instances(
http_code = HTTP_STATUS_CODE_200_OK;
}
//------------------------------------------------------------------------------
void nrf_app::handle_access_token_request(const std::string &request_body,
AccessTokenRsp &access_token_rsp,
int &http_code,
const uint8_t http_version,
ProblemDetails &problem_details) {
Logger::nrf_app().info(
"Handle a request to request an OAuth2 access token from NRF (HTTP "
"version %d)",
http_version);
std::map<std::string, std::string> access_token_req;
// Process request_body
std::vector<std::string> key_values;
boost::split(key_values, request_body, boost::is_any_of("&"),
boost::token_compress_on);
for (auto p : key_values) {
std::vector<std::string> key_value;
boost::split(key_value, p, boost::is_any_of("="), boost::token_compress_on);
if (key_value.size() != 2) {
// error
Logger::nrf_app().debug("Invalid key-value tuple");
} else {
access_token_req[key_value[0]] = key_value[1];
}
Logger::nrf_app().debug("(Key, Value): %s, %s", key_value[0].c_str(),
key_value[1].c_str());
}
// validate the Access Token Request
if ((access_token_req.count("grant_type") == 0) or
(access_token_req.count("nfInstanceId") == 0) or
(access_token_req.count("scope") == 0)) {
http_code = HTTP_STATUS_CODE_400_BAD_REQUEST;
problem_details.setCause(
protocol_application_error_e2str[MANDATORY_IE_MISSING]);
Logger::nrf_app().info("Grant type/nfInstanceId/scope missing");
return;
}
// Generate signature
std::string signature = {};
if (!nrf_jwt_inst->generate_signature(access_token_req.at("nfInstanceId"),
signature)) {
http_code = HTTP_STATUS_CODE_400_BAD_REQUEST;
problem_details.setCause(
protocol_application_error_e2str[MANDATORY_QUERY_PARAM_INCORRECT]);
Logger::nrf_app().info("Mandatory IE incorrect");
return;
}
// AccessTokenRsp
access_token_rsp.setAccessToken(signature);
access_token_rsp.setTokenType("Bearer");
// TODO: Expires_in, Scope;
http_code = HTTP_STATUS_CODE_200_OK;
}
//------------------------------------------------------------------------------
bool nrf_app::add_nf_profile(const std::string &profile_id,
const std::shared_ptr<nrf_profile> &p) {
......@@ -745,8 +797,9 @@ void nrf_app::subscribe_task_tick(uint64_t ms) {
its.it_value.tv_sec = 20; // seconds
its.it_value.tv_nsec = 0; // 100 * 1000 * 1000; //100ms
const uint64_t interval = its.it_value.tv_sec * 1000
+ its.it_value.tv_nsec / 1000000; // convert sec, nsec to msec
const uint64_t interval =
its.it_value.tv_sec * 1000 +
its.it_value.tv_nsec / 1000000; // convert sec, nsec to msec
Logger::nrf_app().debug("subscribe task_tick: %d", ms);
m_event_sub.subscribe_task_tick(
......@@ -798,18 +851,17 @@ void nrf_app::handle_nf_status_registered(const std::string &profile_id) {
Logger::nrf_app().info("Handle NF status registered, profile id %s",
profile_id.c_str());
std::shared_ptr<nrf_profile> profile = { };
std::shared_ptr<nrf_profile> profile = {};
Logger::nrf_app().info("\tFind a NF profile with ID %s", profile_id.c_str());
find_nf_profile(profile_id, profile);
if (profile != nullptr) {
std::vector < std::string > notification_uris = { };
std::vector<std::string> notification_uris = {};
get_subscription_list(profile_id, NOTIFICATION_TYPE_NF_REGISTERED,
notification_uris);
// send notifications
if (notification_uris.size() > 0)
nrf_client_inst->notify_subscribed_event(profile,
NOTIFICATION_TYPE_NF_REGISTERED,
notification_uris);
nrf_client_inst->notify_subscribed_event(
profile, NOTIFICATION_TYPE_NF_REGISTERED, notification_uris);
else
Logger::nrf_app().debug("\tNo subscription found");
......@@ -832,16 +884,15 @@ void nrf_app::handle_nf_status_deregistered(const std::string &profile_id) {
Logger::nrf_app().info("Handle NF status deregistered, profile id %s",
profile_id.c_str());
std::shared_ptr<nrf_profile> profile = { };
std::shared_ptr<nrf_profile> profile = {};
find_nf_profile(profile_id, profile);
if (profile != nullptr) {
std::vector < std::string > notification_uris = { };
std::vector<std::string> notification_uris = {};
get_subscription_list(profile_id, NOTIFICATION_TYPE_NF_DEREGISTERED,
notification_uris);
// send notifications
nrf_client_inst->notify_subscribed_event(profile,
NOTIFICATION_TYPE_NF_DEREGISTERED,
notification_uris);
nrf_client_inst->notify_subscribed_event(
profile, NOTIFICATION_TYPE_NF_DEREGISTERED, notification_uris);
} else {
Logger::nrf_app().error("NF profile not found, profile id %s",
......@@ -861,10 +912,10 @@ void nrf_app::subscribe_nf_status_profile_changed() {
void nrf_app::handle_nf_status_profile_changed(const std::string &profile_id) {
Logger::nrf_app().info("Handle NF status profile changed, profile id %s",
profile_id.c_str());
std::shared_ptr<nrf_profile> profile = { };
std::shared_ptr<nrf_profile> profile = {};
find_nf_profile(profile_id, profile);
if (profile != nullptr) {
std::vector < std::string > notification_uris = { };
std::vector<std::string> notification_uris = {};
get_subscription_list(profile_id, NOTIFICATION_TYPE_NF_PROFILE_CHANGED,
notification_uris);
// Notification data includes NF profile (other alternative, includes
......@@ -886,7 +937,7 @@ void nrf_app::get_subscription_list(const std::string &profile_id,
"\tGet the list of subscriptions related to this profile, profile id %s",
profile_id.c_str());
std::shared_ptr<nrf_profile> profile = { };
std::shared_ptr<nrf_profile> profile = {};
find_nf_profile(profile_id, profile);
if (profile.get() == nullptr) {
......@@ -908,8 +959,7 @@ void nrf_app::get_subscription_list(const std::string &profile_id,
break;
}
}
if (!match_notif_type)
continue;
if (!match_notif_type) continue;
// check validity time
boost::posix_time::ptime t(boost::posix_time::microsec_clock::local_time());
......@@ -924,7 +974,7 @@ void nrf_app::get_subscription_list(const std::string &profile_id,
continue;
}
subscription_condition_t condition = { };
subscription_condition_t condition = {};
s.second.get()->get_sub_condition(condition);
switch (condition.type) {
......@@ -935,8 +985,7 @@ void nrf_app::get_subscription_list(const std::string &profile_id,
s.first.c_str(), uri.c_str());
}
}
break;
} break;
case NF_TYPE_COND: {
std::string nf_type = nf_type_e2str[profile.get()->get_nf_type()];
if (nf_type.compare(condition.nf_type) == 0) {
......@@ -944,8 +993,7 @@ void nrf_app::get_subscription_list(const std::string &profile_id,
Logger::nrf_app().debug("\tSubscription id %s, uri %s",
s.first.c_str(), uri.c_str());
}
}
break;
} break;
case SERVICE_NAME_COND: {
std::string service_name;
......@@ -956,38 +1004,34 @@ void nrf_app::get_subscription_list(const std::string &profile_id,
s.first.c_str(), uri.c_str());
}
}
break;
} break;
case AMF_COND: {
std::string nf_type = nf_type_e2str[profile.get()->get_nf_type()];
if (nf_type.compare("AMF") == 0) {
amf_info_t info = { };
std::static_pointer_cast < amf_profile
> (profile).get()->get_amf_info(info);
if ((info.amf_region_id.compare(condition.amf_info.amf_region_id) == 0)
and (info.amf_set_id.compare(condition.amf_info.amf_set_id) == 0)) {
amf_info_t info = {};
std::static_pointer_cast<amf_profile>(profile).get()->get_amf_info(
info);
if ((info.amf_region_id.compare(condition.amf_info.amf_region_id) ==
0) and
(info.amf_set_id.compare(condition.amf_info.amf_set_id) == 0)) {
uris.push_back(uri);
Logger::nrf_app().debug("\tSubscription id %s, uri %s",
s.first.c_str(), uri.c_str());
}
}
}
break;
} break;
case GUAMI_LIST_COND: {
// TODO:
}
break;
} break;
case NETWOTK_SLICE_COND: {
// TODO:
}
break;
} break;
case NF_GROUP_COND: {
// TODO:
}
break;
} break;
default: {
// TODO:
......@@ -1031,4 +1075,3 @@ bool nrf_app::find_search_result(const std::string &search_id,
return false;
}
}
......@@ -35,12 +35,14 @@
#include "PatchItem.h"
#include "ProblemDetails.h"
#include "SubscriptionData.h"
#include "AccessTokenRsp.h"
#include "nrf_event.hpp"
#include "nrf_profile.hpp"
#include "nrf_search_result.hpp"
#include "nrf_subscription.hpp"
#include "uint_generator.hpp"
namespace oai {
namespace nrf {
namespace app {
......@@ -193,6 +195,20 @@ class nrf_app {
int &http_code, const uint8_t http_version,
ProblemDetails &problem_details);
/*
* Handle a Register NF Instance request
* @param [const std::string &] request_body: includes access token request
* @param [AccessTokenRsp &] access_token_rsp: Access token response
* @param [int &] http_code: HTTP code used to return to the consumer
* @param [const uint8_t] http_version: HTTP version
* @param [ProblemDetails &] problem_details: Store details of the error
* @return void
*/
void handle_access_token_request(const std::string &request_body,
AccessTokenRsp &access_token_rsp,
int &http_code, const uint8_t http_version,
ProblemDetails &problem_details);
/*
* Insert a nrf profile
* @param [const std::string &] profile_id: Profile ID
......
......@@ -3,9 +3,9 @@
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
* the OAI Public License, Version 1.1 (the "License"); you may not use this
*file except in compliance with the License. You may obtain a copy of the
*License at
*
* http://www.openairinterface.org/?page_id=698
*
......@@ -30,24 +30,52 @@
#include "nrf_jwt.hpp"
#include <iostream>
#include "jwt/jwt.hpp"
using namespace oai::nrf::app;
void nrf_jwt::test_jwt(){
using namespace jwt::params;
//------------------------------------------------------------------------------
bool nrf_jwt::generate_signature(const std::string &nf_consumer_id,
std::string &signature) const {
std::string key;
get_secret_key(nf_consumer_id, key);
// Create JWT object
//TODO
jwt::jwt_object obj{jwt::params::algorithm("HS256"),
jwt::params::payload({{"iss", "nrf_instance_id"},
{"sub", "nf_consumer_id"},
{"aud", "nf_producer_id"},
{"scope", "nf_producer_name"},
{"exp", "100"}}),
jwt::params::secret(key)};
// Get the encoded string/assertion
signature = obj.signature();
}
//------------------------------------------------------------------------------
bool nrf_jwt::get_secret_key(const std::string &nf_consumer_id,
std::string &key) const {
// TODO:
key = "secret";
}
auto key = "secret"; //Secret to use for the algorithm
//Create JWT object
jwt::jwt_object obj{algorithm("HS256"), payload({{"some", "payload"}}), secret(key)};
//------------------------------------------------------------------------------
void nrf_jwt::test_jwt() {
using namespace jwt::params;