go-sasl
The go-sasl
is a client and server framework for implementing Simple Authentication and Security Layer (SASL) authentication in Go.
SASL is a framework for authentication and data security in Internet protocols. It decouples authentication mechanisms from application protocols, allowing any authentication mechanism to be used with any protocol. SASL provides a structured interface for adding authentication support to connection-based protocols. The go-sasl
provides a common SASL mechanism interface for the client and server as the following:
SASL mechanisms are responsible for the authentication process, which can include steps such as exchanging credentials, verifying identities, and establishing secure communication channels. Each mechanism defines its own protocol for these steps, allowing for flexibility and extensibility.
Getting Started
Mechanism Negotiation
The client and server negotiate the SASL mechanism to use during the authentication process. The client sends a list of supported mechanisms to the server, which selects one and returns it to the client. The client then initializes the selected mechanism and begins the authentication process.
SASL mechanisms are named by character strings, such as PLAIN
and SCRAM-SHA-256
. The go-sasl
client and server can find mechanisms by name using Server::Mechanism()
and Client::Mechanism()
. The go-sasl
provides the following mechanism plugins:
Mechanism Interface
The go-sasl
provides a common SASL API as the following Mechanism interface for the client and server.
// Context represents a SASL mechanism context.
type Context interface {
// Next returns the next response.
Next(...Parameter) (Response, error)
// Step returns the current step number. The step number is incremented by one after each call to Next.
Step() int
// IsCompleted returns true if the context is completed.
IsCompleted() bool
// Dispose disposes the context.
Dispose() error
}
// Mechanism represents a SASL mechanism.
type Mechanism interface {
// Name returns the mechanism name.
Name() string
// Type returns the mechanism type.
Type() Type
// Start returns the initial context.
Start(...Option) (Context, error)
}
Example
Client side
The following pseudo example demonstrates how to authenticate server messages for SCRAM-SHA-256 mechanism using the go-sasl
server. For more complete examples, see go-sasl mechanism plugin testing, TestMechanism().
package main
import (
"github.com/cybergarage/go-sasl/sasl"
)
func main() {
client := sasl.NewServer()
// Get SCRAM-SHA-256 mechanism negotiation from the client.
mech, err := client.Mechanism("SCRAM-SHA-256")
if err != nil {
return
}
user := ... // "user"
password := ... // "password"
clientOpts := []mech.Option{
mech.Username(user),
mech.Password(password),
}
ctx, err := mech.Start(clientOpts...)
if err != nil {
return
}
// Generate the first authentication message for the server.
clientFirstMsg, err := mech.Next()
if err != nil {
....
return
}
// Send the first server authentication message to the server.
// ex. "n,,n=user,r=5lWV5BbvRW44ff97iaICZ5aK"
clientFirstMsgBytes := clientFirstMsg.Bytes()
...
// Check the first authentication message from the server.
// ex. "r=5lWV5BbvRW44ff97iaICZ5aKf1yv9rLKEHbMACfg,s=QVNyRlpRc3M3OXVIOXlVMg==,i=4096"
serverFirstMsg := ...
clientFinalrMsg, err := mech.Next(serverFirstMsg)
if err != nil {
....
return
}
// Send the final client message to the server.
// ex. "v=rmF9pqV8S7suAoZWja4dJRkFsKQ="
clientFinalrMsgBytes := clientFinalrMsg.Bytes()
....
// Check the final authentication message from the server.
// ex. "v=6xPZm6Qrq8WVGNpjS235dg81OF0="
serverFinalMsg := ...
clientFinalrMsg, err := mech.Next(serverFinalMsg)
if err != nil {
....
return
}
// Dispose the mechanism context.
ctx.Dispose()
Server side
The following pseudo example demonstrates how to authenticate client messages for SCRAM-SHA-256 mechanism using the go-sasl
server. For more complete examples, see go-sasl mechanism plugin testing, TestMechanism().
package main
import (
"github.com/cybergarage/go-sasl/sasl"
)
func main() {
server := sasl.NewServer()
// Receive SCRAM-SHA-256 mechanism negotiation from the client.
mechName := ... // "SCRAM-SHA-256"
mech, err := server.Mechanism(mechName)
if err != nil {
return
}
serverOpts := []mech.Option{...}
ctx, err := mech.Start(serverOpts...)
if err != nil {
return
}
// Check the first authentication message from the client.
// ex. "n,,n=user,r=fyko+d2lbbFgONRv9qkxdawL"
clientFirstMsg := ...
serverFirstMsg, err := mech.Next(clientFirstMsg)
if err != nil {
// Send the error message to the client.
....
return
}
// Send the first server authentication message to the client.
// ex. "r=fyko+d2lbbFgONRv9qkxdawL,s=QSXCR+Q6sek8bf92"
serverFirstMsgBytes := serverFirstMsg.Bytes()
...
// Check the final authentication message from the client.
// ex. "c=biws,r=fyko+d2lbbFgONRv9qkxdawL,p=v0X8v3Bz2T0CJGbJQyF0X+HI4Ts="
clientFinalMsg := ...
finalServerMsg, err := mech.Next(clientFinalMsg)
if err != nil {
// Send the error message to the client.
....
return
}
// Send the final server message to the client.
// ex. "v=rmF9pqV8S7suAoZWja4dJRkFsKQ="
serverFinalMsgBytes := finalServerMsg.Bytes()
....
// Dispose the mechanism context.
ctx.Dispose()
References