2424#include < boost/algorithm/string.hpp>
2525#include < chrono>
2626#include < future>
27+ #include < mutex>
2728#include < sstream>
2829#include < stdexcept>
2930#ifdef USE_ASIO
@@ -542,6 +543,8 @@ TEST(AuthPluginTest, testAuthFactoryAthenz) {
542543}
543544
544545namespace testOauth2Tls {
546+ static const auto mockServerTimeout = std::chrono::seconds(10 );
547+
545548class MockOauth2Server {
546549 public:
547550 MockOauth2Server (const std::string& responseBody, const std::string& responseContentType, int listenPort,
@@ -563,23 +566,57 @@ class MockOauth2Server {
563566 const std::string& request () const { return request_; }
564567
565568 bool mockServe () {
566- ASIO ::ip::tcp::socket socket (io_);
567- acceptor_.accept (socket);
568569 ASIO_ERROR error;
569- ASIO ::ssl::stream<ASIO ::ip::tcp::socket&> sslStream (socket, sslCtx_);
570+ auto socket = std::make_shared<ASIO ::ip::tcp::socket>(io_);
571+ {
572+ std::lock_guard<std::mutex> lock (mutex_);
573+ activeSocket_ = socket;
574+ }
575+
576+ acceptor_.accept (*socket, error);
577+ if (error) {
578+ clearActiveSocket ();
579+ return false ;
580+ }
581+
582+ ASIO ::ssl::stream<ASIO ::ip::tcp::socket&> sslStream (*socket, sslCtx_);
570583 sslStream.handshake (ASIO ::ssl::stream_base::server, error);
571- if (error) return false ;
572- if (!readRequest (sslStream)) return false ;
584+ if (error || !readRequest (sslStream)) {
585+ clearActiveSocket ();
586+ return false ;
587+ }
573588
574- const std::string response = " HTTP/1.1 200 OK\n Content-Type: " + responseContentType_ +
575- " \n Content-Length: " + std::to_string (responseBody_.size ()) +
576- " \n Connection: close\n \n " + responseBody_;
589+ const std::string response = " HTTP/1.1 200 OK\r\ n Content-Type: " + responseContentType_ +
590+ " \r\ n Content-Length: " + std::to_string (responseBody_.size ()) +
591+ " \r\ n Connection: close\r\n\r \n " + responseBody_;
577592 ASIO::write (sslStream, ASIO::buffer (response.data (), response.size ()), error);
593+ clearActiveSocket ();
578594 if (error) return false ;
579595 return true ;
580596 }
581597
598+ void stop () {
599+ ASIO_ERROR error;
600+ {
601+ std::lock_guard<std::mutex> lock (mutex_);
602+ if (acceptor_.is_open ()) {
603+ acceptor_.close (error);
604+ }
605+ if (activeSocket_ && activeSocket_->is_open ()) {
606+ activeSocket_->cancel (error);
607+ activeSocket_->shutdown (ASIO ::ip::tcp::socket::shutdown_both, error);
608+ activeSocket_->close (error);
609+ }
610+ }
611+ io_.stop ();
612+ }
613+
582614 private:
615+ void clearActiveSocket () {
616+ std::lock_guard<std::mutex> lock (mutex_);
617+ activeSocket_.reset ();
618+ }
619+
583620 bool readRequest (ASIO ::ssl::stream<ASIO ::ip::tcp::socket&>& sslStream) {
584621 SocketStream<ASIO ::ssl::stream<ASIO ::ip::tcp::socket&>> stream (sslStream);
585622 request_.clear ();
@@ -615,8 +652,30 @@ class MockOauth2Server {
615652 ASIO ::io_context io_;
616653 ASIO ::ip::tcp::acceptor acceptor_;
617654 ASIO ::ssl::context sslCtx_;
655+ std::shared_ptr<ASIO ::ip::tcp::socket> activeSocket_;
656+ std::mutex mutex_;
618657};
619658
659+ static bool awaitMockServeResult (std::future<bool >& future, MockOauth2Server& server, std::thread& thread,
660+ const char * serverName) {
661+ if (future.wait_for (mockServerTimeout) != std::future_status::ready) {
662+ server.stop ();
663+ if (thread.joinable ()) {
664+ thread.join ();
665+ }
666+ ADD_FAILURE () << serverName << " did not complete within "
667+ << std::chrono::duration_cast<std::chrono::seconds>(mockServerTimeout).count ()
668+ << " seconds" ;
669+ return false ;
670+ }
671+
672+ const bool result = future.get ();
673+ if (thread.joinable ()) {
674+ thread.join ();
675+ }
676+ return result;
677+ }
678+
620679} // namespace testOauth2Tls
621680
622681TEST (AuthPluginTest, testOauth2) {
@@ -821,13 +880,13 @@ TEST(AuthPluginTest, testOauth2TlsClientAuth) {
821880 ASSERT_TRUE (data->hasDataFromCommand ());
822881 ASSERT_EQ (data->getCommandData (), " mockToken" );
823882
824- ASSERT_TRUE (wellKnownFuture.get ());
825- ASSERT_TRUE (tokenFuture.get ());
883+ ASSERT_TRUE (testOauth2Tls::awaitMockServeResult (wellKnownFuture, *wellKnownServer, wellKnownThread,
884+ " Well-known mock server" ));
885+ ASSERT_TRUE (
886+ testOauth2Tls::awaitMockServeResult (tokenFuture, *tokenServer, tokenThread, " Token mock server" ));
826887 ASSERT_NE (wellKnownServer->request ().find (" GET /.well-known/openid-configuration " ), std::string::npos);
827888 ASSERT_NE (tokenServer->request ().find (" POST /oauth/token " ), std::string::npos);
828889 ASSERT_NE (tokenServer->request ().find (" grant_type=client_credentials" ), std::string::npos);
829- wellKnownThread.join ();
830- tokenThread.join ();
831890}
832891
833892TEST (AuthPluginTest, testOauth2TlsClientAuthWrongCert) {
@@ -878,11 +937,11 @@ TEST(AuthPluginTest, testOauth2TlsClientAuthWrongCert) {
878937 AuthenticationPtr auth = AuthOauth2::create (params);
879938 ASSERT_EQ (auth->getAuthData (data), ResultAuthenticationError);
880939
881- ASSERT_TRUE (wellKnownFuture.get ());
882- ASSERT_FALSE (tokenFuture.get ());
940+ ASSERT_TRUE (testOauth2Tls::awaitMockServeResult (wellKnownFuture, *wellKnownServer, wellKnownThread,
941+ " Well-known mock server" ));
942+ ASSERT_FALSE (
943+ testOauth2Tls::awaitMockServeResult (tokenFuture, *tokenServer, tokenThread, " Token mock server" ));
883944 ASSERT_NE (wellKnownServer->request ().find (" GET /.well-known/openid-configuration " ), std::string::npos);
884- wellKnownThread.join ();
885- tokenThread.join ();
886945}
887946
888947TEST (AuthPluginTest, testOauth2TlsClientAuthRequestBody) {
@@ -953,6 +1012,11 @@ TEST(AuthPluginTest, testOauth2TlsClientAuthFailure) {
9531012 params.erase (" tls_key_file" );
9541013 ASSERT_EQ (getAuthDataResult (), ResultAuthenticationError);
9551014
1015+ // Only cert
1016+ params[" tls_cert_file" ] = clientPublicKeyPath;
1017+ params.erase (" tls_key_file" );
1018+ ASSERT_EQ (getAuthDataResult (), ResultAuthenticationError);
1019+
9561020 // Invalid cert and key
9571021 params[" tls_cert_file" ] = TEST_CONF_DIR " /not-exist-cert.pem" ;
9581022 params[" tls_key_file" ] = TEST_CONF_DIR " /not-exist-key.pem" ;
0 commit comments