Skip to content

Commit

Permalink
Ehance the usage of the get_authorization_bearer_token_handler callback
Browse files Browse the repository at this point in the history
  • Loading branch information
lo-simon committed Dec 7, 2023
1 parent 6272d59 commit 311bed6
Show file tree
Hide file tree
Showing 15 changed files with 78 additions and 139 deletions.
3 changes: 1 addition & 2 deletions Development/nmos-cpp-node/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,7 @@ int main(int argc, char* argv[])
if (nmos::experimental::fields::client_authorization(node_model.settings))
{
node_implementation
.on_get_authorization_bearer_token(nmos::experimental::make_authorization_token_handler(authorization_state, gate))
.on_make_authorization_config(nmos::experimental::make_authorization_config_handler(authorization_state, gate))
.on_get_authorization_bearer_token(nmos::experimental::make_get_authorization_bearer_token_handler(authorization_state, gate))
.on_load_authorization_clients(nmos::experimental::make_load_authorization_clients_handler(node_model.settings, gate))
.on_save_authorization_client(nmos::experimental::make_save_authorization_client_handler(node_model.settings, gate))
.on_load_rsa_private_keys(nmos::make_load_rsa_private_keys_handler(node_model.settings, gate)) // may be omitted, only required for OAuth client which is using Private Key JWT as the requested authentication method for the token endpoint
Expand Down
49 changes: 1 addition & 48 deletions Development/nmos/authorization_handlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,53 +207,6 @@ namespace nmos
};
}

// construct callback to make OAuth 2.0 config
authorization_config_handler make_authorization_config_handler(const web::json::value& authorization_server_metadata, const web::json::value& client_metadata, slog::base_gate& gate)
{
return[&](const web::http::oauth2::experimental::oauth2_token& bearer_token)
{
slog::log<slog::severities::more_info>(gate, SLOG_FLF) << "Make OAuth 2.0 config";

web::http::oauth2::experimental::oauth2_config config(
client_metadata.is_null() ? U("") : nmos::experimental::fields::client_id(client_metadata),
client_metadata.is_null() ? U("") : client_metadata.has_string_field(nmos::experimental::fields::client_secret) ? nmos::experimental::fields::client_secret(client_metadata) : U(""),
authorization_server_metadata.is_null() ? U("") : nmos::experimental::fields::authorization_endpoint(authorization_server_metadata),
authorization_server_metadata.is_null() ? U("") : nmos::experimental::fields::token_endpoint(authorization_server_metadata),
client_metadata.is_null() ? U("") : client_metadata.has_array_field(nmos::experimental::fields::redirect_uris) && nmos::experimental::fields::redirect_uris(client_metadata).size() ? nmos::experimental::fields::redirect_uris(client_metadata).at(0).as_string() : U(""),
client_metadata.is_null() ? U("") : client_metadata.has_string_field(nmos::experimental::fields::scope) ? nmos::experimental::fields::scope(client_metadata) : U(""));

if (!client_metadata.is_null())
{
const auto& response_types = nmos::experimental::fields::response_types(client_metadata);
bool found_code = false;
bool found_token = false;
for (auto response_type : response_types)
{
if (web::http::oauth2::experimental::response_types::code.name == response_type.as_string()) { found_code = true; }
else if (web::http::oauth2::experimental::response_types::token.name == response_type.as_string()) { found_token = true; }
};
config.set_bearer_auth(found_code || !found_token);
}

config.set_token(bearer_token);

return config;
};
}
authorization_config_handler make_authorization_config_handler(const authorization_state& authorization_state, slog::base_gate& gate)
{
return[&](const web::http::oauth2::experimental::oauth2_token& /*bearer_token*/)
{
slog::log<slog::severities::more_info>(gate, SLOG_FLF) << "Make OAuth 2.0 config using bearer_token cache";

const auto authorization_server_metadata = get_authorization_server_metadata(authorization_state);
const auto client_metadata = get_client_metadata(authorization_state);

auto make_authorization_config = make_authorization_config_handler(authorization_server_metadata, client_metadata, gate);
return make_authorization_config(authorization_state.bearer_token);
};
}

// construct callback to validate OAuth 2.0 authorization access token
validate_authorization_token_handler make_validate_authorization_token_handler(authorization_state& authorization_state, slog::base_gate& gate)
{
Expand Down Expand Up @@ -364,7 +317,7 @@ namespace nmos
}

// construct callback to retrieve OAuth 2.0 authorization bearer token
authorization_token_handler make_authorization_token_handler(authorization_state& authorization_state, slog::base_gate& gate)
get_authorization_bearer_token_handler make_get_authorization_bearer_token_handler(authorization_state& authorization_state, slog::base_gate& gate)
{
return[&]()
{
Expand Down
12 changes: 2 additions & 10 deletions Development/nmos/authorization_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,14 +135,6 @@ namespace nmos
// construct callback to start the authorization code flow request on a browser
request_authorization_code_handler make_request_authorization_code_handler(slog::base_gate& gate);

// callback to return OAuth 2.0 authorization config
// this callback is executed while constructing http_client_config
// this callback should not throw exceptions
typedef std::function <web::http::oauth2::experimental::oauth2_config(const web::http::oauth2::experimental::oauth2_token& bearer_token)> authorization_config_handler;
// construct callback to make OAuth 2.0 config
authorization_config_handler make_authorization_config_handler(const web::json::value& authorization_server_metadata, const web::json::value& client_metadata, slog::base_gate& gate);
authorization_config_handler make_authorization_config_handler(const authorization_state& authorization_state, slog::base_gate& gate);

// callback to validate OAuth 2.0 authorization access token
// this callback should not throw exceptions
typedef std::function <authorization_error(const utility::string_t& access_token)> validate_authorization_token_handler;
Expand All @@ -158,9 +150,9 @@ namespace nmos
// callback to return OAuth 2.0 authorization bearer token
// this callback is execute while create http_client
// this callback should not throw exceptions
typedef std::function<web::http::oauth2::experimental::oauth2_token()> authorization_token_handler;
typedef std::function<web::http::oauth2::experimental::oauth2_token()> get_authorization_bearer_token_handler;
// construct callback to retrieve OAuth 2.0 authorization bearer token
authorization_token_handler make_authorization_token_handler(authorization_state& authorization_state, slog::base_gate& gate);
get_authorization_bearer_token_handler make_get_authorization_bearer_token_handler(authorization_state& authorization_state, slog::base_gate& gate);
}
}

Expand Down
8 changes: 4 additions & 4 deletions Development/nmos/authorization_operation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,9 @@ namespace nmos

// construct authorization client config based on settings
// with the remaining options defaulted, e.g. authorization request timeout
web::http::client::http_client_config make_authorization_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, authorization_config_handler make_authorization_config, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate)
web::http::client::http_client_config make_authorization_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate)
{
auto config = nmos::make_http_client_config(settings, load_ca_certificates, make_authorization_config, bearer_token, gate);
auto config = nmos::make_http_client_config(settings, load_ca_certificates, bearer_token, gate);
config.set_timeout(std::chrono::seconds(nmos::experimental::fields::authorization_request_max(settings)));

return config;
Expand Down Expand Up @@ -1323,7 +1323,7 @@ namespace nmos
const auto& registration_client_uri = nmos::experimental::fields::registration_client_uri(client_metadata);
const auto& issuer = nmos::experimental::fields::issuer(authorization_server_metadata);

request = request_client_metadata_from_openid_connect(web::http::client::http_client(registration_client_uri, make_authorization_http_client_config(model.settings, load_ca_certificates, make_authorization_config_handler(authorization_server_metadata, client_metadata, gate), { registration_access_token }, gate)),
request = request_client_metadata_from_openid_connect(web::http::client::http_client(registration_client_uri, make_authorization_http_client_config(model.settings, load_ca_certificates, { registration_access_token }, gate)),
auth_version, gate, token).then([&model, &authorization_state, issuer, save_authorization_client, &gate](web::json::value client_metadata)
{
auto lock = model.write_lock();
Expand Down Expand Up @@ -1474,7 +1474,7 @@ namespace nmos
const auto jwks_uri = make_jwks_uri(model.settings);
const auto& initial_access_token = nmos::experimental::fields::initial_access_token(model.settings);

request = request_client_registration(web::http::client::http_client(registration_endpoint, make_authorization_http_client_config(model.settings, load_ca_certificates, make_authorization_config_handler({}, {}, gate), { initial_access_token }, gate)),
request = request_client_registration(web::http::client::http_client(registration_endpoint, make_authorization_http_client_config(model.settings, load_ca_certificates, { initial_access_token }, gate)),
client_name, redirect_uris, {}, response_types, scopes, grants, token_endpoint_auth_method, {}, jwks_uri, auth_version, gate, token).then([&model, &authorization_state, issuer, token_endpoint_auth_method, save_authorization_client, &gate](web::json::value client_metadata)
{
auto lock = model.write_lock();
Expand Down
5 changes: 3 additions & 2 deletions Development/nmos/authorization_operation.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ namespace nmos

namespace details
{

// construct authorization client config based on settings
// with the remaining options defaulted, e.g. authorization request timeout
web::http::client::http_client_config make_authorization_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, authorization_config_handler make_authorization_config, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate);
web::http::client::http_client_config make_authorization_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate);
inline web::http::client::http_client_config make_authorization_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, slog::base_gate& gate)
{
return make_authorization_http_client_config(settings, load_ca_certificates, {}, {}, gate);
return make_authorization_http_client_config(settings, load_ca_certificates, {}, gate);
}

// verify the redirect URI and make an asynchronously POST request on the Authorization API to exchange authorization code for bearer token
Expand Down
35 changes: 20 additions & 15 deletions Development/nmos/client_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -179,36 +179,41 @@ namespace nmos
return make_http_client_config(nmos::experimental::fields::client_secure(settings), settings, load_ca_certificates, gate);
}

// construct client config including OAuth 2.0 config based on settings, e.g. using the specified proxy
// construct oauth2 config with the bearer token
web::http::oauth2::experimental::oauth2_config make_oauth2_config(const web::http::oauth2::experimental::oauth2_token& bearer_token)
{
web::http::oauth2::experimental::oauth2_config config(U(""), U(""), U(""), U(""), U(""), U(""));
config.set_token(bearer_token);

return config;
}

// construct client config including OAuth 2.0 config based on settings, e.g. using the specified proxy and OCSP config
// with the remaining options defaulted, e.g. authorization request timeout
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::authorization_config_handler make_authorization_config, slog::base_gate& gate)
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate)
{
auto config = make_http_client_config(settings, load_ca_certificates, gate);

if (make_authorization_config)
if (bearer_token.is_valid_access_token())
{
auto oauth2_config = make_authorization_config({});
if (oauth2_config.token().is_valid_access_token())
{
config.set_oauth2(make_authorization_config({}));
}
config.set_oauth2(make_oauth2_config(bearer_token));
}

return config;
}

// construct client config including OAuth 2.0 config based on settings, e.g. using the specified proxy
// construct client config including OAuth 2.0 config based on settings, e.g. using the specified proxy and OCSP config
// with the remaining options defaulted, e.g. authorization request timeout
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::authorization_config_handler make_authorization_config, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate)
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::get_authorization_bearer_token_handler get_authorization_bearer_token, slog::base_gate& gate)
{
auto config = make_http_client_config(settings, load_ca_certificates, gate);
web::http::oauth2::experimental::oauth2_token bearer_token;

if (make_authorization_config && bearer_token.is_valid_access_token())
if (get_authorization_bearer_token)
{
config.set_oauth2(make_authorization_config(bearer_token));
bearer_token = get_authorization_bearer_token();
}

return config;
return make_http_client_config(settings, load_ca_certificates, bearer_token, gate);
}

// construct client config based on specified secure flag and settings, e.g. using the specified proxy
Expand Down Expand Up @@ -238,7 +243,7 @@ namespace nmos

// construct client config based on settings and access token, e.g. using the specified proxy
// with the remaining options defaulted
web::websockets::client::websocket_client_config make_websocket_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::authorization_token_handler get_authorization_bearer_token, slog::base_gate& gate)
web::websockets::client::websocket_client_config make_websocket_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::get_authorization_bearer_token_handler get_authorization_bearer_token, slog::base_gate& gate)
{
auto config = make_websocket_client_config(settings, std::move(load_ca_certificates), gate);

Expand Down
8 changes: 5 additions & 3 deletions Development/nmos/client_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,18 @@ namespace nmos
web::http::client::http_client_config make_http_client_config(bool secure, const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, slog::base_gate& gate);
// construct client config based on settings, e.g. using the specified proxy and OCSP config
// with the remaining options defaulted, e.g. request timeout
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::authorization_config_handler make_authorization_config, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate);
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::authorization_config_handler make_authorization_config, slog::base_gate& gate);
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, slog::base_gate& gate);
// construct client config including OAuth 2.0 config based on settings, e.g. using the specified proxy and OCSP config
// with the remaining options defaulted, e.g. authorization request timeout
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, const web::http::oauth2::experimental::oauth2_token& bearer_token, slog::base_gate& gate);
web::http::client::http_client_config make_http_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::get_authorization_bearer_token_handler get_authorization_bearer_token, slog::base_gate& gate);

// construct client config based on specified secure flag and settings, e.g. using the specified proxy
// with the remaining options defaulted
web::websockets::client::websocket_client_config make_websocket_client_config(bool secure, const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, slog::base_gate& gate);
// construct client config based on settings, e.g. using the specified proxy
// with the remaining options defaulted
web::websockets::client::websocket_client_config make_websocket_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::authorization_token_handler get_authorization_bearer_token, slog::base_gate& gate);
web::websockets::client::websocket_client_config make_websocket_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, nmos::experimental::get_authorization_bearer_token_handler get_authorization_bearer_token, slog::base_gate& gate);
web::websockets::client::websocket_client_config make_websocket_client_config(const nmos::settings& settings, load_ca_certificates_handler load_ca_certificates, slog::base_gate& gate);

// make an API request with logging
Expand Down
Loading

0 comments on commit 311bed6

Please sign in to comment.