Documentation ¶
Overview ¶
Package scram provides client and server implementations of the Salted Challenge Response Authentication Mechanism (SCRAM) described in RFC-5802 and RFC-7677.
Usage ¶
The scram package provides two variables, `SHA1` and `SHA256`, that are used to construct Client or Server objects.
clientSHA1, err := scram.SHA1.NewClient(username, password, authID) clientSHA256, err := scram.SHA256.NewClient(username, password, authID) serverSHA1, err := scram.SHA1.NewServer(credentialLookupFcn) serverSHA256, err := scram.SHA256.NewServer(credentialLookupFcn)
These objects are used to construct ClientConversation or ServerConversation objects that are used to carry out authentication.
Example ¶
package main import "github.com/xdg-go/scram" func main() { // Get Client with username, password and (optional) authorization ID. clientSHA1, err := scram.SHA1.NewClient("mulder", "trustno1", "") if err != nil { panic(err) } // Prepare the authentication conversation. Use the empty string as the // initial server message argument to start the conversation. conv := clientSHA1.NewConversation() var serverMsg string // Get the first message, send it and read the response. firstMsg, err := conv.Step(serverMsg) if err != nil { panic(err) } serverMsg = sendClientMsg(firstMsg) // Get the second message, send it, and read the response. secondMsg, err := conv.Step(serverMsg) if err != nil { panic(err) } serverMsg = sendClientMsg(secondMsg) // Validate the server's final message. We have no further message to // send so ignore that return value. _, err = conv.Step(serverMsg) if err != nil { panic(err) } return } func sendClientMsg(s string) string { // A real implementation would send this to a server and read a reply. return "" }
Output:
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
Client implements the client side of SCRAM authentication. It holds configuration values needed to initialize new client-side conversations for a specific username, password and authorization ID tuple. Client caches the computationally-expensive parts of a SCRAM conversation as described in RFC-5802. If repeated authentication conversations may be required for a user (e.g. disconnect/reconnect), the user's Client should be preserved.
For security reasons, Clients have a default minimum PBKDF2 iteration count of 4096. If a server requests a smaller iteration count, an authentication conversation will error.
A Client can also be used by a server application to construct the hashed authentication values to be stored for a new user. See StoredCredentials() for more.
func (*Client) GetStoredCredentials ¶
func (c *Client) GetStoredCredentials(kf KeyFactors) StoredCredentials
GetStoredCredentials takes a salt and iteration count structure and provides the values that must be stored by a server to authentication a user. These values are what the Server credential lookup function must return for a given username.
func (*Client) NewConversation ¶
func (c *Client) NewConversation() *ClientConversation
NewConversation constructs a client-side authentication conversation. Conversations cannot be reused, so this must be called for each new authentication attempt.
func (*Client) WithMinIterations ¶
WithMinIterations changes minimum required PBKDF2 iteration count.
func (*Client) WithNonceGenerator ¶
func (c *Client) WithNonceGenerator(ng NonceGeneratorFcn) *Client
WithNonceGenerator replaces the default nonce generator (base64 encoding of 24 bytes from crypto/rand) with a custom generator. This is provided for testing or for users with custom nonce requirements.
type ClientConversation ¶
type ClientConversation struct {
// contains filtered or unexported fields
}
ClientConversation implements the client-side of an authentication conversation with a server. A new conversation must be created for each authentication attempt.
func (*ClientConversation) Done ¶
func (cc *ClientConversation) Done() bool
Done returns true if the conversation is completed or has errored.
func (*ClientConversation) Step ¶
func (cc *ClientConversation) Step(challenge string) (response string, err error)
Step takes a string provided from a server (or just an empty string for the very first conversation step) and attempts to move the authentication conversation forward. It returns a string to be sent to the server or an error if the server message is invalid. Calling Step after a conversation completes is also an error.
func (*ClientConversation) Valid ¶
func (cc *ClientConversation) Valid() bool
Valid returns true if the conversation successfully authenticated with the server, including counter-validation that the server actually has the user's stored credentials.
type CredentialLookup ¶
type CredentialLookup func(string) (StoredCredentials, error)
CredentialLookup is a callback to provide StoredCredentials for a given username. This is used to configure Server objects.
NOTE: these are specific to a given hash function. The callback provided to a Server with a given hash function must provide the corresponding StoredCredentials.
type HashGeneratorFcn ¶
HashGeneratorFcn abstracts a factory function that returns a hash.Hash value to be used for SCRAM operations. Generally, one would use the provided package variables, `scram.SHA1` and `scram.SHA256`, for the most common forms of SCRAM.
var SHA1 HashGeneratorFcn = func() hash.Hash { return sha1.New() }
SHA1 is a function that returns a crypto/sha1 hasher and should be used to create Client objects configured for SHA-1 hashing.
var SHA256 HashGeneratorFcn = func() hash.Hash { return sha256.New() }
SHA256 is a function that returns a crypto/sha256 hasher and should be used to create Client objects configured for SHA-256 hashing.
func (HashGeneratorFcn) NewClient ¶
func (f HashGeneratorFcn) NewClient(username, password, authzID string) (*Client, error)
NewClient constructs a SCRAM client component based on a given hash.Hash factory receiver. This constructor will normalize the username, password and authzID via the SASLprep algorithm, as recommended by RFC-5802. If SASLprep fails, the method returns an error.
func (HashGeneratorFcn) NewClientUnprepped ¶
func (f HashGeneratorFcn) NewClientUnprepped(username, password, authzID string) (*Client, error)
NewClientUnprepped acts like NewClient, except none of the arguments will be normalized via SASLprep. This is not generally recommended, but is provided for users that may have custom normalization needs.
func (HashGeneratorFcn) NewServer ¶
func (f HashGeneratorFcn) NewServer(cl CredentialLookup) (*Server, error)
NewServer constructs a SCRAM server component based on a given hash.Hash factory receiver. To be maximally generic, it uses dependency injection to handle credential lookup, which is the process of turning a username string into a struct with stored credentials for authentication.
type KeyFactors ¶
KeyFactors represent the two server-provided factors needed to compute client credentials for authentication. Salt is decoded bytes (i.e. not base64), but in string form so that KeyFactors can be used as a map key for cached credentials.
type NonceGeneratorFcn ¶
type NonceGeneratorFcn func() string
NonceGeneratorFcn defines a function that returns a string of high-quality random printable ASCII characters EXCLUDING the comma (',') character. The default nonce generator provides Base64 encoding of 24 bytes from crypto/rand.
type Server ¶
Server implements the server side of SCRAM authentication. It holds configuration values needed to initialize new server-side conversations. Generally, this can be persistent within an application.
func (*Server) NewConversation ¶
func (s *Server) NewConversation() *ServerConversation
NewConversation constructs a server-side authentication conversation. Conversations cannot be reused, so this must be called for each new authentication attempt.
func (*Server) WithNonceGenerator ¶
func (s *Server) WithNonceGenerator(ng NonceGeneratorFcn) *Server
WithNonceGenerator replaces the default nonce generator (base64 encoding of 24 bytes from crypto/rand) with a custom generator. This is provided for testing or for users with custom nonce requirements.
type ServerConversation ¶
type ServerConversation struct {
// contains filtered or unexported fields
}
ServerConversation implements the server-side of an authentication conversation with a client. A new conversation must be created for each authentication attempt.
func (*ServerConversation) AuthzID ¶
func (sc *ServerConversation) AuthzID() string
AuthzID returns the (optional) client-provided authorization identity, if any. If one was not provided, it returns the empty string. This is valid to call if the first conversation Step() is successful.
func (*ServerConversation) Done ¶
func (sc *ServerConversation) Done() bool
Done returns true if the conversation is completed or has errored.
func (*ServerConversation) Step ¶
func (sc *ServerConversation) Step(challenge string) (response string, err error)
Step takes a string provided from a client and attempts to move the authentication conversation forward. It returns a string to be sent to the client or an error if the client message is invalid. Calling Step after a conversation completes is also an error.
func (*ServerConversation) Username ¶
func (sc *ServerConversation) Username() string
Username returns the client-provided username. This is valid to call if the first conversation Step() is successful.
func (*ServerConversation) Valid ¶
func (sc *ServerConversation) Valid() bool
Valid returns true if the conversation successfully authenticated the client.
type StoredCredentials ¶
type StoredCredentials struct { KeyFactors StoredKey []byte ServerKey []byte }
StoredCredentials are the values that a server must store for a given username to allow authentication. They include the salt and iteration count, plus the derived values to authenticate a client and for the server to authenticate itself back to the client.
NOTE: these are specific to a given hash function. To allow a user to authenticate with either SCRAM-SHA-1 or SCRAM-SHA-256, two sets of StoredCredentials must be created and stored, one for each hash function.