From 48ff01e26833f13f0a461d8f19bf4fb095318bef Mon Sep 17 00:00:00 2001 From: Tom Klonikowski Date: Sun, 9 Oct 2011 16:26:00 +0200 Subject: [PATCH] ZOOKEEPER-1112: Add support for C client for SASL authentication Patch #2 2nd patch * provides a simple api for sasl authentication (zoo_sasl_init, zoo_sasl_connect, zoo_sasl_authenticate) * requires libsasl2 (and plugins) * autoconf/make configuration * test for digest-md5 authentication * extended configuration for digest-md5 sasl server required by sasl2 (Forward-ported from https://reviews.apache.org/r/2315/ by Damien Diederen.) --- .../zookeeper-client-c/Makefile.am | 27 +- .../zookeeper-client-c/configure.ac | 17 ++ .../include/zookeeper_sasl.h | 83 ++++++ .../zookeeper-client-c/src/zk_sasl.c | 246 ++++++++++++++++++ .../zookeeper-client-c/tests/TestClient.cc | 84 +++++- .../apache/zookeeper/util/SecurityUtils.java | 11 +- 6 files changed, 457 insertions(+), 11 deletions(-) create mode 100644 zookeeper-client/zookeeper-client-c/include/zookeeper_sasl.h create mode 100644 zookeeper-client/zookeeper-client-c/src/zk_sasl.c diff --git a/zookeeper-client/zookeeper-client-c/Makefile.am b/zookeeper-client/zookeeper-client-c/Makefile.am index a5312a8e9f2..36b51b0e7f6 100644 --- a/zookeeper-client/zookeeper-client-c/Makefile.am +++ b/zookeeper-client/zookeeper-client-c/Makefile.am @@ -18,7 +18,17 @@ endif LIB_LDFLAGS = -no-undefined -version-info 2 $(SOLARIS_LIB_LDFLAGS) -pkginclude_HEADERS = include/zookeeper.h include/zookeeper_version.h include/zookeeper_log.h include/proto.h include/recordio.h generated/zookeeper.jute.h +if WANT_SASL +SASL_CFLAGS = -DSASL +SASL_LIBS = -lsasl2 +SASL_HDR = include/zookeeper_sasl.h +SASL_SRC = src/zk_sasl.c $(SASL_HDR) +else +STATIC_CXX=-DUSE_STATIC_LIB +STATIC_LD=-static-libtool-libs +endif + +pkginclude_HEADERS = include/zookeeper.h include/zookeeper_version.h include/zookeeper_log.h include/proto.h include/recordio.h generated/zookeeper.jute.h $(SASL_HDR) EXTRA_DIST=LICENSE HASHTABLE_SRC = src/hashtable/hashtable_itr.h src/hashtable/hashtable_itr.c \ @@ -31,13 +41,13 @@ COMMON_SRC = src/zookeeper.c include/zookeeper.h include/zookeeper_version.h inc src/recordio.c include/recordio.h include/proto.h \ src/zk_adaptor.h generated/zookeeper.jute.c \ src/zk_log.c src/zk_hashtable.h src/zk_hashtable.c \ - src/addrvec.h src/addrvec.c + src/addrvec.h src/addrvec.c $(SASL_SRC) # These are the symbols (classes, mostly) we want to export from our library. EXPORT_SYMBOLS = '(zoo_|zookeeper_|zhandle|Z|format_log_message|log_message|logLevel|deallocate_|allocate_|zerror|is_unrecoverable)' noinst_LTLIBRARIES += libzkst.la libzkst_la_SOURCES =$(COMMON_SRC) src/st_adaptor.c -libzkst_la_LIBADD = -lm $(CLOCK_GETTIME_LIBS) +libzkst_la_LIBADD = -lm $(CLOCK_GETTIME_LIBS) $(SASL_LIBS) lib_LTLIBRARIES = libzookeeper_st.la libzookeeper_st_la_SOURCES = @@ -49,7 +59,7 @@ if WANT_SYNCAPI noinst_LTLIBRARIES += libzkmt.la libzkmt_la_SOURCES =$(COMMON_SRC) src/mt_adaptor.c libzkmt_la_CFLAGS = -DTHREADED -libzkmt_la_LIBADD = -lm $(CLOCK_GETTIME_LIBS) +libzkmt_la_LIBADD = -lm $(CLOCK_GETTIME_LIBS) $(SASL_LIBS) lib_LTLIBRARIES += libzookeeper_mt.la libzookeeper_mt_la_SOURCES = @@ -62,17 +72,18 @@ bin_PROGRAMS = cli_st cli_st_SOURCES = src/cli.c cli_st_LDADD = libzookeeper_st.la +cli_st_CFLAGS = $(SASL_CFLAGS) if WANT_SYNCAPI bin_PROGRAMS += cli_mt load_gen cli_mt_SOURCES = src/cli.c cli_mt_LDADD = libzookeeper_mt.la -cli_mt_CFLAGS = -DTHREADED +cli_mt_CFLAGS = -DTHREADED $(SASL_CFLAGS) load_gen_SOURCES = src/load_gen.c load_gen_LDADD = libzookeeper_mt.la -load_gen_CFLAGS = -DTHREADED +load_gen_CFLAGS = -DTHREADED $(SASL_CFLAGS) endif @@ -122,14 +133,14 @@ TESTS_ENVIRONMENT = ZKROOT=${srcdir}/../.. \ CLASSPATH=$$CLASSPATH:$$CLOVER_HOME/lib/clover*.jar nodist_zktest_st_SOURCES = $(TEST_SOURCES) zktest_st_LDADD = libzkst.la libhashtable.la $(CPPUNIT_LIBS) -ldl -zktest_st_CXXFLAGS = -DUSE_STATIC_LIB $(CPPUNIT_CFLAGS) $(USEIPV6) $(SOLARIS_CPPFLAGS) +zktest_st_CXXFLAGS = -DUSE_STATIC_LIB $(CPPUNIT_CFLAGS) $(USEIPV6) $(SASL_CFLAGS) $(SOLARIS_CPPFLAGS) zktest_st_LDFLAGS = -shared $(SYMBOL_WRAPPERS) $(SOLARIS_LIB_LDFLAGS) if WANT_SYNCAPI check_PROGRAMS += zktest-mt nodist_zktest_mt_SOURCES = $(TEST_SOURCES) tests/PthreadMocks.cc zktest_mt_LDADD = libzkmt.la libhashtable.la -lpthread $(CPPUNIT_LIBS) -ldl - zktest_mt_CXXFLAGS = -DUSE_STATIC_LIB -DTHREADED $(CPPUNIT_CFLAGS) $(USEIPV6) + zktest_mt_CXXFLAGS = -DUSE_STATIC_LIB -DTHREADED $(CPPUNIT_CFLAGS) $(USEIPV6) $(SASL_CFLAGS) if SOLARIS SHELL_SYMBOL_WRAPPERS_MT = cat ${srcdir}/tests/wrappers-mt.opt SYMBOL_WRAPPERS_MT=$(SYMBOL_WRAPPERS) $(SHELL_SYMBOL_WRAPPERS_MT:sh) diff --git a/zookeeper-client/zookeeper-client-c/configure.ac b/zookeeper-client/zookeeper-client-c/configure.ac index 1ecd17dbf8b..9bff251bbfe 100644 --- a/zookeeper-client/zookeeper-client-c/configure.ac +++ b/zookeeper-client/zookeeper-client-c/configure.ac @@ -111,6 +111,23 @@ fi AM_CONDITIONAL([WANT_SYNCAPI],[test "x$with_syncapi" != xno]) +AC_ARG_WITH([sasl], + [AS_HELP_STRING([--with-sasl],[build with support for SASL [default=yes]])], + [],[with_sasl=yes]) + +AC_CHECK_LIB([sasl2], [sasl_client_init],[have_sasl=yes],[have_sasl=no]) + +if test "x$with_sasl" != xno && test "x$have_sasl" = xno; then + AC_MSG_WARN([cannot build SASL support -- sasl2 not found]) + with_sasl=no +fi +if test "x$with_sasl" != xno; then + AC_MSG_NOTICE([building with SASL support]) +else + AC_MSG_NOTICE([building without SASL support]) +fi +AM_CONDITIONAL([WANT_SASL],[test "x$with_sasl" != xno]) + # Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdlib.h string.h sys/socket.h sys/time.h unistd.h sys/utsname.h]) diff --git a/zookeeper-client/zookeeper-client-c/include/zookeeper_sasl.h b/zookeeper-client/zookeeper-client-c/include/zookeeper_sasl.h new file mode 100644 index 00000000000..7752a402aad --- /dev/null +++ b/zookeeper-client/zookeeper-client-c/include/zookeeper_sasl.h @@ -0,0 +1,83 @@ +/** + * 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. + */ + +#ifndef ZOOKEEPER_SASL_H_ +#define ZOOKEEPER_SASL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief initialize sasl library + * + * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init + * \param callbacks sasl callbacks + * \return ZSYSTEMERROR if initialization failed + */ +ZOOAPI int zoo_sasl_init(zhandle_t *zh, sasl_callback_t *callbacks); + +/** + * \brief creates a sasl connection for the zookeeper socket + * + * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init + * \param servicename name of the zookeeper service + * \param host host of the zookeeper service + * \param sasl_conn out parameter for the created sasl connection + * \param mech out parameter for the sasl mechanisms supported by the client + * \param mechlen out parameter for the count of supported mechs + * \return ZSYSTEMERRROR if connection failed + */ +ZOOAPI int zoo_sasl_connect(zhandle_t *zh, char *servicename, + char *host, zoo_sasl_conn_t **sasl_conn, const char **mechs, int *mechlen); + +/** + * \brief authenticates asynchronously + * + * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init + * \param zh the connection handle obtained by a call to \ref zoo_sasl_connect + * \param mech the selected mechanism + * \param supportedmechs mechanisms supported by client (obtained by a call + * to \ref zoo_sasl_connect) + * \return + */ +ZOOAPI int zoo_asasl_authenticate(zhandle_t *th, zoo_sasl_conn_t *conn, const char *mech, + const char *supportedmechs); + +#ifdef THREADED +/** + * \brief authenticates synchronously + * + * \param zh the zookeeper handle obtained by a call to \ref zookeeper_init + * \param zh the connection handle obtained by a call to \ref zoo_sasl_connect + * \param mech the selected mechanism + * \param supportedmechs mechanisms supported by client (obtained by a call + * to \ref zoo_sasl_connect) + * \return + */ +ZOOAPI int zoo_sasl_authenticate(zhandle_t *th, zoo_sasl_conn_t *conn, const char *mech, + const char *supportedmechs); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ZOOKEEPER_SASL_H_ */ diff --git a/zookeeper-client/zookeeper-client-c/src/zk_sasl.c b/zookeeper-client/zookeeper-client-c/src/zk_sasl.c new file mode 100644 index 00000000000..727528256d3 --- /dev/null +++ b/zookeeper-client/zookeeper-client-c/src/zk_sasl.c @@ -0,0 +1,246 @@ +/** + * 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. + */ + +#include +#include +#include +#include +#include + +#include "zk_adaptor.h" +#include "zookeeper_log.h" +#include "zookeeper_sasl.h" + +#define SAMPLE_SEC_BUF_SIZE (2048) + + +static int sasl_proceed(int sr, zhandle_t *zh, zoo_sasl_conn_t *conn, + const char *clientout, int clientoutlen, int sync); + +static int sasl_auth(zhandle_t *zh, zoo_sasl_conn_t *conn, const char *mech, + const char *supportedmechs, int sync) { + const char *clientout; + const char *chosenmech; + unsigned clientoutlen; + int sr = 0; + + /* + if (supportedmechs) { + serverin = (char *) malloc(strlen(supportedmechs)); + strncpy(serverin, supportedmechs, strlen(supportedmechs)); + } + */ + + if (mech) { + if (!strstr(supportedmechs, mech)) { + LOG_DEBUG(LOGCALLBACK(zh), "client doesn't support mandatory mech '%s'\n", mech); + return ZSYSTEMERROR; + } + } + + sr = sasl_client_start((sasl_conn_t *) conn, mech, NULL, &clientout, &clientoutlen, + &chosenmech); + + LOG_DEBUG(LOGCALLBACK(zh), "SASL Authentication mechanism: %s", chosenmech); + + return sasl_proceed(sr, zh, conn, clientout, clientoutlen, sync); +} + +#ifdef THREADED +int zoo_sasl_authenticate(zhandle_t *zh, zoo_sasl_conn_t *conn, const char *mech, + const char *supportedmechs) { + return sasl_auth(zh, conn, mech, supportedmechs, 1); +} +#endif + +int zoo_asasl_authenticate(zhandle_t *zh, zoo_sasl_conn_t *conn, const char *mech, + const char *supportedmechs) { + return sasl_auth(zh, conn, mech, supportedmechs, 0); +} + +static int sasl_step(int rc, zhandle_t *zh, zoo_sasl_conn_t *conn, int sync, + const char *serverin, int serverinlen) { + const char *clientout; + unsigned clientoutlen; + int sr; + int r = rc; + + if (r != ZOK) { + LOG_ERROR(LOGCALLBACK(zh), "Reading sasl response failed: %d", r); + return r; + } + + sr = sasl_client_step((sasl_conn_t *) conn, serverin, serverinlen, NULL, &clientout, + &clientoutlen); + + return sasl_proceed(sr, zh, conn, clientout, clientoutlen, sync); +} + +static int sasl_step_async(int rc, zhandle_t *zh, zoo_sasl_conn_t *conn, + const char *serverin, int serverinlen) { + return sasl_step(rc, zh, conn, 0, serverin, serverinlen); +} + +static int sasl_complete(int rc, zhandle_t *zh, zoo_sasl_conn_t *conn, + const char *serverin, int serverinlen) { + if (rc != ZOK) { + LOG_ERROR(LOGCALLBACK(zh), "Reading sasl response failed: %d", rc); + return rc; + } + + LOG_DEBUG(LOGCALLBACK(zh), "SASL Authentication complete [%d]", rc); + return rc; +} + +static int sasl_proceed(int sr, zhandle_t *zh, zoo_sasl_conn_t *conn, + const char *clientout, int clientoutlen, int sync) { + int r = ZOK; + if (sr != SASL_OK && sr != SASL_CONTINUE) { + LOG_ERROR(LOGCALLBACK(zh), "starting SASL negotiation: %s %s", + sasl_errstring(sr, NULL, NULL), + sasl_errdetail((sasl_conn_t *) conn)); + return ZSYSTEMERROR; + } + + if (sr == SASL_CONTINUE || clientoutlen > 0) { + if(sync) { +#ifdef THREADED + const char *serverin; + unsigned serverinlen; + + r = zoo_sasl(zh, conn, clientout, clientoutlen, &serverin, &serverinlen); + if (sr == SASL_CONTINUE) { + r = sasl_step(r, zh, conn, sync, serverin, serverinlen); + } else { + r = sasl_complete(r, zh, conn, serverin, serverinlen); + } +#else + LOG_ERROR(LOGCALLBACK(zh), "Sync sasl_proceed used without threads"); + abort(); +#endif + } else { + r = zoo_asasl(zh, conn, clientout, clientoutlen, + (sr == SASL_CONTINUE) ? sasl_step_async : sasl_complete); + } + } + if (r != ZOK) { + LOG_ERROR(LOGCALLBACK(zh), "Sending sasl request failed: %d", r); + return r; + } + return r; +} + +int zoo_sasl_init(zhandle_t *zh, sasl_callback_t *callbacks) { + int rc = sasl_client_init(callbacks); + if (rc != SASL_OK) { + LOG_ERROR(LOGCALLBACK(zh), "initializing libsasl: %s", + sasl_errstring(rc, NULL, NULL)); + rc = ZSYSTEMERROR; + } else { + rc = ZOK; + } + return rc; +} + +int zoo_sasl_connect(zhandle_t *zh, char *servicename, char *host, zoo_sasl_conn_t **sasl_conn, + const char **mechs, int *mechlen) { + char localaddr[NI_MAXHOST + NI_MAXSERV], remoteaddr[NI_MAXHOST + NI_MAXSERV]; + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + int r; + int salen; + int niflags, error; + struct sockaddr_storage local_ip, remote_ip; + sasl_conn_t *conn; + //sasl_security_properties_t secprops; + //sasl_ssf_t extssf = 128; + + /* set ip addresses */ + salen = sizeof(local_ip); + if (getsockname(zh->fd, (struct sockaddr *) &local_ip, + (unsigned *) &salen) < 0) { + LOG_ERROR(LOGCALLBACK(zh), "getsockname"); + return ZSYSTEMERROR; + } + + niflags = (NI_NUMERICHOST | NI_NUMERICSERV); +#ifdef NI_WITHSCOPEID + if (((struct sockaddr *)&local_ip)->sa_family ==AF_INET6) + niflags |= NI_WITHSCOPEID; +#endif + error = getnameinfo((struct sockaddr *) &local_ip, salen, hbuf, + sizeof(hbuf), pbuf, sizeof(pbuf), niflags); + if (error != 0) { + LOG_ERROR(LOGCALLBACK(zh), "getnameinfo: %s\n", gai_strerror(error)); + strcpy(hbuf, "unknown"); + strcpy(pbuf, "unknown"); + return ZSYSTEMERROR; + } + snprintf(localaddr, sizeof(localaddr), "%s;%s", hbuf, pbuf); + + salen = sizeof(remote_ip); + if (getpeername(zh->fd, (struct sockaddr *) &remote_ip, + (unsigned *) &salen) < 0) { + LOG_ERROR(LOGCALLBACK(zh), "getpeername"); + return ZSYSTEMERROR; + } + + niflags = (NI_NUMERICHOST | NI_NUMERICSERV); +#ifdef NI_WITHSCOPEID + if (((struct sockaddr *)&remote_ip)->sa_family == AF_INET6) + niflags |= NI_WITHSCOPEID; +#endif + error = getnameinfo((struct sockaddr *) &remote_ip, salen, hbuf, + sizeof(hbuf), pbuf, sizeof(pbuf), niflags); + if (error != 0) { + LOG_ERROR(LOGCALLBACK(zh), "getnameinfo: %s\n", gai_strerror(error)); + strcpy(hbuf, "unknown"); + strcpy(pbuf, "unknown"); + return ZSYSTEMERROR; + } + snprintf(remoteaddr, sizeof(remoteaddr), "%s;%s", hbuf, pbuf); + + LOG_DEBUG(LOGCALLBACK(zh), "Zookeeper Host: %s %s %s", "ubook", localaddr, remoteaddr); + + /* + memset(&secprops, 0L, sizeof(secprops)); + secprops.maxbufsize = SAMPLE_SEC_BUF_SIZE; + secprops.max_ssf = 2048; + secprops.min_ssf = 128; + */ + + /* client new connection */ + r = sasl_client_new(servicename, host ? host : hbuf, localaddr, remoteaddr, + NULL, 0, &conn); + if (r != SASL_OK) { + LOG_ERROR(LOGCALLBACK(zh), "allocating connection state: %s %s", + sasl_errstring(r, NULL, NULL), sasl_errdetail(conn)); + return ZSYSTEMERROR; + } else { + r = ZOK; + } + + //sasl_setprop(conn, SASL_SSF_EXTERNAL, &extssf); + + //sasl_setprop(conn, SASL_SEC_PROPS, &secprops); + + sasl_listmech(conn, NULL, NULL, " ", NULL, mechs, NULL, mechlen); + + *sasl_conn = (zoo_sasl_conn_t *) conn; + + return r; +} diff --git a/zookeeper-client/zookeeper-client-c/tests/TestClient.cc b/zookeeper-client/zookeeper-client-c/tests/TestClient.cc index 743d481a4b1..8d302054959 100644 --- a/zookeeper-client/zookeeper-client-c/tests/TestClient.cc +++ b/zookeeper-client/zookeeper-client-c/tests/TestClient.cc @@ -41,6 +41,10 @@ using namespace std; #include "Util.h" #include "ZKMocks.h" +#ifdef SASL +#include +#endif + struct buff_struct_2 { int32_t len; int32_t off; @@ -225,7 +229,9 @@ class Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture CPPUNIT_TEST(testGetChildren2); CPPUNIT_TEST(testLastZxid); CPPUNIT_TEST(testRemoveWatchers); +#ifdef SASL CPPUNIT_TEST(testSasl); +#endif #endif CPPUNIT_TEST_SUITE_END(); @@ -511,6 +517,53 @@ class Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture return rc; } +#ifdef SASL + static int saslSimpleCallback(void *context __attribute__((unused)), int id, + const char **result, unsigned *len) { + const char *user = "super"; + + /* paranoia check */ + if (!result) { + return -1; + } + + switch (id) { + case SASL_CB_USER: + *result = user; + break; + case SASL_CB_AUTHNAME: + *result = user; + break; + default: + return -1; + } + return 0; + } + + static int saslPassCallback(sasl_conn_t *conn, void *context __attribute__((unused)), + int id, sasl_secret_t **psecret) { + const char *pass = "test"; + unsigned long int len; + + /* paranoia check */ + if (!psecret) { + return -1; + } + + switch (id) { + case SASL_CB_PASS: + len = strlen(pass); + *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len); + (*psecret)->len = len; + strcpy((char *)(*psecret)->data, (char *) pass); + break; + default: + return -1; + } + return 0; + } +#endif + static void verifyCreateFails(const char *path, zhandle_t *zk) { CPPUNIT_ASSERT_EQUAL((int)ZBADARGUMENTS, zoo_create(zk, path, "", 0, &ZOO_OPEN_ACL_UNSAFE, 0, 0, 0)); @@ -1485,11 +1538,19 @@ class Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture CPPUNIT_ASSERT_EQUAL((int)ZOK,rc); } +#ifdef SASL void testSasl() { int rc; const char *saslopt = "-sasl"; count = 0; - watchctx_t ctx1, ctx2; + watchctx_t ctx1, ctx2, ctx3, ctx4; + + zoo_sasl_conn_t *sasl_conn; + const char *supportedmechs; + const char *mech = "DIGEST-MD5"; + const char *service = "zookeeper"; + const char *host = "zk-sasl-md5"; + int supportedmechcount; const char *serverin; unsigned serverinlen; @@ -1513,10 +1574,31 @@ class Zookeeper_simpleSystem : public CPPUNIT_NS::TestFixture zhandle_t *zk2 = createClient(&ctx2); rc = zoo_asasl(zk2, NULL, (const char *) "", 0, saslDigestInitCompletion); +#ifdef THREADED + + sasl_callback_t callbacks[] = { + { SASL_CB_USER, (int (*)())&saslSimpleCallback, NULL }, + { SASL_CB_AUTHNAME, (int (*)())&saslSimpleCallback, NULL }, + { SASL_CB_PASS, (int (*)())&saslPassCallback, NULL }, + { SASL_CB_LIST_END, NULL, NULL } }; + + rc = zoo_sasl_init(callbacks); + CPPUNIT_ASSERT_EQUAL((int) ZOK, rc); + + zhandle_t *zk3 = createClient(&ctx3); + + rc = zoo_sasl_connect(zk3, (char *) service, (char *) host, &sasl_conn, + &supportedmechs, &supportedmechcount); + CPPUNIT_ASSERT_EQUAL((int) ZOK, rc); + + rc = zoo_sasl_authenticate(zk3, sasl_conn, mech, supportedmechs); + CPPUNIT_ASSERT_EQUAL((int) ZOK, rc); +#endif stopServer(); startServer(); } +#endif }; volatile int Zookeeper_simpleSystem::count; diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java b/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java index b3de2e52667..dd93a03d048 100644 --- a/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java +++ b/zookeeper-server/src/main/java/org/apache/zookeeper/util/SecurityUtils.java @@ -18,6 +18,8 @@ package org.apache.zookeeper.util; +import java.util.HashMap; + import java.security.Principal; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; @@ -150,6 +152,11 @@ public static SaslServer createSaslServer( final String serverName, final CallbackHandler callbackHandler, final Logger LOG) { + // required by c client api - Sasl.QOP="auth" is not set + // by default although stated in javadoc (Sun JRE 1.6.0_26-b03) + HashMap props = new HashMap(); + props.put(Sasl.QOP, "auth-conf,auth-int,auth"); + if (subject != null) { // server is using a JAAS-authenticated subject: determine service // principal name and hostname from zk server's subject. @@ -214,7 +221,7 @@ public static SaslServer createSaslServer( public SaslServer run() { try { SaslServer saslServer; - saslServer = Sasl.createSaslServer(mech, servicePrincipalName, serviceHostname, null, callbackHandler); + saslServer = Sasl.createSaslServer(mech, servicePrincipalName, serviceHostname, props, callbackHandler); return saslServer; } catch (SaslException e) { LOG.error("Zookeeper Server failed to create a SaslServer to interact with a client during session initiation: ", e); @@ -234,7 +241,7 @@ public SaslServer run() { // DIGEST-MD5 mechanism for now. // TODO: use 'authMech=' value in zoo.cfg. try { - SaslServer saslServer = Sasl.createSaslServer("DIGEST-MD5", protocol, serverName, null, callbackHandler); + SaslServer saslServer = Sasl.createSaslServer("DIGEST-MD5", protocol, serverName, props, callbackHandler); return saslServer; } catch (SaslException e) { LOG.error("Zookeeper Quorum member failed to create a SaslServer to interact with a client during session initiation", e);