1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #ifdef THREADED 20 21 #include <cppunit/extensions/HelperMacros.h> 22 #include "CppAssertHelper.h" 23 24 #include <sys/socket.h> 25 #include <unistd.h> 26 27 #include <zookeeper.h> 28 29 #include "Util.h" 30 #include "WatchUtil.h" 31 32 class Zookeeper_SASLAuth : public CPPUNIT_NS::TestFixture { 33 CPPUNIT_TEST_SUITE(Zookeeper_SASLAuth); 34 CPPUNIT_TEST(testServerRequireClientSASL); 35 #ifdef HAVE_CYRUS_SASL_H 36 CPPUNIT_TEST(testClientSASL); 37 #ifdef ZOO_IPV6_ENABLED 38 CPPUNIT_TEST(testClientSASLOverIPv6); 39 #endif/* ZOO_IPV6_ENABLED */ 40 CPPUNIT_TEST(testClientSASLReadOnly); 41 CPPUNIT_TEST(testClientSASLPacketOrder); 42 #endif /* HAVE_CYRUS_SASL_H */ 43 CPPUNIT_TEST_SUITE_END(); 44 FILE *logfile; 45 static const char hostPorts[]; 46 static const char jaasConf[]; watcher(zhandle_t *,int type,int state,const char * path,void * v)47 static void watcher(zhandle_t *, int type, int state, const char *path,void*v){ 48 watchctx_t *ctx = (watchctx_t*)v; 49 50 if (state == ZOO_CONNECTED_STATE || state == ZOO_READONLY_STATE) { 51 ctx->connected = true; 52 } else { 53 ctx->connected = false; 54 } 55 if (type != ZOO_SESSION_EVENT) { 56 evt_t evt; 57 evt.path = path; 58 evt.type = type; 59 ctx->putEvent(evt); 60 } 61 } 62 63 public: Zookeeper_SASLAuth()64 Zookeeper_SASLAuth() { 65 logfile = openlogfile("Zookeeper_SASLAuth"); 66 } 67 ~Zookeeper_SASLAuth()68 ~Zookeeper_SASLAuth() { 69 if (logfile) { 70 fflush(logfile); 71 fclose(logfile); 72 logfile = 0; 73 } 74 } 75 setUp()76 void setUp() { 77 zoo_set_log_stream(logfile); 78 79 // Create SASL configuration file for server. 80 FILE *conff = fopen("Zookeeper_SASLAuth.jaas.conf", "wt"); 81 CPPUNIT_ASSERT(conff); 82 size_t confLen = strlen(jaasConf); 83 CPPUNIT_ASSERT_EQUAL(fwrite(jaasConf, 1, confLen, conff), confLen); 84 CPPUNIT_ASSERT_EQUAL(fclose(conff), 0); 85 conff = NULL; 86 87 // Create password file for client. 88 FILE *passf = fopen("Zookeeper_SASLAuth.password", "wt"); 89 CPPUNIT_ASSERT(passf); 90 CPPUNIT_ASSERT(fputs("mypassword", passf) > 0); 91 CPPUNIT_ASSERT_EQUAL(fclose(passf), 0); 92 passf = NULL; 93 } 94 startServer(bool useJaasConf=true,bool readOnly=false)95 void startServer(bool useJaasConf = true, bool readOnly = false) { 96 char cmd[1024]; 97 sprintf(cmd, "%s startRequireSASLAuth %s %s", 98 ZKSERVER_CMD, 99 useJaasConf ? "Zookeeper_SASLAuth.jaas.conf" : "", 100 readOnly ? "true" : ""); 101 CPPUNIT_ASSERT(system(cmd) == 0); 102 } 103 stopServer()104 void stopServer() { 105 char cmd[1024]; 106 sprintf(cmd, "%s stop", ZKSERVER_CMD); 107 CPPUNIT_ASSERT(system(cmd) == 0); 108 } 109 testServerRequireClientSASL()110 void testServerRequireClientSASL() { 111 startServer(false); 112 113 watchctx_t ctx; 114 int rc = 0; 115 zhandle_t *zk = zookeeper_init(hostPorts, watcher, 10000, 0, &ctx, 0); 116 ctx.zh = zk; 117 CPPUNIT_ASSERT(zk); 118 119 // Wait for handle to be connected. 120 CPPUNIT_ASSERT(ctx.waitForConnected(zk)); 121 122 char pathbuf[80]; 123 struct Stat stat_a = {0}; 124 125 rc = zoo_create2(zk, "/serverRequireClientSASL", "", 0, 126 &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, sizeof(pathbuf), &stat_a); 127 CPPUNIT_ASSERT_EQUAL((int)ZSESSIONCLOSEDREQUIRESASLAUTH, rc); 128 129 stopServer(); 130 } 131 132 #ifdef HAVE_CYRUS_SASL_H 133 134 // We need to disable the deprecation warnings as Apple has 135 // decided to deprecate all of CyrusSASL's functions with OS 10.11 136 // (see MESOS-3030, ZOOKEEPER-4201). We are using GCC pragmas also 137 // for covering clang. 138 #ifdef __APPLE__ 139 #pragma GCC diagnostic push 140 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 141 #endif 142 testClientSASLHelper(const char * hostPorts,const char * path)143 void testClientSASLHelper(const char *hostPorts, const char *path) { 144 startServer(); 145 146 // Initialize Cyrus SASL. 147 CPPUNIT_ASSERT_EQUAL(sasl_client_init(NULL), SASL_OK); 148 149 // Initialize SASL parameters. 150 zoo_sasl_params_t sasl_params = { 0 }; 151 152 sasl_params.service = "zookeeper"; 153 sasl_params.host = "zk-sasl-md5"; 154 sasl_params.mechlist = "DIGEST-MD5"; 155 sasl_params.callbacks = zoo_sasl_make_basic_callbacks( 156 "myuser", NULL, "Zookeeper_SASLAuth.password"); 157 158 // Connect. 159 watchctx_t ctx; 160 int rc = 0; 161 zhandle_t *zk = zookeeper_init_sasl(hostPorts, watcher, 10000, NULL, 162 &ctx, /*flags*/0, /*log_callback*/NULL, &sasl_params); 163 ctx.zh = zk; 164 CPPUNIT_ASSERT(zk); 165 166 // Wait for SASL auth to complete and handle to be connected. 167 CPPUNIT_ASSERT(ctx.waitForConnected(zk)); 168 169 // Leave mark. 170 char pathbuf[80]; 171 struct Stat stat_a = {0}; 172 rc = zoo_create2(zk, path, "", 0, 173 &ZOO_OPEN_ACL_UNSAFE, 0, pathbuf, sizeof(pathbuf), &stat_a); 174 CPPUNIT_ASSERT_EQUAL((int)ZOK, rc); 175 176 // Stop and restart the server to test automatic reconnect & re-auth. 177 stopServer(); 178 CPPUNIT_ASSERT(ctx.waitForDisconnected(zk)); 179 startServer(); 180 181 // Wait for automatic SASL re-auth to complete. 182 CPPUNIT_ASSERT(ctx.waitForConnected(zk)); 183 184 // Check mark left above. 185 rc = zoo_exists(zk, path, /*watch*/false, &stat_a); 186 CPPUNIT_ASSERT_EQUAL((int)ZOK, rc); 187 188 stopServer(); 189 } 190 testClientSASL()191 void testClientSASL() { 192 testClientSASLHelper(hostPorts, "/clientSASL"); 193 } 194 testClientSASLOverIPv6()195 void testClientSASLOverIPv6() { 196 const char *ipAndPort = "::1:22181"; 197 198 testClientSASLHelper(ipAndPort, "/clientSASLOverIPv6"); 199 } 200 testClientSASLReadOnly()201 void testClientSASLReadOnly() { 202 startServer(/*useJaasConf*/ true, /*readOnly*/ true); 203 204 // Initialize Cyrus SASL. 205 CPPUNIT_ASSERT_EQUAL(sasl_client_init(NULL), SASL_OK); 206 207 // Initialize SASL parameters. 208 zoo_sasl_params_t sasl_params = { 0 }; 209 210 sasl_params.service = "zookeeper"; 211 sasl_params.host = "zk-sasl-md5"; 212 sasl_params.mechlist = "DIGEST-MD5"; 213 sasl_params.callbacks = zoo_sasl_make_basic_callbacks( 214 "myuser", NULL, "Zookeeper_SASLAuth.password"); 215 216 // Connect. 217 watchctx_t ctx; 218 int rc = 0; 219 zhandle_t *zk = zookeeper_init_sasl(hostPorts, watcher, 10000, NULL, 220 &ctx, /*flags*/ZOO_READONLY, /*log_callback*/NULL, &sasl_params); 221 ctx.zh = zk; 222 CPPUNIT_ASSERT(zk); 223 224 // Wait for SASL auth to complete and handle to be connected. 225 CPPUNIT_ASSERT(ctx.waitForConnected(zk)); 226 227 // Assert can read. 228 char buf[1024]; 229 int len = sizeof(buf); 230 rc = zoo_get(zk, "/", 0, buf, &len, 0); 231 CPPUNIT_ASSERT_EQUAL((int)ZOK, rc); 232 233 // Assert can not write. 234 char path[1024]; 235 rc = zoo_create(zk, "/test", "hello", 5, &ZOO_OPEN_ACL_UNSAFE, 0, path, sizeof(path)); 236 CPPUNIT_ASSERT_EQUAL((int)ZNOTREADONLY, rc); 237 238 stopServer(); 239 } 240 testClientSASLPacketOrder()241 void testClientSASLPacketOrder() { 242 startServer(); 243 244 // Initialize Cyrus SASL. 245 CPPUNIT_ASSERT_EQUAL(sasl_client_init(NULL), SASL_OK); 246 247 // Initialize SASL parameters. 248 zoo_sasl_params_t sasl_params = { 0 }; 249 250 sasl_params.service = "zookeeper"; 251 sasl_params.host = "zk-sasl-md5"; 252 sasl_params.mechlist = "DIGEST-MD5"; 253 sasl_params.callbacks = zoo_sasl_make_basic_callbacks( 254 "myuser", NULL, "Zookeeper_SASLAuth.password"); 255 256 // Connect. 257 watchctx_t ctx; 258 int rc = 0; 259 zhandle_t *zk = zookeeper_init_sasl(hostPorts, watcher, 10000, NULL, 260 &ctx, /*flags*/0, /*log_callback*/NULL, &sasl_params); 261 ctx.zh = zk; 262 CPPUNIT_ASSERT(zk); 263 264 // No wait: try and queue a packet before SASL auth is complete. 265 char buf[1024]; 266 int len = sizeof(buf); 267 rc = zoo_get(zk, "/", 0, buf, &len, 0); 268 CPPUNIT_ASSERT_EQUAL((int)ZOK, rc); 269 270 stopServer(); 271 } 272 273 #ifdef __APPLE__ 274 #pragma GCC diagnostic pop 275 #endif 276 277 #endif /* HAVE_CYRUS_SASL_H */ 278 }; 279 280 const char Zookeeper_SASLAuth::hostPorts[] = "127.0.0.1:22181"; 281 282 const char Zookeeper_SASLAuth::jaasConf[] = 283 "Server {\n" 284 " org.apache.zookeeper.server.auth.DigestLoginModule required\n" 285 " user_myuser=\"mypassword\";\n" 286 "};\n"; 287 288 CPPUNIT_TEST_SUITE_REGISTRATION(Zookeeper_SASLAuth); 289 290 #endif /* THREADED */ 291