253 lines
7 KiB
C++
253 lines
7 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.
|
|
*
|
|
* ==--==
|
|
* =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
|
|
*
|
|
* authentication_tests.cpp
|
|
*
|
|
* Tests cases for covering authentication using websocket_client
|
|
*
|
|
* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
|
****/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#if defined(__cplusplus_winrt) || !defined(_M_ARM)
|
|
|
|
using namespace web::websockets;
|
|
using namespace web::websockets::client;
|
|
|
|
using namespace tests::functional::websocket::utilities;
|
|
|
|
namespace tests { namespace functional { namespace websocket { namespace client {
|
|
|
|
SUITE(authentication_tests)
|
|
{
|
|
|
|
// Authorization not implemented in non WinRT websocket_client yet - CodePlex 254
|
|
#if defined(__cplusplus_winrt)
|
|
void auth_helper(test_websocket_server& server, const utility::string_t &username = U(""), const utility::string_t &password = U(""))
|
|
{
|
|
server.set_http_handler([username, password](test_http_request request)
|
|
{
|
|
test_http_response resp;
|
|
if (request->username().empty()) // No credentials -> challenge the request
|
|
{
|
|
resp.set_status_code(401); // Unauthorized.
|
|
resp.set_realm("My Realm");
|
|
}
|
|
else if (request->username().compare(utility::conversions::to_utf8string(username))
|
|
|| request->password().compare(utility::conversions::to_utf8string(password)))
|
|
{
|
|
resp.set_status_code(403); // User name/password did not match: Forbidden - auth failure.
|
|
}
|
|
else
|
|
{
|
|
resp.set_status_code(200); // User name and passwords match. Successful auth.
|
|
}
|
|
return resp;
|
|
});
|
|
}
|
|
|
|
// connect without credentials, when the server expects credentials
|
|
TEST_FIXTURE(uri_address, auth_no_credentials, "Ignore", "245")
|
|
{
|
|
test_websocket_server server;
|
|
websocket_client client;
|
|
auth_helper(server);
|
|
VERIFY_THROWS(client.connect(m_uri).wait(), websocket_exception);
|
|
}
|
|
|
|
// Connect with credentials
|
|
TEST_FIXTURE(uri_address, auth_with_credentials, "Ignore", "245")
|
|
{
|
|
test_websocket_server server;
|
|
websocket_client_config config;
|
|
web::credentials cred(U("user"), U("password"));
|
|
config.set_credentials(cred);
|
|
websocket_client client(config);
|
|
|
|
auth_helper(server, cred.username(), U("password"));
|
|
client.connect(m_uri).wait();
|
|
client.close().wait();
|
|
}
|
|
#endif
|
|
|
|
// helper function to check if failure is due to timeout.
|
|
bool is_timeout(const std::string &msg)
|
|
{
|
|
if (msg.find("set_fail_handler") != std::string::npos)
|
|
{
|
|
if (msg.find("handshake timed out") != std::string::npos || msg.find("Timer Expired") != std::string::npos)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
TEST(ssl_test)
|
|
{
|
|
websocket_client client;
|
|
std::string body_str("hello");
|
|
|
|
try
|
|
{
|
|
client.connect(U("wss://echo.websocket.org/")).wait();
|
|
auto receive_task = client.receive().then([body_str](websocket_incoming_message ret_msg)
|
|
{
|
|
VERIFY_ARE_EQUAL(ret_msg.length(), body_str.length());
|
|
auto ret_str = ret_msg.extract_string().get();
|
|
|
|
VERIFY_ARE_EQUAL(body_str.compare(ret_str), 0);
|
|
VERIFY_ARE_EQUAL(ret_msg.message_type(), websocket_message_type::text_message);
|
|
});
|
|
|
|
websocket_outgoing_message msg;
|
|
msg.set_utf8_message(body_str);
|
|
client.send(msg).wait();
|
|
|
|
receive_task.wait();
|
|
client.close().wait();
|
|
}
|
|
catch (const websocket_exception &e)
|
|
{
|
|
if (is_timeout(e.what()))
|
|
{
|
|
// Since this test depends on an outside server sometimes it sporadically can fail due to timeouts
|
|
// especially on our build machines.
|
|
return;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// These tests are specific to our websocketpp based implementation.
|
|
#if !defined(__cplusplus_winrt)
|
|
|
|
void sni_test_impl(websocket_client &client)
|
|
{
|
|
try
|
|
{
|
|
client.connect(U("wss://jabbr.net")).wait();
|
|
|
|
// Should never be reached.
|
|
VERIFY_IS_TRUE(false);
|
|
}
|
|
catch (const websocket_exception &e)
|
|
{
|
|
if (is_timeout(e.what()))
|
|
{
|
|
// Since this test depends on an outside server sometimes it sporadically can fail due to timeouts
|
|
// especially on our build machines.
|
|
return;
|
|
}
|
|
|
|
// This test just covers establishing the TLS connection and verifying
|
|
// the server certificate, expect it to return an unexpected HTTP status code.
|
|
if (e.error_code().value() == 20)
|
|
{
|
|
return;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// Test specifically for server SignalR team hit interesting cases with.
|
|
TEST(sni_with_older_server_test)
|
|
{
|
|
websocket_client client;
|
|
sni_test_impl(client);
|
|
}
|
|
|
|
// WinRT doesn't expose option for disabling.
|
|
TEST(disable_sni)
|
|
{
|
|
websocket_client_config config;
|
|
config.disable_sni();
|
|
websocket_client client(config);
|
|
|
|
try
|
|
{
|
|
client.connect(U("wss://jabbr.net")).wait();
|
|
|
|
// Should never be reached.
|
|
VERIFY_IS_TRUE(false);
|
|
}
|
|
catch (const websocket_exception &e)
|
|
{
|
|
// Should fail for a reason different than invalid HTTP status.
|
|
if (e.error_code().value() != 20)
|
|
{
|
|
return;
|
|
}
|
|
throw;
|
|
}
|
|
}
|
|
|
|
// Winrt doesn't allow explicitly setting server host for SNI.
|
|
TEST(sni_explicit_hostname)
|
|
{
|
|
websocket_client_config config;
|
|
const auto &name = utf8string("jabbr.net");
|
|
config.set_server_name(name);
|
|
VERIFY_ARE_EQUAL(name, config.server_name());
|
|
websocket_client client(config);
|
|
sni_test_impl(client);
|
|
}
|
|
|
|
void handshake_error_test_impl(const ::utility::string_t &host)
|
|
{
|
|
websocket_client client;
|
|
try
|
|
{
|
|
client.connect(host).wait();
|
|
VERIFY_IS_TRUE(false);
|
|
}
|
|
catch (const websocket_exception &e)
|
|
{
|
|
if (is_timeout(e.what()))
|
|
{
|
|
// Since this test depends on an outside server sometimes it sporadically can fail due to timeouts
|
|
// especially on our build machines.
|
|
return;
|
|
}
|
|
VERIFY_ARE_EQUAL("TLS handshake failed", e.error_code().message());
|
|
}
|
|
}
|
|
|
|
TEST(self_signed_cert)
|
|
{
|
|
handshake_error_test_impl(U("wss://www.pcwebshop.co.uk/"));
|
|
}
|
|
|
|
TEST(hostname_mismatch)
|
|
{
|
|
handshake_error_test_impl(U("wss://swordsoftruth.com/"));
|
|
}
|
|
|
|
TEST(cert_expired)
|
|
{
|
|
handshake_error_test_impl(U("wss://tv.eurosport.com/"));
|
|
}
|
|
|
|
#endif
|
|
|
|
} // SUITE(authentication_tests)
|
|
|
|
}}}}
|
|
|
|
#endif
|