blob: e6aa4cb3d50d18ef063819d75df11d8ac1034738 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
#ifdef THREADED
#include <cppunit/extensions/HelperMacros.h>
#include "CppAssertHelper.h"
#include <sys/socket.h>
#include <unistd.h>
#include <zookeeper.h>
#include "Util.h"
#include "WatchUtil.h"
class Zookeeper_SASLAuth : public CPPUNIT_NS::TestFixture {
CPPUNIT_TEST_SUITE(Zookeeper_SASLAuth);
CPPUNIT_TEST(testServerRequireClientSASL);
#ifdef HAVE_CYRUS_SASL_H
CPPUNIT_TEST(testClientSASL);
#ifdef ZOO_IPV6_ENABLED
CPPUNIT_TEST(testClientSASLOverIPv6);
#endif/* ZOO_IPV6_ENABLED */
CPPUNIT_TEST(testClientSASLReadOnly);
CPPUNIT_TEST(testClientSASLPacketOrder);
#endif /* HAVE_CYRUS_SASL_H */
CPPUNIT_TEST_SUITE_END();
FILE *logfile;
static const char hostPorts[];
static const char jaasConf[];
static void watcher(zhandle_t *, int type, int state, const char *path,void*v){
watchctx_t *ctx = (watchctx_t*)v;
if (state == ZOO_CONNECTED_STATE || state == ZOO_READONLY_STATE) {
ctx->connected = true;
} else {
ctx->connected = false;
}
if (type != ZOO_SESSION_EVENT) {
evt_t evt;
evt.path = path;
evt.type = type;
ctx->putEvent(evt);
}
}
public:
Zookeeper_SASLAuth() {
logfile = openlogfile("Zookeeper_SASLAuth");
}
~Zookeeper_SASLAuth() {
if (logfile) {
fflush(logfile);
fclose(logfile);
logfile = 0;
}
}
void setUp() {
zoo_set_log_stream(logfile);
// Create SASL configuration file for server.
FILE *conff = fopen("Zookeeper_SASLAuth.jaas.conf", "wt");
CPPUNIT_ASSERT(conff);
size_t confLen = strlen(jaasConf);
CPPUNIT_ASSERT_EQUAL(fwrite(jaasConf, 1, confLen, conff), confLen);
CPPUNIT_ASSERT_EQUAL(fclose(conff), 0);
conff = NULL;
// Create password file for client.
FILE *passf = fopen("Zookeeper_SASLAuth.password", "wt");
CPPUNIT_ASSERT(passf);
CPPUNIT_ASSERT(fputs("mypassword", passf) > 0);
CPPUNIT_ASSERT_EQUAL(fclose(passf), 0);
passf = NULL;
}
void startServer(bool useJaasConf = true, bool readOnly = false) {
char cmd[1024];
sprintf(cmd, "%s startRequireSASLAuth %s %s",
ZKSERVER_CMD,
useJaasConf ? "Zookeeper_SASLAuth.jaas.conf" : "",
readOnly ? "true" : "");
CPPUNIT_ASSERT(system(cmd) == 0);
}
void stopServer() {
char cmd[1024];
sprintf(cmd, "%s stop", ZKSERVER_CMD);
CPPUNIT_ASSERT(system(cmd) == 0);
}
void testServerRequireClientSASL() {
startServer(false);
watchctx_t ctx;
int rc = 0;
zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0, &ctx, 0);
ctx.zh = zk;
CPPUNIT_ASSERT(zk);
// Wait for handle to be connected.
CPPUNIT_ASSERT(ctx.waitForConnected(zk));
char pathbuf[80];
struct Stat stat_a = {0};
rc = zoo_create2(zk, "/serverRequireClientSASL", "", 0,
&ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, sizeof(pathbuf), &stat_a);
CPPUNIT_ASSERT_EQUAL((int)ZSESSIONCLOSEDREQUIRESASLAUTH, rc);
stopServer();
}
#ifdef HAVE_CYRUS_SASL_H
void testClientSASLHelper(const char *hostPorts, const char *path) {
startServer();
// Initialize Cyrus SASL.
CPPUNIT_ASSERT_EQUAL(sasl_client_init(NULL), SASL_OK);
// Initialize SASL parameters.
zoo_sasl_params_t sasl_params = { 0 };
sasl_params.service = "zookeeper";
sasl_params.host = "zk-sasl-md5";
sasl_params.mechlist = "DIGEST-MD5";
sasl_params.callbacks = zoo_sasl_make_basic_callbacks(
"myuser", NULL, "Zookeeper_SASLAuth.password");
// Connect.
watchctx_t ctx;
int rc = 0;
zhandle_t *zk = zookeeper_init_sasl(hostPorts, watcher, 10000, NULL,
&ctx, /*flags*/0, /*log_callback*/NULL, &sasl_params);
ctx.zh = zk;
CPPUNIT_ASSERT(zk);
// Wait for SASL auth to complete and handle to be connected.
CPPUNIT_ASSERT(ctx.waitForConnected(zk));
// Leave mark.
char pathbuf[80];
struct Stat stat_a = {0};
rc = zoo_create2(zk, path, "", 0,
&ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, sizeof(pathbuf), &stat_a);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
// Stop and restart the server to test automatic reconnect & re-auth.
stopServer();
CPPUNIT_ASSERT(ctx.waitForDisconnected(zk));
startServer();
// Wait for automatic SASL re-auth to complete.
CPPUNIT_ASSERT(ctx.waitForConnected(zk));
// Check mark left above.
rc = zoo_exists(zk, path, /*watch*/false, &stat_a);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
stopServer();
}
void testClientSASL() {
testClientSASLHelper(hostPorts, "/clientSASL");
}
void testClientSASLOverIPv6() {
const char *ipAndPort = "::1:22181";
testClientSASLHelper(ipAndPort, "/clientSASLOverIPv6");
}
void testClientSASLReadOnly() {
startServer(/*useJaasConf*/ true, /*readOnly*/ true);
// Initialize Cyrus SASL.
CPPUNIT_ASSERT_EQUAL(sasl_client_init(NULL), SASL_OK);
// Initialize SASL parameters.
zoo_sasl_params_t sasl_params = { 0 };
sasl_params.service = "zookeeper";
sasl_params.host = "zk-sasl-md5";
sasl_params.mechlist = "DIGEST-MD5";
sasl_params.callbacks = zoo_sasl_make_basic_callbacks(
"myuser", NULL, "Zookeeper_SASLAuth.password");
// Connect.
watchctx_t ctx;
int rc = 0;
zhandle_t *zk = zookeeper_init_sasl(hostPorts, watcher, 10000, NULL,
&ctx, /*flags*/ZOO_READONLY, /*log_callback*/NULL, &sasl_params);
ctx.zh = zk;
CPPUNIT_ASSERT(zk);
// Wait for SASL auth to complete and handle to be connected.
CPPUNIT_ASSERT(ctx.waitForConnected(zk));
// Assert can read.
char buf[1024];
int len = sizeof(buf);
rc = zoo_get(zk, "/", 0, buf, &len, 0);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
// Assert can not write.
char path[1024];
rc = zoo_create(zk, "/test", "hello", 5, &ZOO_OPEN_ACL_UNSAFE, 0, path, sizeof(path));
CPPUNIT_ASSERT_EQUAL((int)ZNOTREADONLY, rc);
stopServer();
}
void testClientSASLPacketOrder() {
startServer();
// Initialize Cyrus SASL.
CPPUNIT_ASSERT_EQUAL(sasl_client_init(NULL), SASL_OK);
// Initialize SASL parameters.
zoo_sasl_params_t sasl_params = { 0 };
sasl_params.service = "zookeeper";
sasl_params.host = "zk-sasl-md5";
sasl_params.mechlist = "DIGEST-MD5";
sasl_params.callbacks = zoo_sasl_make_basic_callbacks(
"myuser", NULL, "Zookeeper_SASLAuth.password");
// Connect.
watchctx_t ctx;
int rc = 0;
zhandle_t *zk = zookeeper_init_sasl(hostPorts, watcher, 10000, NULL,
&ctx, /*flags*/0, /*log_callback*/NULL, &sasl_params);
ctx.zh = zk;
CPPUNIT_ASSERT(zk);
// No wait: try and queue a packet before SASL auth is complete.
char buf[1024];
int len = sizeof(buf);
rc = zoo_get(zk, "/", 0, buf, &len, 0);
CPPUNIT_ASSERT_EQUAL((int)ZOK, rc);
stopServer();
}
#endif /* HAVE_CYRUS_SASL_H */
};
const char Zookeeper_SASLAuth::hostPorts[] = "127.0.0.1:22181";
const char Zookeeper_SASLAuth::jaasConf[] =
"Server {\n"
" org.apache.zookeeper.server.auth.DigestLoginModule required\n"
" user_myuser=\"mypassword\";\n"
"};\n";
CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_SASLAuth);
#endif /* THREADED */