예제 #1
0
파일: stonehouse.go 프로젝트: rayqiu/zmq4
func main() {

	//  Start authentication engine
	zmq.AuthSetVerbose(true)
	zmq.AuthStart()
	zmq.AuthAllow("127.0.0.1")

	//  Tell the authenticator to allow any CURVE requests for this domain
	zmq.AuthCurveAdd("global", zmq.CURVE_ALLOW_ANY)

	//  We need two certificates, one for the client and one for
	//  the server. The client must know the server's public key
	//  to make a CURVE connection.
	client_public, client_secret, err := zmq.NewCurveKeypair()
	checkErr(err)
	server_public, server_secret, _ := zmq.NewCurveKeypair()
	checkErr(err)

	//  Create and bind server socket
	server, _ := zmq.NewSocket(zmq.PUSH)
	server.ServerAuthCurve("global", server_secret)
	server.Bind("tcp://*:9000")

	//  Create and connect client socket
	client, _ := zmq.NewSocket(zmq.PULL)
	client.ClientAuthCurve(server_public, client_public, client_secret)
	client.Connect("tcp://127.0.0.1:9000")

	//  Send a single message from server to client
	_, err = server.Send("Hello", 0)
	checkErr(err)
	message, err := client.Recv(0)
	checkErr(err)
	if message != "Hello" {
		log.Fatalln(message, "!= Hello")
	}

	zmq.AuthStop()

	fmt.Println("Stonehouse test OK")

}
예제 #2
0
파일: resource.go 프로젝트: besserIO/dcams
func NewREQ(name string) (*Resource, error) {
	if name == "" {
		log.Fatal("Provide REQ resource name")
	}
	PublicKey, PrivateKey, err := zmq.NewCurveKeypair()
	if err != nil {
		return nil, err
	}
	r := Resource{PublicKey: PublicKey, PrivateKey: PrivateKey, Address: "tcp://127.0.0.1:8000", Name: name, Type: TYPE_REQ, UUID: uuid.New()}
	return &r, err
}
예제 #3
0
func NewSocket(cb chan Response, socketType zmq.Type) *ZMQSocket {
	pub, secret, _ := zmq.NewCurveKeypair()
	l := new(sync.Mutex)
	socket := ZMQSocket{
		socketType: socketType,
		publicKey:  pub,
		secretKey:  secret,
		callback:   cb,
		lock:       l,
	}
	return &socket
}
예제 #4
0
/*
 * Loads a zmq curve key pair from disk. If the requested pair cannot be found, a new pair that
 * matches the name is generated.
 */
func InitKeys(private_key_path string) (private_key string, public_key string, err error) {
	if !strings.HasSuffix(private_key_path, ".private") {
		return "", "", errors.New(fmt.Sprintf("Invalid private key path '%v'.", private_key_path))
	}
	if err = CheckPermissions(private_key_path); err != nil {
		return "", "", err
	}

	public_key_path := strings.TrimSuffix(private_key_path, ".private") + ".public"
	if err = CheckPermissions(public_key_path); err != nil {
		return "", "", err
	}
	CheckPermissions(public_key_path)
	private_key_buf, _ := ioutil.ReadFile(private_key_path)
	private_key = string(private_key_buf)
	public_key_buf, _ := ioutil.ReadFile(public_key_path)
	public_key = string(public_key_buf)

	if private_key != "" && public_key != "" {
		return private_key, public_key, nil
	} else if private_key == "" && public_key == "" {
		if public_key, private_key, err = zmq.NewCurveKeypair(); err != nil {
			return "", "", err
		}
		if err = ioutil.WriteFile(private_key_path, []byte(private_key), 0600); err != nil {
			return "", "", err
		}
		if err = ioutil.WriteFile(public_key_path, []byte(public_key), 0600); err != nil {
			return "", "", err
		}
	} else {
		return "", "", errors.New(fmt.Sprintf("Imbalanced key setup: '%v'", private_key_path))
	}

	return private_key, public_key, nil
}
예제 #5
0
파일: zmq4_test.go 프로젝트: pebbe/zmq4
func TestSecurityCurve(t *testing.T) {

	time.Sleep(100 * time.Millisecond)

	var handler, server, client *zmq.Socket
	defer func() {
		for _, s := range []*zmq.Socket{handler} {
			if s != nil {
				s.SetLinger(0)
				s.Close()
			}
		}
	}()

	if _, minor, _ := zmq.Version(); minor >= 1 && !zmq.HasCurve() {
		t.Skip("Curve not available")
	}

	//  Generate new keypairs for this test
	client_public, client_secret, err := zmq.NewCurveKeypair()
	if err != nil {
		t.Fatal("NewCurveKeypair:", err)
	}
	server_public, server_secret, err := zmq.NewCurveKeypair()
	if err != nil {
		t.Fatal("NewCurveKeypair:", err)
	}

	handler, err = zmq.NewSocket(zmq.REP)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	err = handler.Bind("inproc://zeromq.zap.01")
	if err != nil {
		t.Fatal("handler.Bind:", err)
	}

	doHandler := func(state zmq.State) error {
		msg, err := handler.RecvMessage(0)
		if err != nil {
			return err //  Terminating
		}
		version := msg[0]
		sequence := msg[1]
		// domain := msg[2]
		// address := msg[3]
		identity := msg[4]
		mechanism := msg[5]
		client_key := msg[6]
		client_key_text := zmq.Z85encode(client_key)

		if version != "1.0" {
			return errors.New("version != 1.0")
		}
		if mechanism != "CURVE" {
			return errors.New("mechanism != CURVE")
		}
		if identity != "IDENT" {
			return errors.New("identity != IDENT")
		}

		if client_key_text == client_public {
			handler.SendMessage(version, sequence, "200", "OK", "anonymous", "")
		} else {
			handler.SendMessage(version, sequence, "400", "Invalid client public key", "", "")
		}
		return nil
	}

	doQuit := func(i interface{}) error {
		err := handler.Close()
		handler = nil
		if err != nil {
			t.Error("handler.Close:", err)
		}
		return errors.New("Quit")
	}
	quit := make(chan interface{})

	reactor := zmq.NewReactor()
	reactor.AddSocket(handler, zmq.POLLIN, doHandler)
	reactor.AddChannel(quit, 0, doQuit)
	go func() {
		reactor.Run(100 * time.Millisecond)
		quit <- true
	}()
	defer func() {
		quit <- true
		<-quit
		close(quit)
	}()

	//  Server socket will accept connections
	server, err = zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	err = server.SetCurveServer(1)
	if err != nil {
		t.Fatal("server.SetCurveServer(1):", err)
	}
	err = server.SetCurveSecretkey(server_secret)
	if err != nil {
		t.Fatal("server.SetCurveSecretkey:", err)
	}
	err = server.SetIdentity("IDENT")
	if err != nil {
		t.Fatal("server.SetIdentity:", err)
	}
	server.Bind("tcp://127.0.0.1:9998")
	if err != nil {
		t.Fatal("server.Bind:", err)
	}

	err = server.SetRcvtimeo(time.Second)
	if err != nil {
		t.Fatal("server.SetRcvtimeo:", err)
	}

	//  Check CURVE security with valid credentials
	client, err = zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	err = client.SetCurveServerkey(server_public)
	if err != nil {
		t.Fatal("client.SetCurveServerkey:", err)
	}
	err = client.SetCurvePublickey(client_public)
	if err != nil {
		t.Fatal("client.SetCurvePublickey:", err)
	}
	err = client.SetCurveSecretkey(client_secret)
	if err != nil {
		t.Fatal("client.SetCurveSecretkey:", err)
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if err != nil {
		t.Fatal("client.Connect:", err)
	}
	msg, err := bounce(server, client)
	if err != nil {
		t.Error(msg, err)
	}
	err = client.Close()
	client = nil
	if err != nil {
		t.Fatal("client.Close:", err)
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with a garbage server key
	//  This will be caught by the curve_server class, not passed to ZAP
	garbage_key := "0000111122223333444455556666777788889999"
	client, err = zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	err = client.SetCurveServerkey(garbage_key)
	if err != nil {
		t.Fatal("client.SetCurveServerkey:", err)
	}
	err = client.SetCurvePublickey(client_public)
	if err != nil {
		t.Fatal("client.SetCurvePublickey:", err)
	}
	err = client.SetCurveSecretkey(client_secret)
	if err != nil {
		t.Fatal("client.SetCurveSecretkey:", err)
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if err != nil {
		t.Fatal("client.Connect:", err)
	}
	err = client.SetRcvtimeo(time.Second)
	if err != nil {
		t.Fatal("client.SetRcvtimeo:", err)
	}
	_, err = bounce(server, client)
	if err == nil {
		t.Error("Expected failure, got success")
	}
	client.SetLinger(0)
	err = client.Close()
	client = nil
	if err != nil {
		t.Fatal("client.Close:", err)
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with a garbage client secret key
	//  This will be caught by the curve_server class, not passed to ZAP
	client, err = zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	err = client.SetCurveServerkey(server_public)
	if err != nil {
		t.Fatal("client.SetCurveServerkey:", err)
	}
	err = client.SetCurvePublickey(garbage_key)
	if err != nil {
		t.Fatal("client.SetCurvePublickey:", err)
	}
	err = client.SetCurveSecretkey(client_secret)
	if err != nil {
		t.Fatal("client.SetCurveSecretkey:", err)
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if err != nil {
		t.Fatal("client.Connect:", err)
	}
	err = client.SetRcvtimeo(time.Second)
	if err != nil {
		t.Fatal("client.SetRcvtimeo:", err)
	}
	_, err = bounce(server, client)
	if err == nil {
		t.Error("Expected failure, got success")
	}
	client.SetLinger(0)
	err = client.Close()
	client = nil
	if err != nil {
		t.Fatal("client.Close:", err)
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with a garbage client secret key
	//  This will be caught by the curve_server class, not passed to ZAP
	client, err = zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	err = client.SetCurveServerkey(server_public)
	if err != nil {
		t.Fatal("client.SetCurveServerkey:", err)
	}
	err = client.SetCurvePublickey(client_public)
	if err != nil {
		t.Fatal("client.SetCurvePublickey:", err)
	}
	err = client.SetCurveSecretkey(garbage_key)
	if err != nil {
		t.Fatal("client.SetCurveSecretkey:", err)
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if err != nil {
		t.Fatal("client.Connect:", err)
	}
	err = client.SetRcvtimeo(time.Second)
	if err != nil {
		t.Fatal("client.SetRcvtimeo:", err)
	}
	_, err = bounce(server, client)
	if err == nil {
		t.Error("Expected failure, got success")
	}
	client.SetLinger(0)
	err = client.Close()
	client = nil
	if err != nil {
		t.Fatal("client.Close:", err)
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with bogus client credentials
	//  This must be caught by the ZAP handler

	bogus_public, bogus_secret, _ := zmq.NewCurveKeypair()
	client, err = zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	err = client.SetCurveServerkey(server_public)
	if err != nil {
		t.Fatal("client.SetCurveServerkey:", err)
	}
	err = client.SetCurvePublickey(bogus_public)
	if err != nil {
		t.Fatal("client.SetCurvePublickey:", err)
	}
	err = client.SetCurveSecretkey(bogus_secret)
	if err != nil {
		t.Fatal("client.SetCurveSecretkey:", err)
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if err != nil {
		t.Fatal("client.Connect:", err)
	}
	err = client.SetRcvtimeo(time.Second)
	if err != nil {
		t.Fatal("client.SetRcvtimeo:", err)
	}
	_, err = bounce(server, client)
	if err == nil {
		t.Error("Expected failure, got success")
	}
	client.SetLinger(0)
	err = client.Close()
	client = nil
	if err != nil {
		t.Fatal("client.Close:", err)
	}

	//  Shutdown
	err = server.Close()
	server = nil
	if err != nil {
		t.Error("server.Close:", err)
	}
}
예제 #6
0
파일: zmq4_test.go 프로젝트: rdterner/zmq4
func Example_test_security_curve() {

	time.Sleep(100 * time.Millisecond)

	//  Generate new keypairs for this test
	client_public, client_secret, err := zmq.NewCurveKeypair()
	if checkErr(err) {
		return
	}
	server_public, server_secret, err := zmq.NewCurveKeypair()
	if checkErr(err) {
		return
	}

	handler, err := zmq.NewSocket(zmq.REP)
	if checkErr(err) {
		return
	}
	err = handler.Bind("inproc://zeromq.zap.01")
	if checkErr(err) {
		return
	}

	doHandler := func(state zmq.State) error {
		msg, err := handler.RecvMessage(0)
		if err != nil {
			return err //  Terminating
		}
		version := msg[0]
		sequence := msg[1]
		// domain := msg[2]
		// address := msg[3]
		identity := msg[4]
		mechanism := msg[5]
		client_key := msg[6]
		client_key_text := zmq.Z85encode(client_key)

		if version != "1.0" {
			return errors.New("version != 1.0")
		}
		if mechanism != "CURVE" {
			return errors.New("mechanism != CURVE")
		}
		if identity != "IDENT" {
			return errors.New("identity != IDENT")
		}

		if client_key_text == client_public {
			handler.SendMessage(version, sequence, "200", "OK", "anonymous", "")
		} else {
			handler.SendMessage(version, sequence, "400", "Invalid client public key", "", "")
		}
		return nil
	}

	doQuit := func(i interface{}) error {
		err := handler.Close()
		checkErr(err)
		fmt.Println("Handler closed")
		return errors.New("Quit")
	}
	quit := make(chan interface{})

	reactor := zmq.NewReactor()
	reactor.AddSocket(handler, zmq.POLLIN, doHandler)
	reactor.AddChannel(quit, 0, doQuit)
	go func() {
		reactor.Run(100 * time.Millisecond)
		fmt.Println("Reactor finished")
		quit <- true
	}()
	defer func() {
		quit <- true
		<-quit
		close(quit)
	}()

	//  Server socket will accept connections
	server, err := zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	err = server.SetCurveServer(1)
	if checkErr(err) {
		return
	}
	err = server.SetCurveSecretkey(server_secret)
	if checkErr(err) {
		return
	}
	err = server.SetIdentity("IDENT")
	if checkErr(err) {
		return
	}
	server.Bind("tcp://127.0.0.1:9998")
	if checkErr(err) {
		return
	}

	err = server.SetRcvtimeo(time.Second)
	if checkErr(err) {
		return
	}

	//  Check CURVE security with valid credentials
	client, err := zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	err = client.SetCurveServerkey(server_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurvePublickey(client_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurveSecretkey(client_secret)
	if checkErr(err) {
		return
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if checkErr(err) {
		return
	}
	bounce(server, client, false)
	err = client.Close()
	if checkErr(err) {
		return
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with a garbage server key
	//  This will be caught by the curve_server class, not passed to ZAP
	garbage_key := "0000111122223333444455556666777788889999"
	client, err = zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	err = client.SetCurveServerkey(garbage_key)
	if checkErr(err) {
		return
	}
	err = client.SetCurvePublickey(client_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurveSecretkey(client_secret)
	if checkErr(err) {
		return
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if checkErr(err) {
		return
	}
	err = client.SetRcvtimeo(time.Second)
	if checkErr(err) {
		return
	}
	bounce(server, client, true)
	client.SetLinger(0)
	err = client.Close()
	if checkErr(err) {
		return
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with a garbage client secret key
	//  This will be caught by the curve_server class, not passed to ZAP
	client, err = zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	err = client.SetCurveServerkey(server_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurvePublickey(garbage_key)
	if checkErr(err) {
		return
	}
	err = client.SetCurveSecretkey(client_secret)
	if checkErr(err) {
		return
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if checkErr(err) {
		return
	}
	err = client.SetRcvtimeo(time.Second)
	if checkErr(err) {
		return
	}
	bounce(server, client, true)
	client.SetLinger(0)
	err = client.Close()
	if checkErr(err) {
		return
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with a garbage client secret key
	//  This will be caught by the curve_server class, not passed to ZAP
	client, err = zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	err = client.SetCurveServerkey(server_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurvePublickey(client_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurveSecretkey(garbage_key)
	if checkErr(err) {
		return
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if checkErr(err) {
		return
	}
	err = client.SetRcvtimeo(time.Second)
	if checkErr(err) {
		return
	}
	bounce(server, client, true)
	client.SetLinger(0)
	err = client.Close()
	if checkErr(err) {
		return
	}

	time.Sleep(100 * time.Millisecond)

	//  Check CURVE security with bogus client credentials
	//  This must be caught by the ZAP handler

	bogus_public, bogus_secret, _ := zmq.NewCurveKeypair()
	client, err = zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	err = client.SetCurveServerkey(server_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurvePublickey(bogus_public)
	if checkErr(err) {
		return
	}
	err = client.SetCurveSecretkey(bogus_secret)
	if checkErr(err) {
		return
	}
	err = client.Connect("tcp://127.0.0.1:9998")
	if checkErr(err) {
		return
	}
	err = client.SetRcvtimeo(time.Second)
	if checkErr(err) {
		return
	}
	bounce(server, client, true)
	client.SetLinger(0)
	err = client.Close()
	if checkErr(err) {
		return
	}

	//  Shutdown
	err = server.Close()
	checkErr(err)

	fmt.Println("Done")
	// Output:
	// 5 error
	// 5 error
	// 5 error
	// 5 error
	// Done
	// Handler closed
	// Reactor finished
}
예제 #7
0
파일: auth_test.go 프로젝트: gallir/zmq4
func TestAuthStart(t *testing.T) {

	if _, minor, _ := zmq.Version(); minor >= 1 && !zmq.HasCurve() {
		t.Skip("Curve not available")
	}

	type Meta struct {
		key   string
		value string
		ok    bool
	}

	zmq.AuthSetVerbose(false)

	//  Start authentication engine
	err := zmq.AuthStart()
	if err != nil {
		t.Fatal("AuthStart:", err)
	}
	defer zmq.AuthStop()

	zmq.AuthSetMetadataHandler(
		func(version, request_id, domain, address, identity, mechanism string, credentials ...string) (metadata map[string]string) {
			return map[string]string{
				"Identity": identity,
				"User-Id":  "anonymous",
				"Hello":    "World!",
				"Foo":      "Bar",
			}
		})

	zmq.AuthAllow("domain1", "127.0.0.1")

	//  We need two certificates, one for the client and one for
	//  the server. The client must know the server's public key
	//  to make a CURVE connection.
	client_public, client_secret, err := zmq.NewCurveKeypair()
	if err != nil {
		t.Fatal("NewCurveKeypair:", err)
	}
	server_public, server_secret, err := zmq.NewCurveKeypair()
	if err != nil {
		t.Fatal("NewCurveKeypair:", err)
	}

	//  Tell authenticator to use this public client key
	zmq.AuthCurveAdd("domain1", client_public)

	//  Create and bind server socket
	server, err := zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	defer func() {
		server.SetLinger(0)
		server.Close()
	}()
	server.SetIdentity("Server1")
	server.ServerAuthCurve("domain1", server_secret)
	err = server.Bind("tcp://*:9000")
	if err != nil {
		t.Fatal("server.Bind:", err)
	}

	//  Create and connect client socket
	client, err := zmq.NewSocket(zmq.DEALER)
	if err != nil {
		t.Fatal("NewSocket:", err)
	}
	defer func() {
		client.SetLinger(0)
		client.Close()
	}()
	server.SetIdentity("Client1")
	client.ClientAuthCurve(server_public, client_public, client_secret)
	err = client.Connect("tcp://127.0.0.1:9000")
	if err != nil {
		t.Fatal("client.Connect:", err)
	}

	//  Send a message from client to server
	msg := []string{"Greetings", "Earthlings!"}
	_, err = client.SendMessage(msg[0], msg[1])
	if err != nil {
		t.Fatal("client.SendMessage:", err)
	}

	// Receive message and metadata on the server
	tests := []Meta{
		{"Identity", "Server1", true},
		{"User-Id", "anonymous", true},
		{"Socket-Type", "DEALER", true},
		{"Hello", "World!", true},
		{"Foo", "Bar", true},
		{"Fuz", "", false},
	}
	keys := make([]string, len(tests))
	for i, test := range tests {
		keys[i] = test.key
	}
	message, metadata, err := server.RecvMessageWithMetadata(0, keys...)
	if err != nil {
		t.Fatal("server.RecvMessageWithMetadata:", err)
	}
	if !arrayEqual(message, msg) {
		t.Errorf("Received message was %q, expected %q", message, msg)
	}
	if _, minor, _ := zmq.Version(); minor < 1 {
		t.Log("Metadata not avalable in ZeroMQ versions prior to 4.1.0")
	} else {
		for _, test := range tests {
			value, ok := metadata[test.key]
			if value != test.value || ok != test.ok {
				t.Errorf("Metadata %s, expected %q %v, got %q %v", test.key, test.value, test.ok, value, ok)
			}
		}
	}
}
예제 #8
0
파일: auth_test.go 프로젝트: JeremyOT/zmq4
func ExampleAuthStart() {

	checkErr := func(err error) bool {
		if err == nil {
			return false
		}
		log.Println(err)
		return true
	}

	zmq.AuthSetVerbose(false)

	//  Start authentication engine
	err := zmq.AuthStart()
	if checkErr(err) {
		return
	}
	defer zmq.AuthStop()

	zmq.AuthSetMetadataHandler(
		func(version, request_id, domain, address, identity, mechanism string, credentials ...string) (metadata map[string]string) {
			return map[string]string{
				"Identity": identity,
				"User-Id":  "anonymous",
				"Hello":    "World!",
				"Foo":      "Bar",
			}
		})

	zmq.AuthAllow("domain1", "127.0.0.1")

	//  We need two certificates, one for the client and one for
	//  the server. The client must know the server's public key
	//  to make a CURVE connection.
	client_public, client_secret, err := zmq.NewCurveKeypair()
	if checkErr(err) {
		return
	}
	server_public, server_secret, err := zmq.NewCurveKeypair()
	if checkErr(err) {
		return
	}

	//  Tell authenticator to use this public client key
	zmq.AuthCurveAdd("domain1", client_public)

	//  Create and bind server socket
	server, err := zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	defer server.Close()
	server.SetIdentity("Server1")
	server.ServerAuthCurve("domain1", server_secret)
	err = server.Bind("tcp://*:9000")
	if checkErr(err) {
		return
	}

	//  Create and connect client socket
	client, err := zmq.NewSocket(zmq.DEALER)
	if checkErr(err) {
		return
	}
	defer client.Close()
	server.SetIdentity("Client1")
	client.ClientAuthCurve(server_public, client_public, client_secret)
	err = client.Connect("tcp://127.0.0.1:9000")
	if checkErr(err) {
		return
	}

	//  Send a message from client to server
	_, err = client.SendMessage("Greatings", "Earthlings!")
	if checkErr(err) {
		return
	}

	// Receive message and metadata on the server
	keys := []string{"Identity", "User-Id", "Socket-Type", "Hello", "Foo", "Fuz"}
	message, metadata, err := server.RecvMessageWithMetadata(0, keys...)
	if checkErr(err) {
		return
	}
	fmt.Println(message)
	if _, minor, _ := zmq.Version(); minor < 1 {
		// Metadata requires at least ZeroMQ version 4.1
		fmt.Println(`Identity: "Server1" true`)
		fmt.Println(`User-Id: "anonymous" true`)
		fmt.Println(`Socket-Type: "DEALER" true`)
		fmt.Println(`Hello: "World!" true`)
		fmt.Println(`Foo: "Bar" true`)
		fmt.Println(`Fuz: "" false`)
	} else {
		for _, key := range keys {
			value, ok := metadata[key]
			fmt.Printf("%v: %q %v\n", key, value, ok)
		}
	}
	// Output:
	// [Greatings Earthlings!]
	// Identity: "Server1" true
	// User-Id: "anonymous" true
	// Socket-Type: "DEALER" true
	// Hello: "World!" true
	// Foo: "Bar" true
	// Fuz: "" false
}