zauth - Man Page

Class for authentication for ZeroMQ security mechanisms

Synopsis

#define CURVE_ALLOW_ANY "*"

//  CZMQ v3 API (for use with zsock, not zsocket, which is deprecated).
//
//  Create new zauth actor instance. This installs authentication on all
//  zsock sockets. Until you add policies, all incoming NULL connections are
//  allowed (classic ZeroMQ behaviour), and all PLAIN and CURVE connections
//  are denied:
//
//      zactor_t *auth = zactor_new (zauth, NULL);
//
//  Destroy zauth instance. This removes authentication and allows all
//  connections to pass, without authentication:
//
//      zactor_destroy (&auth);
//
//  Note that all zauth commands are synchronous, so your application always
//  waits for a signal from the actor after each command.
//
//  Enable verbose logging of commands and activity. Verbose logging can help
//  debug non-trivial authentication policies:
//
//      zstr_send (auth, "VERBOSE");
//      zsock_wait (auth);
//
//  Allow a list of IP addresses. For NULL, all clients from
//  these addresses will be accepted. For PLAIN and CURVE, they will be
//  allowed to continue with authentication. You can call this method
//  multiple times to allow more IP addresses. If you allow one
//  or more addresses, any non-allowed addresses are treated as
//  blocked:
//
//      zstr_sendx (auth, "ALLOW", "127.0.0.1", "127.0.0.2", NULL);
//      zsock_wait (auth);
//
//  Deny (block) a list of IP addresses. For all security mechanisms,
//  this rejects the connection without any further authentication. Use
//  either an allowed list, or a blocked list, not not both. If you define both
//  an allowed list and a blocked list, only the allowed list takes effect:
//
//      zstr_sendx (auth, "DENY", "192.168.0.1", "192.168.0.2", NULL);
//      zsock_wait (auth);
//
//  Configure PLAIN authentication using a plain-text password file. You can
//  modify the password file at any time; zauth will reload it automatically
//  if modified externally:
//
//      zstr_sendx (auth, "PLAIN", filename, NULL);
//      zsock_wait (auth);
//
//  Configure CURVE authentication, using a directory that holds all public
//  client certificates, i.e. their public keys. The certificates must be in
//  zcert_save format. You can add and remove certificates in that directory
//  at any time. To allow all client keys without checking, specify
//  CURVE_ALLOW_ANY for the directory name:
//
//      zstr_sendx (auth, "CURVE", directory, NULL);
//      zsock_wait (auth);
//
//  Configure GSSAPI authentication, using an underlying mechanism (usually
//  Kerberos) to establish a secure context and perform mutual authentication:
//
//      zstr_sendx (auth, "GSSAPI", NULL);
//      zsock_wait (auth);
//
//  This is the zauth constructor as a zactor_fn:
CZMQ_EXPORT void
    zauth (zsock_t *pipe, void *certstore);

//  Selftest
CZMQ_EXPORT void
    zauth_test (bool verbose);
Please add '@interface' section in './../src/zauth.c'.

Description

A zauth actor takes over authentication for all incoming connections in its context. You can allow or block peers based on IP address, and define policies for securing PLAIN, CURVE, and GSSAPI connections.

This class replaces zauth_v2, and is meant for applications that use the CZMQ v3 API (meaning, zsock).

Example

From zauth_test method.

const char *SELFTEST_DIR_RW = "src/selftest-rw";

const char *testbasedir  = ".test_zauth";
const char *testpassfile = "password-file";
const char *testcertfile = "mycert.txt";
char *basedirpath = NULL;   // subdir in a test, under SELFTEST_DIR_RW
char *passfilepath = NULL;  // pathname to testfile in a test, in dirpath
char *certfilepath = NULL;  // pathname to testfile in a test, in dirpath

basedirpath = zsys_sprintf ("%s/%s", SELFTEST_DIR_RW, testbasedir);
assert (basedirpath);
passfilepath = zsys_sprintf ("%s/%s", basedirpath, testpassfile);
assert (passfilepath);
certfilepath = zsys_sprintf ("%s/%s", basedirpath, testcertfile);
assert (certfilepath);

// Make sure old aborted tests do not hinder us
zdir_t *dir = zdir_new (basedirpath, NULL);
if (dir) {
    zdir_remove (dir, true);
    zdir_destroy (&dir);
}
zsys_file_delete (passfilepath);
zsys_file_delete (certfilepath);
zsys_dir_delete  (basedirpath);

//  Create temporary directory for test files
zsys_dir_create (basedirpath);

//  Check there's no authentication
zsock_t *server = zsock_new (ZMQ_PULL);
assert (server);
zsock_t *client = zsock_new (ZMQ_PUSH);
assert (client);
bool success = s_can_connect (&server, &client, true);
assert (success);

//  Install the authenticator
zactor_t *auth = zactor_new (zauth, NULL);
assert (auth);
if (verbose) {
    zstr_sendx (auth, "VERBOSE", NULL);
    zsock_wait (auth);
}
//  Check there's no authentication on a default NULL server
success = s_can_connect (&server, &client, true);
assert (success);

//  When we set a domain on the server, we switch on authentication
//  for NULL sockets, but with no policies, the client connection
//  will be allowed.
zsock_set_zap_domain (server, "global");
success = s_can_connect (&server, &client, true);
assert (success);

//  Block 127.0.0.1, connection should fail
zsock_set_zap_domain (server, "global");
zstr_sendx (auth, "DENY", "127.0.0.1", NULL);
zsock_wait (auth);
success = s_can_connect (&server, &client, true);
assert (!success);

//  Allow our address, which overrides the block list
zsock_set_zap_domain (server, "global");
zstr_sendx (auth, "ALLOW", "127.0.0.1", NULL);
zsock_wait (auth);
success = s_can_connect (&server, &client, true);
assert (success);

//  Try PLAIN authentication
zsock_set_zap_domain (server, "global");
zsock_set_plain_server (server, 1);
zsock_set_plain_username (client, "admin");
zsock_set_plain_password (client, "Password");
success = s_can_connect (&server, &client, true);
assert (!success);

FILE *password = fopen (passfilepath, "w");
assert (password);
fprintf (password, "admin=Password\n");
fclose (password);
zsock_set_zap_domain (server, "global");
zsock_set_plain_server (server, 1);
zsock_set_plain_username (client, "admin");
zsock_set_plain_password (client, "Password");
zstr_sendx (auth, "PLAIN", passfilepath, NULL);
zsock_wait (auth);
success = s_can_connect (&server, &client, false);
assert (success);

#if (ZMQ_VERSION >= ZMQ_MAKE_VERSION (4, 1, 0))
// Test that the User-Id metadata is present
zframe_t *frame = zframe_recv (server);
assert (frame != NULL);
const char *user_id = zframe_meta (frame, "User-Id");
assert (user_id != NULL);
assert (streq (user_id, "admin"));
zframe_destroy (&frame);
#endif
s_renew_sockets(&server, &client);

zsock_set_zap_domain (server, "global");
zsock_set_plain_server (server, 1);
zsock_set_plain_username (client, "admin");
zsock_set_plain_password (client, "Bogus");
success = s_can_connect (&server, &client, true);
assert (!success);

if (zsys_has_curve ()) {
    //  Try CURVE authentication
    //  We'll create two new certificates and save the client public
    //  certificate on disk; in a real case we'd transfer this securely
    //  from the client machine to the server machine.
    zcert_t *server_cert = zcert_new ();
    assert (server_cert);
    zcert_t *client_cert = zcert_new ();
    assert (client_cert);
    const char *server_key = zcert_public_txt (server_cert);

    //  Test without setting-up any authentication
    zcert_apply (server_cert, server);
    zcert_apply (client_cert, client);
    zsock_set_curve_server (server, 1);
    zsock_set_curve_serverkey (client, server_key);
    zsock_set_zap_domain (server, "global");
    success = s_can_connect (&server, &client, true);
    assert (!success);

    //  Test CURVE_ALLOW_ANY
    zcert_apply (server_cert, server);
    zcert_apply (client_cert, client);
    zsock_set_curve_server (server, 1);
    zsock_set_curve_serverkey (client, server_key);
    zstr_sendx (auth, "CURVE", CURVE_ALLOW_ANY, NULL);
    zsock_wait (auth);
    success = s_can_connect (&server, &client, true);
    assert (success);

    //  Test full client authentication using certificates
    zcert_set_meta (client_cert, "Hello", "%s", "World!");
    zcert_apply (server_cert, server);
    zcert_apply (client_cert, client);
    zsock_set_curve_server (server, 1);
    zsock_set_curve_serverkey (client, server_key);
    zcert_save_public (client_cert, certfilepath);
    zstr_sendx (auth, "CURVE", basedirpath, NULL);
    zsock_wait (auth);
    zsock_set_zap_domain (server, "global");
    success = s_can_connect (&server, &client, false);
    assert (success);

#if (ZMQ_VERSION >= ZMQ_MAKE_VERSION (4, 1, 0))
    // Test send/recv certificate metadata
    zframe_t *frame = zframe_recv (server);
    assert (frame != NULL);
    const char *meta = zframe_meta (frame, "Hello");
    assert (meta != NULL);
    assert (streq (meta, "World!"));
    const char *user_id = zframe_meta (frame, "User-Id");
    assert (user_id != NULL);
    assert (streq (user_id, zcert_public_txt(client_cert)));
    zframe_destroy (&frame);
    s_renew_sockets(&server, &client);
#endif

    zcert_destroy (&server_cert);
    zcert_destroy (&client_cert);

    // Test custom zcertstore
    zcertstore_t *certstore = zcertstore_new (NULL);
    zcertstore_set_loader (certstore, s_test_loader, NULL, NULL);
    zactor_destroy(&auth);
    auth = zactor_new (zauth, certstore);
    assert (auth);
    if (verbose) {
        zstr_sendx (auth, "VERBOSE", NULL);
        zsock_wait (auth);
    }

    byte public_key [32] = { 105, 76, 150, 58, 214, 191, 218, 65, 50, 172,
                             131, 188, 247, 211, 136, 170, 227, 26, 57, 170,
                             185, 63, 246, 225, 177, 230, 12, 8, 134, 136,
                             105, 106 };
    byte secret_key [32] = { 245, 217, 172, 73, 106, 28, 195, 17, 218, 132,
                             135, 209, 99, 240, 98, 232, 7, 137, 244, 100,
                             242, 23, 29, 114, 70, 223, 83, 1, 113, 207,
                             132, 149 };
    zcert_t *shared_cert = zcert_new_from (public_key, secret_key);
    assert (shared_cert);
    zcert_apply (shared_cert, server);
    zcert_apply (shared_cert, client);
    zsock_set_curve_server (server, 1);
    zsock_set_curve_serverkey (client, "x?T*N/1Y{8goubv{Ts}#&#f}TXJ//DVe#D2HkoLU");
    success = s_can_connect (&server, &client, true);
    assert (success);
    zcert_destroy (&shared_cert);
}
//  Remove the authenticator and check a normal connection works
zactor_destroy (&auth);
success = s_can_connect (&server, &client, true);
assert (success);

zsock_destroy (&client);
zsock_destroy (&server);

//  Delete all test files
dir = zdir_new (basedirpath, NULL);
assert (dir);
zdir_remove (dir, true);
zdir_destroy (&dir);

zstr_free (&passfilepath);
zstr_free (&certfilepath);
zstr_free (&basedirpath);

#endif

#if defined (__WINDOWS__)
zsys_shutdown();
#endif

Authors

The czmq manual was written by the authors in the AUTHORS file.

Resources

Main web site:

Report bugs to the email <zeromq-dev@lists.zeromq.org[1]>

Notes

1.

zeromq-dev@lists.zeromq.org
mailto:zeromq-dev@lists.zeromq.org

Info

07/17/2024 CZMQ 4.2.1 CZMQ Manual