1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
/* SPDX-License-Identifier: MPL-2.0 */
#include "testutil.hpp"
#include "testutil_unity.hpp"
#include <stdlib.h>
#include <string.h>
static void zap_handler (void *zap_)
{
// Process ZAP requests forever
while (true) {
char *version = s_recv (zap_);
if (!version)
break; // Terminating
char *sequence = s_recv (zap_);
char *domain = s_recv (zap_);
char *address = s_recv (zap_);
char *routing_id = s_recv (zap_);
char *mechanism = s_recv (zap_);
char *username = s_recv (zap_);
char *password = s_recv (zap_);
TEST_ASSERT_EQUAL_STRING ("1.0", version);
TEST_ASSERT_EQUAL_STRING ("PLAIN", mechanism);
TEST_ASSERT_EQUAL_STRING ("IDENT", routing_id);
send_string_expect_success (zap_, version, ZMQ_SNDMORE);
send_string_expect_success (zap_, sequence, ZMQ_SNDMORE);
if (streq (username, "admin") && streq (password, "password")) {
send_string_expect_success (zap_, "200", ZMQ_SNDMORE);
send_string_expect_success (zap_, "OK", ZMQ_SNDMORE);
send_string_expect_success (zap_, "anonymous", ZMQ_SNDMORE);
send_string_expect_success (zap_, "", 0);
} else {
send_string_expect_success (zap_, "400", ZMQ_SNDMORE);
send_string_expect_success (zap_, "Invalid username or password",
ZMQ_SNDMORE);
send_string_expect_success (zap_, "", ZMQ_SNDMORE);
send_string_expect_success (zap_, "", 0);
}
free (version);
free (sequence);
free (domain);
free (address);
free (routing_id);
free (mechanism);
free (username);
free (password);
}
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (zap_));
}
void *zap_thread;
char my_endpoint[MAX_SOCKET_STRING];
static void setup_zap_handler ()
{
// Spawn ZAP handler
// We create and bind ZAP socket in main thread to avoid case
// where child thread does not start up fast enough.
void *handler = zmq_socket (get_test_context (), ZMQ_REP);
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01"));
zap_thread = zmq_threadstart (&zap_handler, handler);
}
static void teardown_zap_handler ()
{
// Wait until ZAP handler terminates
zmq_threadclose (zap_thread);
}
const char domain[] = "test";
void *server;
static void setup_server ()
{
// Server socket will accept connections
server = test_context_socket (ZMQ_DEALER);
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (server, ZMQ_ROUTING_ID, "IDENT", 6));
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, domain, strlen (domain)));
const int as_server = 1;
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (server, ZMQ_PLAIN_SERVER, &as_server, sizeof (int)));
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
}
static void teardown_server ()
{
test_context_socket_close (server);
}
void setUp ()
{
setup_test_context ();
setup_zap_handler ();
setup_server ();
}
void tearDown ()
{
teardown_server ();
teardown_test_context ();
teardown_zap_handler ();
}
void test_plain_success ()
{
// Check PLAIN security with correct username/password
void *client = test_context_socket (ZMQ_DEALER);
const char username[] = "admin";
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username)));
const char password[] = "password";
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password)));
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
bounce (server, client);
test_context_socket_close (client);
}
void test_plain_client_as_server_fails ()
{
// Check PLAIN security with badly configured client (as_server)
// This will be caught by the plain_server class, not passed to ZAP
void *client = test_context_socket (ZMQ_DEALER);
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (client, ZMQ_ZAP_DOMAIN, domain, strlen (domain)));
const int as_server = 1;
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (client, ZMQ_PLAIN_SERVER, &as_server, sizeof (int)));
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
expect_bounce_fail (server, client);
test_context_socket_close_zero_linger (client);
}
void test_plain_wrong_credentials_fails ()
{
// Check PLAIN security -- failed authentication
void *client = test_context_socket (ZMQ_DEALER);
const char username[] = "wronguser";
const char password[] = "wrongpass";
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username)));
TEST_ASSERT_SUCCESS_ERRNO (
zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password)));
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
expect_bounce_fail (server, client);
test_context_socket_close_zero_linger (client);
}
void test_plain_vanilla_socket ()
{
// Unauthenticated messages from a vanilla socket shouldn't be received
fd_t s = connect_socket (my_endpoint);
// send anonymous ZMTP/1.0 greeting
send (s, "\x01\x00", 2, 0);
// send sneaky message that shouldn't be received
send (s, "\x08\x00sneaky\0", 9, 0);
int timeout = 250;
zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
char *buf = s_recv (server);
if (buf != NULL) {
printf ("Received unauthenticated message: %s\n", buf);
TEST_ASSERT_NULL (buf);
}
close (s);
}
int main (void)
{
setup_test_environment ();
UNITY_BEGIN ();
RUN_TEST (test_plain_success);
RUN_TEST (test_plain_client_as_server_fails);
RUN_TEST (test_plain_wrong_credentials_fails);
RUN_TEST (test_plain_vanilla_socket);
return UNITY_END ();
}
|