From 708a5df2bb328705622c42f84b4167ea2c7c98c9 Mon Sep 17 00:00:00 2001 From: Ivan Cherniukh Date: Wed, 9 Sep 2020 09:09:04 -0700 Subject: [PATCH 1/2] Add support for oauth2 using only client credentials --- .../cpprest/details/http_constants.dat | 1 + Release/include/cpprest/oauth2.h | 15 ++++ .../functional/http/client/oauth2_tests.cpp | 68 +++++++++++++++++++ 3 files changed, 84 insertions(+) diff --git a/Release/include/cpprest/details/http_constants.dat b/Release/include/cpprest/details/http_constants.dat index c3b1a53cb6..3deb24a146 100644 --- a/Release/include/cpprest/details/http_constants.dat +++ b/Release/include/cpprest/details/http_constants.dat @@ -190,6 +190,7 @@ DAT(expires_in, "expires_in") DAT(grant_type, "grant_type") DAT(redirect_uri, "redirect_uri") DAT(refresh_token, "refresh_token") +DAT(client_credentials, "client_credentials") DAT(response_type, "response_type") DAT(scope, "scope") DAT(state, "state") diff --git a/Release/include/cpprest/oauth2.h b/Release/include/cpprest/oauth2.h index 693ebbe34c..68a7c7b9ab 100644 --- a/Release/include/cpprest/oauth2.h +++ b/Release/include/cpprest/oauth2.h @@ -284,6 +284,21 @@ class oauth2_config return _request_token(ub); } + /// + /// Fetches an access token from the token endpoint using client credentials grant type. + /// The task creates an HTTP request to the token_endpoint() using + /// client authentication as the authorization grant. + /// See: http://tools.ietf.org/html/rfc6749#section-4.4 + /// + /// Task that fetches token(s) using client credentials. + pplx::task token_from_client_credentials() + { + uri_builder ub; + ub.append_query( + details::oauth2_strings::grant_type, details::oauth2_strings::client_credentials, false); + return _request_token(ub); + } + /// /// Returns enabled state of the configuration. /// The oauth2_handler will perform OAuth 2.0 authentication only if diff --git a/Release/tests/functional/http/client/oauth2_tests.cpp b/Release/tests/functional/http/client/oauth2_tests.cpp index e1f5408588..08bb12a652 100644 --- a/Release/tests/functional/http/client/oauth2_tests.cpp +++ b/Release/tests/functional/http/client/oauth2_tests.cpp @@ -291,6 +291,74 @@ SUITE(oauth2_tests) VERIFY_ARE_EQUAL(U("done"), m_oauth2_config.token().access_token()); } + TEST_FIXTURE(oauth2_test_setup, oauth2_token_from_client_credentials) + { + VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); + + m_oauth2_config.set_user_agent(U("test_user_agent")); + + // Fetch using HTTP Basic authentication. + { + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_ARE_EQUAL(request->m_method, methods::POST); + + VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); + + VERIFY_ARE_EQUAL( + U("Basic MTIzQUJDOjQ1NkRFRg=="), + request->m_headers[header_names::authorization]); + + VERIFY_ARE_EQUAL( + to_body_data(U("grant_type=client_credentials")), + request->m_body); + + VERIFY_ARE_EQUAL( + U("test_user_agent"), + get_request_user_agent(request)); + + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply( + status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); + }); + + m_oauth2_config.token_from_client_credentials().wait(); + VERIFY_ARE_EQUAL(U("xyzzy123"), m_oauth2_config.token().access_token()); + VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + } + + // Fetch using client key & secret in request body (x-www-form-urlencoded). + { + m_scoped.server()->next_request().then([](test_request* request) { + VERIFY_IS_TRUE(is_application_x_www_form_urlencoded(request)); + + VERIFY_ARE_EQUAL(U(""), request->m_headers[header_names::authorization]); + + VERIFY_ARE_EQUAL( + to_body_data(U("grant_type=client_credentials&client_id=123ABC&client_secret=456DEF")), + request->m_body); + + VERIFY_ARE_EQUAL(U("test_user_agent"), get_request_user_agent(request)); + + std::map headers; + headers[header_names::content_type] = mime_types::application_json; + request->reply( + status_codes::OK, U(""), headers, "{\"access_token\":\"xyzzy123\",\"token_type\":\"bearer\"}"); + }); + + m_oauth2_config.set_token(oauth2_token()); // Clear token. + VERIFY_IS_FALSE(m_oauth2_config.is_enabled()); + + m_oauth2_config.set_http_basic_auth(false); + m_oauth2_config.token_from_client_credentials().wait(); + + VERIFY_ARE_EQUAL( + U("xyzzy123"), + m_oauth2_config.token().access_token()); + VERIFY_IS_TRUE(m_oauth2_config.is_enabled()); + } + } + TEST_FIXTURE(oauth2_test_setup, oauth2_bearer_token) { m_oauth2_config.set_token(oauth2_token(U("12345678"))); From 8ae5da616dca0beb0c3ac9910c8db64153b33b0d Mon Sep 17 00:00:00 2001 From: Ivan Cherniukh Date: Tue, 15 Dec 2020 13:57:00 -0800 Subject: [PATCH 2/2] Update oauth2.h indentation correction --- Release/include/cpprest/oauth2.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Release/include/cpprest/oauth2.h b/Release/include/cpprest/oauth2.h index 68a7c7b9ab..b1ec324996 100644 --- a/Release/include/cpprest/oauth2.h +++ b/Release/include/cpprest/oauth2.h @@ -295,7 +295,7 @@ class oauth2_config { uri_builder ub; ub.append_query( - details::oauth2_strings::grant_type, details::oauth2_strings::client_credentials, false); + details::oauth2_strings::grant_type, details::oauth2_strings::client_credentials, false); return _request_token(ub); }