[
https://issues.apache.org/jira/browse/THRIFT-4619?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16595533#comment-16595533
]
ASF GitHub Bot commented on THRIFT-4619:
----------------------------------------
dcelasun closed pull request #1581: THRIFT-4619: Transport SASL Client fo go
URL: https://github.com/apache/thrift/pull/1581
This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:
As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):
diff --git a/lib/go/thrift/sasl_transport.go b/lib/go/thrift/sasl_transport.go
new file mode 100644
index 0000000000..6535b8d60a
--- /dev/null
+++ b/lib/go/thrift/sasl_transport.go
@@ -0,0 +1,245 @@
+package thrift
+
+import (
+ "bytes"
+ "context"
+ "encoding/binary"
+ "fmt"
+ "git.apache.org/thrift.git/lib/go/thrift"
+ "github.com/beltran/gosasl"
+ "io"
+)
+
+const (
+ START = 1
+ OK = 2
+ BAD = 3
+ ERROR = 4
+ COMPLETE = 5
+)
+
+// TSaslTransport is a tranport thrift struct that uses SASL
+type TSaslTransport struct {
+ service string
+ saslClient *gosasl.Client
+ tp thrift.TTransport
+ tpFramed thrift.TFramedTransport
+ mechanism string
+ writeBuf bytes.Buffer
+ readBuf bytes.Buffer
+ buffer [4]byte
+ rawFrameSize uint32
+ frameSize int
+ maxLength uint32
+ principal string
+ OpeningContext context.Context
+}
+
+// NewTSaslTransport return a TSaslTransport
+func NewTSaslTransport(trans thrift.TTransport, host string, mechanismName
string, configuration map[string]string) (*TSaslTransport, error) {
+ var mechanism gosasl.Mechanism
+ if mechanismName == "PLAIN" {
+ mechanism = gosasl.NewPlainMechanism(configuration["username"],
configuration["password"])
+ } else if mechanismName == "GSSAPI" {
+ var err error
+ mechanism, err =
gosasl.NewGSSAPIMechanism(configuration["service"])
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ panic("Mechanism not supported")
+ }
+ client := gosasl.NewSaslClient(host, mechanism)
+
+ return &TSaslTransport{
+ saslClient: client,
+ tp: trans,
+ mechanism: mechanismName,
+ maxLength: DEFAULT_MAX_LENGTH,
+ principal: configuration["principal"],
+ OpeningContext: context.Background(),
+ }, nil
+}
+
+// IsOpen opens a SASL connection
+func (p *TSaslTransport) IsOpen() bool {
+ return p.tp.IsOpen() && p.saslClient.Complete()
+}
+
+// Open check if a SASL transport connection is opened
+func (p *TSaslTransport) Open() (err error) {
+ if !p.tp.IsOpen() {
+ err = p.tp.Open()
+ if err != nil {
+ return err
+ }
+ }
+ if err = p.sendSaslMsg(p.OpeningContext, START, []byte(p.mechanism));
err != nil {
+ return nil
+ }
+
+ proccessed, err := p.saslClient.Start()
+ if err != nil {
+ return
+ }
+
+ if err = p.sendSaslMsg(p.OpeningContext, OK, proccessed); err != nil {
+ return nil
+ }
+
+ for true {
+ status, challenge := p.recvSaslMsg(p.OpeningContext)
+ if status == OK {
+ proccessed, err = p.saslClient.Step(challenge)
+ if err != nil {
+ return
+ }
+ p.sendSaslMsg(p.OpeningContext, OK, proccessed)
+ } else if status == COMPLETE {
+ if !p.saslClient.Complete() {
+ return
thrift.NewTTransportException(thrift.NOT_OPEN, "The server erroneously
indicated that SASL negotiation was complete")
+ }
+ break
+ } else {
+ return
thrift.NewTTransportExceptionFromError(fmt.Errorf("Bad SASL negotiation status:
%d (%s)", status, challenge))
+ }
+ }
+ return nil
+}
+
+// Close close a SASL transport connection
+func (p *TSaslTransport) Close() (err error) {
+ p.saslClient.Dispose()
+ return p.tp.Close()
+}
+
+func (p *TSaslTransport) sendSaslMsg(ctx context.Context, status uint8, body
[]byte) error {
+ header := make([]byte, 5)
+ header[0] = status
+ length := uint32(len(body))
+ binary.BigEndian.PutUint32(header[1:], length)
+
+ _, err := p.tp.Write(append(header[:], body[:]...))
+ if err != nil {
+ return err
+ }
+
+ err = p.tp.Flush(ctx)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (p *TSaslTransport) recvSaslMsg(ctx context.Context) (int8, []byte) {
+ header := make([]byte, 5)
+ _, err := io.ReadFull(p.tp, header)
+ if err != nil {
+ return ERROR, nil
+ }
+
+ status := int8(header[0])
+ length := binary.BigEndian.Uint32(header[1:])
+
+ if length > 0 {
+ payload := make([]byte, length)
+ _, err = io.ReadFull(p.tp, payload)
+ if err != nil {
+ return ERROR, nil
+ }
+ return status, payload
+ }
+ return status, nil
+}
+
+func (p *TSaslTransport) Read(buf []byte) (l int, err error) {
+ if p.rawFrameSize == 0 && p.frameSize == 0 {
+ p.rawFrameSize, err = p.readFrameHeader()
+ if err != nil {
+ return
+ }
+ }
+
+ var got int
+ if p.rawFrameSize > 0 {
+ rawBuf := make([]byte, p.rawFrameSize)
+ got, err = p.tp.Read(rawBuf)
+ if err != nil {
+ return
+ }
+ p.rawFrameSize = p.rawFrameSize - uint32(got)
+
+ var unwrappedBuf []byte
+ unwrappedBuf, err = p.saslClient.Decode(rawBuf)
+ if err != nil {
+ return
+ }
+ p.frameSize += len(unwrappedBuf)
+ p.readBuf.Write(unwrappedBuf)
+ }
+
+ // totalBytes := p.readBuf.Len()
+ got, err = p.readBuf.Read(buf)
+ p.frameSize = p.frameSize - got
+
+ /*
+ if p.readBuf.Len() > 0 {
+ err =
thrift.NewTTransportExceptionFromError(fmt.Errorf("Not enough frame size %d to
read %d bytes", p.frameSize, totalBytes))
+ return
+ }
+ */
+ if p.frameSize < 0 {
+ return 0,
thrift.NewTTransportException(thrift.UNKNOWN_TRANSPORT_EXCEPTION, "Negative
frame size")
+ }
+ return got, thrift.NewTTransportExceptionFromError(err)
+}
+
+func (p *TSaslTransport) readFrameHeader() (uint32, error) {
+ buf := p.buffer[:4]
+ if _, err := io.ReadFull(p.tp, buf); err != nil {
+ return 0, err
+ }
+ size := binary.BigEndian.Uint32(buf)
+ if size < 0 || size > p.maxLength {
+ return 0,
thrift.NewTTransportException(thrift.UNKNOWN_TRANSPORT_EXCEPTION,
fmt.Sprintf("Incorrect frame size (%d)", size))
+ }
+ return size, nil
+}
+
+func (p *TSaslTransport) Write(buf []byte) (int, error) {
+ n, err := p.writeBuf.Write(buf)
+ return n, thrift.NewTTransportExceptionFromError(err)
+}
+
+// Flush the bytes in the buffer
+func (p *TSaslTransport) Flush(ctx context.Context) (err error) {
+ wrappedBuf, err := p.saslClient.Encode(p.writeBuf.Bytes())
+ if err != nil {
+ return thrift.NewTTransportExceptionFromError(err)
+ }
+
+ p.writeBuf.Reset()
+
+ size := len(wrappedBuf)
+ buf := p.buffer[:4]
+ binary.BigEndian.PutUint32(buf, uint32(size))
+ _, err = p.tp.Write(buf)
+
+ if err != nil {
+ return thrift.NewTTransportExceptionFromError(err)
+ }
+
+ if size > 0 {
+ if n, err := p.tp.Write(wrappedBuf); err != nil {
+ print("Error while flushing write buffer of size ",
size, " to transport, only wrote ", n, " bytes: ", err.Error(), "\n")
+ return thrift.NewTTransportExceptionFromError(err)
+ }
+ }
+ err = p.tp.Flush(ctx)
+ return thrift.NewTTransportExceptionFromError(err)
+}
+
+// RemainingBytes return the size of the unwrapped bytes
+func (p *TSaslTransport) RemainingBytes() uint64 {
+ return uint64(p.frameSize)
+}
diff --git a/lib/go/thrift/sasl_transport_test.go
b/lib/go/thrift/sasl_transport_test.go
new file mode 100644
index 0000000000..2df2992c93
--- /dev/null
+++ b/lib/go/thrift/sasl_transport_test.go
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ */
+
+package thrift
+
+import (
+ "testing"
+)
+
+func TestSaslTransport(t *testing.T) {
+ configuration := map[string]string{
+ "username": "thriftUsername",
+ "password": "thriftPassword",
+ }
+
+ socket := NewTMemoryBuffer()
+ trans, err := NewTSaslTransport(socket, "localhost", "PLAIN",
configuration)
+ if err != nil {
+ t.Fatal(err)
+ }
+ trans.Open()
+ socket.Reset()
+ TransportTest(t, trans, trans)
+}
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
> Transport SASL Client fo go
> ---------------------------
>
> Key: THRIFT-4619
> URL: https://issues.apache.org/jira/browse/THRIFT-4619
> Project: Thrift
> Issue Type: New Feature
> Components: Go - Library
> Reporter: Jaume M
> Priority: Major
>
--
This message was sent by Atlassian JIRA
(v7.6.3#76005)