spectrum2/3rdparty/cpprestsdk/tests/functional/http/client/oauth1_tests.cpp
2015-11-19 15:19:14 +01:00

315 lines
13 KiB
C++

/***
* ==++==
*
* 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<oauth1_config>(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 &parameters = 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<utility::string_t, utility::string_t> 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<utility::string_t, utility::string_t> 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)
}}}}