/*** * ==++== * * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * ==--== * =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ * * Test cases for oauth1. * * =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- ****/ #include "stdafx.h" #include "cpprest/details/http_helpers.h" using namespace web; using namespace web::http; using namespace web::http::client; using namespace web::http::details; using namespace web::http::oauth1::experimental; using namespace web::http::oauth1::details; using namespace utility; using namespace concurrency; using namespace tests::functional::http::utilities; namespace tests { namespace functional { namespace http { namespace client { SUITE(oauth1_tests) { struct oauth1_test_config { oauth1_test_config() : m_server_uri(U("http://localhost:17778/")), m_test_token(U("test_token"), U("test_token_secret")), m_oauth1_config(U("test_key"), U("test_secret"), m_server_uri, m_server_uri, m_server_uri, m_server_uri, oauth1_methods::hmac_sha1), m_oauth1_handler(std::shared_ptr(new oauth1_config(m_oauth1_config))) {} const utility::string_t m_server_uri; const oauth1_token m_test_token; oauth1_config m_oauth1_config; oauth1_handler m_oauth1_handler; }; struct oauth1_token_setup : public oauth1_test_config { oauth1_token_setup() { m_oauth1_config.set_token(m_test_token); } }; struct oauth1_server_setup : public oauth1_test_config { oauth1_server_setup() : m_server(m_server_uri) {} test_http_server::scoped_server m_server; }; #define TEST_ACCESSOR(value_, name_) \ t.set_ ## name_(value_); \ VERIFY_ARE_EQUAL(value_, t.name_()); TEST(oauth1_token_accessors) { oauth1_token t(U(""), U("")); TEST_ACCESSOR(U("a%123"), access_token) TEST_ACCESSOR(U("b%20456"), secret) const auto key1 = U("abc"); const auto value1 = U("123"); const auto key2 = U("xyz"); const auto value2 = U("456"); t.set_additional_parameter(key1, value1); t.set_additional_parameter(U("xyz"), U("456")); const auto ¶meters = t.additional_parameters(); VERIFY_ARE_EQUAL(parameters.at(key1), value1); VERIFY_ARE_EQUAL(parameters.at(key2), value2); t.clear_additional_parameters(); VERIFY_ARE_EQUAL(0, t.additional_parameters().size()); } TEST(oauth1_config_accessors) { oauth1_config t(U(""), U(""), U(""), U(""), U(""), U(""), oauth1_methods::hmac_sha1); TEST_ACCESSOR(U("Test123"), consumer_key) TEST_ACCESSOR(U("bar456"), consumer_secret) TEST_ACCESSOR(U("file:///123?123=a&1="), temp_endpoint) TEST_ACCESSOR(U("x:yxw#0"), auth_endpoint) TEST_ACCESSOR(U("baz:"), token_endpoint) TEST_ACCESSOR(U("/xyzzy=2"), callback_uri) TEST_ACCESSOR(oauth1_methods::plaintext, method) TEST_ACCESSOR(U("wally.world x"), realm) const auto key1 = U("abc"); const auto value1 = U("123"); const auto key2 = U("xyz"); const auto value2 = U("456"); t.add_parameter(key1, value1); t.add_parameter(U("xyz"), U("456")); const auto parameters = t.parameters(); VERIFY_ARE_EQUAL(parameters.at(key1), value1); VERIFY_ARE_EQUAL(parameters.at(key2), value2); t.clear_parameters(); VERIFY_ARE_EQUAL(0, t.parameters().size()); t.set_parameters(parameters); const auto parameters2 = t.parameters(); VERIFY_ARE_EQUAL(parameters2.at(key1), value1); VERIFY_ARE_EQUAL(parameters2.at(key2), value2); } #undef TEST_ACCESSOR TEST_FIXTURE(oauth1_token_setup, oauth1_signature_base_string) { // Basic base string generation. { http_request r; r.set_method(methods::POST); r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); // Port set to avoid default. auto state = m_oauth1_config._generate_auth_state(); state.set_timestamp(U("12345678")); state.set_nonce(U("ABCDEFGH")); utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); utility::string_t correct_base_string(U( "POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_token%26oauth_version%3D1.0" )); VERIFY_ARE_EQUAL(correct_base_string, base_string); } // Added "extra_param" and proper parameter normalization. { http_request r; r.set_method(methods::POST); r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); auto state = m_oauth1_config._generate_auth_state(U("oauth_test"), U("xyzzy")); state.set_timestamp(U("12345678")); state.set_nonce(U("ABCDEFGH")); utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); utility::string_t correct_base_string(U( "POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_test%3Dxyzzy%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_token%26oauth_version%3D1.0" )); VERIFY_ARE_EQUAL(correct_base_string, base_string); } // Use application/x-www-form-urlencoded with parameters in body { http_request r(methods::POST); r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); // Port set to avoid default. r.set_body("MyVariableOne=ValueOne&MyVariableTwo=ValueTwo", "application/x-www-form-urlencoded"); auto state = m_oauth1_config._generate_auth_state(); state.set_timestamp(U("12345678")); state.set_nonce(U("ABCDEFGH")); utility::string_t base_string = m_oauth1_config._build_signature_base_string(r, state); utility::string_t correct_base_string(U( "POST&http%3A%2F%2Fexample.com%2Frequest&a%3Db%26c%3Dd%26MyVariableOne%3DValueOne%26%26MyVariableTwo%3DValueTwo%26oauth_consumer_key%3Dtest_key%26oauth_nonce%3DABCDEFGH%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D12345678%26oauth_token%3Dtest_token%26oauth_version%3D1.0" )); } } TEST_FIXTURE(oauth1_token_setup, oauth1_hmac_sha1_method) { http_request r; r.set_method(methods::POST); r.set_request_uri(U("http://example.com:80/request?a=b&c=d")); // Port set to avoid default. auto state = m_oauth1_config._generate_auth_state(); state.set_timestamp(U("12345678")); state.set_nonce(U("ABCDEFGH")); utility::string_t signature = m_oauth1_config._build_hmac_sha1_signature(r, state); utility::string_t correct_signature(U("iUq3VlP39UNXoJHXlKjgSTmjEs8=")); VERIFY_ARE_EQUAL(correct_signature, signature); } TEST_FIXTURE(oauth1_token_setup, oauth1_plaintext_method) { utility::string_t signature(m_oauth1_config._build_plaintext_signature()); utility::string_t correct_signature(U("test_secret&test_token_secret")); VERIFY_ARE_EQUAL(correct_signature, signature); } TEST_FIXTURE(oauth1_server_setup, oauth1_hmac_sha1_request) { m_oauth1_config.set_token(m_test_token); m_oauth1_config.set_method(oauth1_methods::hmac_sha1); http_client_config client_config; client_config.set_oauth1(m_oauth1_config); http_client client(m_server_uri, client_config); m_server.server()->next_request().then([](test_request *request) { const utility::string_t header_authorization(request->m_headers[header_names::authorization]); const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"test_token\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); request->reply(status_codes::OK); }); VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); http_response response = client.request(methods::GET).get(); VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); } TEST_FIXTURE(oauth1_server_setup, oauth1_plaintext_request) { m_oauth1_config.set_token(m_test_token); m_oauth1_config.set_method(oauth1_methods::plaintext); http_client_config client_config; client_config.set_oauth1(m_oauth1_config); http_client client(m_server_uri, client_config); m_server.server()->next_request().then([](test_request *request) { const utility::string_t header_authorization(request->m_headers[header_names::authorization]); const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"test_token\", oauth_signature_method=\"PLAINTEXT\", oauth_timestamp=\"")); VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); request->reply(status_codes::OK); }); VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); http_response response = client.request(methods::GET).get(); VERIFY_ARE_EQUAL(status_codes::OK, response.status_code()); } TEST_FIXTURE(oauth1_server_setup, oauth1_build_authorization_uri) { m_server.server()->next_request().then([](test_request *request) { const utility::string_t header_authorization(request->m_headers[header_names::authorization]); // Verify prefix, and without 'oauth_token'. const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); // Verify suffix with proper 'oauth_callback'. const utility::string_t suffix(U(", oauth_callback=\"http%3A%2F%2Flocalhost%3A17778%2F\"")); VERIFY_IS_TRUE(std::equal(suffix.rbegin(), suffix.rend(), header_authorization.rbegin())); // Reply with temporary token and secret. std::map headers; headers[header_names::content_type] = mime_types::application_x_www_form_urlencoded; request->reply(status_codes::OK, U(""), headers, "oauth_token=testbar&oauth_token_secret=xyzzy&oauth_callback_confirmed=true"); }); VERIFY_IS_FALSE(m_oauth1_config.token().is_valid_access_token()); utility::string_t auth_uri = m_oauth1_config.build_authorization_uri().get(); VERIFY_ARE_EQUAL(auth_uri, U("http://localhost:17778/?oauth_token=testbar")); VERIFY_IS_FALSE(m_oauth1_config.token().is_valid_access_token()); } // NOTE: This test also covers token_from_verifier(). TEST_FIXTURE(oauth1_server_setup, oauth1_token_from_redirected_uri) { m_server.server()->next_request().then([](test_request *request) { const utility::string_t header_authorization(request->m_headers[header_names::authorization]); // Verify temporary token prefix. const utility::string_t prefix(U("OAuth oauth_version=\"1.0\", oauth_consumer_key=\"test_key\", oauth_token=\"xyzzy\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"")); VERIFY_ARE_EQUAL(0, header_authorization.find(prefix)); // Verify suffix with 'oauth_verifier'. const utility::string_t suffix(U(", oauth_verifier=\"simsalabim\"")); VERIFY_IS_TRUE(std::equal(suffix.rbegin(), suffix.rend(), header_authorization.rbegin())); // Verify we have 'oauth_nonce' and 'oauth_signature'. VERIFY_ARE_NOT_EQUAL(utility::string_t::npos, header_authorization.find(U("oauth_nonce"))); VERIFY_ARE_NOT_EQUAL(utility::string_t::npos, header_authorization.find(U("oauth_signature"))); // Reply with access token and secret. std::map headers; headers[header_names::content_type] = mime_types::application_x_www_form_urlencoded; request->reply(status_codes::OK, U(""), headers, "oauth_token=test&oauth_token_secret=bar"); }); m_oauth1_config.set_token(oauth1_token(U("xyzzy"), U(""))); // Simulate temporary token. const web::http::uri redirected_uri(U("http://localhost:17778/?oauth_token=xyzzy&oauth_verifier=simsalabim")); m_oauth1_config.token_from_redirected_uri(redirected_uri).wait(); VERIFY_IS_TRUE(m_oauth1_config.token().is_valid_access_token()); VERIFY_ARE_EQUAL(m_oauth1_config.token().access_token(), U("test")); VERIFY_ARE_EQUAL(m_oauth1_config.token().secret(), U("bar")); } } // SUITE(oauth1_tests) }}}}