11package kafka
22
33import (
4+ "crypto/tls"
5+ "crypto/x509"
6+ "fmt"
7+ "io"
8+ "io/ioutil"
9+ "log"
410 "net"
511 "reflect"
612 "strings"
@@ -10,10 +16,120 @@ import (
1016 "github.com/optiopay/kafka/proto"
1117)
1218
19+ const TLSCaFile = "./testkeys/ca.crt"
20+ const TLSCertFile = "./testkeys/oats.crt"
21+ const TLSKeyFile = "./testkeys/oats.key"
22+
1323type serializableMessage interface {
1424 Bytes () ([]byte , error )
1525}
1626
27+ type TLSConf struct {
28+ ca []byte
29+ cert []byte
30+ key []byte
31+ }
32+
33+ func getTLSConf () (* TLSConf , error ) {
34+ ca , err := ioutil .ReadFile (TLSCaFile )
35+ if err != nil {
36+ return nil , fmt .Errorf ("Cannot read %s" , TLSCaFile )
37+ }
38+ cert , err := ioutil .ReadFile (TLSCertFile )
39+ if err != nil {
40+ return nil , fmt .Errorf ("Cannot read %s" , TLSCertFile )
41+ }
42+
43+ key , err := ioutil .ReadFile (TLSKeyFile )
44+ if err != nil {
45+ return nil , fmt .Errorf ("Cannot read %s" , TLSKeyFile )
46+ }
47+
48+ return & TLSConf {ca : ca , cert : cert , key : key }, nil
49+
50+ }
51+
52+ //just read request before start to response
53+ func readRequest (r io.Reader ) error {
54+ dec := proto .NewDecoder (r )
55+ size := dec .DecodeInt32 ()
56+ var read int32 = 0
57+ buf := make ([]byte , size )
58+
59+ for read < size {
60+ n , err := r .Read (buf )
61+ if err != nil {
62+ return err
63+ }
64+ read += int32 (n )
65+ }
66+ return nil
67+ }
68+
69+ func testTLSServer (messages ... serializableMessage ) (net.Listener , error ) {
70+ tlsConf , err := getTLSConf ()
71+ if err != nil {
72+ return nil , err
73+ }
74+
75+ roots := x509 .NewCertPool ()
76+ ok := roots .AppendCertsFromPEM (tlsConf .ca )
77+ if ! ok {
78+ return nil , fmt .Errorf ("Cannot parse root certificate" )
79+ }
80+
81+ certificate , err := tls .X509KeyPair (tlsConf .cert , tlsConf .key )
82+ if err != nil {
83+ return nil , fmt .Errorf ("Failed to parse key/cert for TLS: %s" , err )
84+ }
85+
86+ conf := & tls.Config {
87+ Certificates : []tls.Certificate {certificate },
88+ RootCAs : roots ,
89+ }
90+
91+ _ = conf
92+
93+ ln , err := tls .Listen ("tcp4" , "localhost:22222" , conf )
94+ if err != nil {
95+ return nil , err
96+ }
97+
98+ responses := make ([][]byte , len (messages ))
99+ for i , m := range messages {
100+ b , err := m .Bytes ()
101+ if err != nil {
102+ _ = ln .Close ()
103+ return nil , err
104+ }
105+ responses [i ] = b
106+ }
107+
108+ go func () {
109+ for {
110+ cli , err := ln .Accept ()
111+
112+ if err != nil {
113+ return
114+ }
115+
116+ go func (conn net.Conn ) {
117+ err := readRequest (conn )
118+ if err != nil {
119+ log .Panic (err )
120+ }
121+
122+ time .Sleep (time .Millisecond * 50 )
123+ for _ , resp := range responses {
124+ _ , _ = cli .Write (resp )
125+ }
126+ err = cli .Close ()
127+ }(cli )
128+ }
129+ }()
130+ return ln , nil
131+ }
132+
17133func testServer (messages ... serializableMessage ) (net.Listener , error ) {
18134 ln , err := net .Listen ("tcp4" , "" )
19135 if err != nil {
@@ -620,3 +736,59 @@ func TestNoServerResponse(t *testing.T) {
620736 t .Fatalf ("could not close test server: %s" , err )
621737 }
622738}
739+
740+ func TestTLSConnection (t * testing.T ) {
741+ resp1 := & proto.MetadataResp {
742+ CorrelationID : 1 ,
743+ Brokers : []proto.MetadataRespBroker {
744+ {
745+ NodeID : 666 ,
746+ Host : "example.com" ,
747+ Port : 999 ,
748+ },
749+ },
750+ Topics : []proto.MetadataRespTopic {
751+ {
752+ Name : "foo" ,
753+ Partitions : []proto.MetadataRespPartition {
754+ {
755+ ID : 7 ,
756+ Leader : 7 ,
757+ Replicas : []int32 {7 },
758+ Isrs : []int32 {7 },
759+ },
760+ },
761+ },
762+ },
763+ }
764+ ln , err := testTLSServer (resp1 )
765+ if err != nil {
766+ t .Fatalf ("test server error: %s" , err )
767+ }
768+ tlsConf , err := getTLSConf ()
769+ if err != nil {
770+ t .Fatalf ("cannot get tls parametes: %s" , err )
771+ }
772+ _ = tlsConf
773+ conn , err := newTLSConnection (ln .Addr ().String (), tlsConf .ca , tlsConf .cert , tlsConf .key , time .Second , time .Second )
774+
775+ if err != nil {
776+ t .Fatalf ("could not conect to test server: %s" , err )
777+ }
778+ resp , err := conn .Metadata (& proto.MetadataReq {
779+ ClientID : "tester" ,
780+ Topics : []string {"first" , "second" },
781+ })
782+ if err != nil {
783+ t .Fatalf ("could not fetch response: %s" , err )
784+ }
785+ if ! reflect .DeepEqual (resp , resp1 ) {
786+ t .Fatalf ("expected different response %#v" , resp )
787+ }
788+ if err := conn .Close (); err != nil {
789+ t .Fatalf ("could not close kafka connection: %s" , err )
790+ }
791+ if err := ln .Close (); err != nil {
792+ t .Fatalf ("could not close test server: %s" , err )
793+ }
794+ }
0 commit comments