saslconn

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 12, 2023 License: MIT Imports: 13 Imported by: 0

README

saslconn

A connection based SASL protocol definition + implementation according to RFC-4422


Go Reference

This repository serves two purposes:

  • Proposing a SASL connection protocol described via protobuf files
  • Containing a implementation of the proposed protocol in Golang based on the go-sasl library

Since the protocol is described through protobuf messages it should be relatively easy to implement the protocol in other programming languages.

Usage

The implementation of the protocol is inspired by golang's TLS implementation. Hence establishing connections hopefully feels very familiar.

Note: The following example transfers credentials in plain-text via the network. To ensure confidentiality and integrity you should consider combining the SASL connection with other protective mechanisms like TLS (see next section).

Client

import (
    "github.com/cspengl/saslconn"
    "github.com/emersion/go-sasl"
)

func main() {
    config := &saslconn.Config{
        Mechanisms: []*saslconn.Mechanism{
            {
                Name: sasl.Plain,
                Client: sasl.NewPlainClient("userident", "username", "secret"),
            },
        },
    }

    conn, err := saslconn.Dial("tcp", ":9000", config)
    defer func() {
        if err := conn.Close(); err != nil {
            panic(err)
        }
    }()
    if err != nil {
        panic(err)
    }
    if _, err := conn.Write([]byte("Hello World!")); err != nil {
        panic(err)
    }
}

Server

import (
    "fmt"

    "github.com/cspengl/saslconn"
    "github.com/emersion/go-sasl"
)

func main() {
    config := &saslconn.Config{
        Mechanisms: []*saslconn.Mechanism{
            {
                Name: sasl.Plain,
                Server: sasl.NewPlainServer(
					func(identity, username, password string) error {
                        // always successful
						return nil
					},
				),
            },
            
        },
    }

    listener, err := saslconn.Listen("tcp", ":9000", config)
    defer func() {
        if err := listener.Close(); err != nil {
            panic(err)
        }
    }()
    conn, err := listener.Accept()
    if err != nil {
        panic(err)
    }
    helloWorldFromClient := make([]byte, 12)
    if _, err := conn.Read(helloWorldFromClient); err != nil {
        panic(err)
    }
    fmt.Println(string(helloWorldFromClient))
}

Combination with TLS

Neither SASL mechanisms nor the proposed connection protocol itself provide adequate integrity and/or confidentialty protection of the authentication exchange it is highly recommended to combine it with other protective mechanisms like TLS.

Example

import (
    "fmt"
    "crypto/tls"

    "github.com/cspengl/saslconn"
    "github.com/emersion/go-sasl"
)

func main() {
    config := &saslconn.Config{
        Mechanisms: []*saslconn.Mechanism{
            {
                Name: sasl.Plain,
                Server: sasl.NewPlainServer(
					func(identity, username, password string) error {
                        // always successful
						return nil
					},
				),
            },
            
        },
    }

    cert, err := tls.LoadX509KeyPair("example-cert.pem", "example-key.pem")
	if err != nil {
		log.Fatal(err)
	}
	tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}}

    listener, err := saslconn.ListenTLS("tcp", ":9000", tlsConfig, config)
    defer func() {
        if err := listener.Close(); err != nil {
            panic(err)
        }
    }()
    //...
}

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrHandshakeAborted gets returned from handshake if the
	// client or server aborted the ongoing handshake
	ErrHandshakeAborted = errors.New("handshake got aborted")
)

Functions

func Listen

func Listen(network, laddr string, config *Config) (net.Listener, error)

Listen creates a SASL listener by calling NewListener after using net.Listen to create the inner listener

func ListenTLS

func ListenTLS(network, laddr string, tlsConfig *tls.Config, config *Config) (net.Listener, error)

ListenTLS creates a tls listener before creating a SASL listener. This enables using a already secured TLS connection before transmitting credentials in plain text

func NewListener

func NewListener(inner net.Listener, config *Config) net.Listener

NewListener creates a listener accepting connections from an inner listener. It's accept function will return a SASL conn. It does not initiate a handshake.

Types

type Config

type Config struct {
	Mechanisms []*Mechanism
}

Config describes the the configuration used for establishing a SASL connection. It contains a list of supported mechanisms.

type Conn

type Conn struct {
	net.Conn
	// contains filtered or unexported fields
}

Conn describes a SASL authenticated connection. It implements the net.Conn interface

func Client

func Client(conn net.Conn, config *Config) *Conn

Client returns a new SASL connection using the given net.Conn as the underlying transport. It will act as the client.

func Dial

func Dial(network, addr string, config *Config) (*Conn, error)

Dial connects to the given network address using net.Dial and initiates a handshake returning the resulting SASL connection

func DialWithDialer

func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error)

DialWithDialer connects to a given network address using net.Dial and initiates a handshake returning the resulting SASL connection

func Server

func Server(conn net.Conn, config *Config) *Conn

Server returns a new SASL connection using the given net.Conn as the underlying transport. It will act as the server.

func (*Conn) Close

func (c *Conn) Close() error

Close closes the inner connection

func (*Conn) ConnectionState

func (c *Conn) ConnectionState() ConnectionState

ConnectionState returns the connection state of the connection

func (*Conn) Handshake

func (c *Conn) Handshake() error

Handshake calls HandshakeContext internally by using context.Background()

For controlling canceling or timeouts use HandshakeContext instead

func (*Conn) HandshakeContext

func (c *Conn) HandshakeContext(ctx context.Context) error

HandshakeContext initiates the handshake based on the connection role as client or server if it has not been run.

Since it is called as part of Read and Write it is mostly not neccessary to call it manually.

func (*Conn) LocalAddr

func (c *Conn) LocalAddr() net.Addr

LocalAddr returns the local address of the inner connection

func (*Conn) NetConn

func (c *Conn) NetConn() net.Conn

NetConn returns the underlying net.Conn

func (*Conn) Read

func (c *Conn) Read(b []byte) (n int, err error)

Read reads data from the connection.

As Read calls Handshake, in order to prevent indefinite blocking a deadline must be set for both Read and Write before Read is called when the handshake has not yet completed. See SetDeadline, SetReadDeadline, and SetWriteDeadline.

func (*Conn) RemoteAddr

func (c *Conn) RemoteAddr() net.Addr

RemoteAddr returns the remote address of the inner connection

func (*Conn) SetDeadline

func (c *Conn) SetDeadline(t time.Time) error

SetDeadline sets the read and write deadline for the inner connection

func (*Conn) SetReadDeadline

func (c *Conn) SetReadDeadline(t time.Time) error

SetReadDeadline sets the read deadline for the inner connection

func (*Conn) SetWriteDeadline

func (c *Conn) SetWriteDeadline(t time.Time) error

SetWriteDeadline sets the write deadline for the inner connection

func (*Conn) Write

func (c *Conn) Write(b []byte) (n int, err error)

Write writes data to the connection.

As Write calls Handshake, in order to prevent indefinite blocking a deadline must be set for both Read and Write before Write is called when the handshake has not yet completed. See SetDeadline, SetReadDeadline, and SetWriteDeadline.

type ConnectionState

type ConnectionState struct {
	// HandshakeComplete gives the status of the handshake
	HandshakeComplete bool
	// NegotiatedMechanism contains the mechanism negotiated
	// during the handshake. If it has not yet been selected
	// it is ""
	NegotiatedMechanism string
}

ConnectionState describes the state of a SASL connection

type Mechanism

type Mechanism struct {
	// Name is the name of the mechanism which must comply the
	// naming scheme defined in RFC4422 section 3.1
	Name string
	// Client specifies the client implementation for this mechanism
	Client MechanismClient
	// Server specifies the server implementation for this mechanism
	Server MechanismServer
}

Mechanism describes a SASL mechanism as describes in RFC4422

type MechanismClient

type MechanismClient sasl.Client

MechanismClient is redefined from the go-sasl library

type MechanismServer

type MechanismServer sasl.Server

MechanismServer is redefined from the go-sasl library

Directories

Path Synopsis
internal
pkg
protorw
package protorw solves the size delimination problem for protobuf messages.
package protorw solves the size delimination problem for protobuf messages.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL