mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-22 20:09:41 +01:00
accounts: Add SASL PLAIN handler
This commit is contained in:
parent
1679bc9ac2
commit
70665850aa
@ -4,11 +4,17 @@
|
|||||||
package irc
|
package irc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/DanielOaks/girc-go/ircmsg"
|
"github.com/DanielOaks/girc-go/ircmsg"
|
||||||
|
"github.com/tidwall/buntdb"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -23,6 +29,9 @@ var (
|
|||||||
NoAccount = ClientAccount{
|
NoAccount = ClientAccount{
|
||||||
Name: "*", // * is used until actual account name is set
|
Name: "*", // * is used until actual account name is set
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generic sasl fail error
|
||||||
|
errSaslFail = errors.New("SASL failed")
|
||||||
)
|
)
|
||||||
|
|
||||||
// ClientAccount represents a user account.
|
// ClientAccount represents a user account.
|
||||||
@ -113,12 +122,84 @@ func authenticateHandler(server *Server, client *Client, msg ircmsg.IrcMessage)
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sasl is being done now by the handler, so we empty the client's vars now
|
||||||
|
client.saslInProgress = false
|
||||||
|
client.saslMechanism = ""
|
||||||
|
client.saslValue = ""
|
||||||
|
|
||||||
return handler(server, client, client.saslMechanism, data)
|
return handler(server, client, client.saslMechanism, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// authPlainHandler parses the SASL PLAIN mechanism.
|
// authPlainHandler parses the SASL PLAIN mechanism.
|
||||||
func authPlainHandler(server *Server, client *Client, mechanism string, value []byte) bool {
|
func authPlainHandler(server *Server, client *Client, mechanism string, value []byte) bool {
|
||||||
client.Send(nil, server.nameString, ERR_SASLFAIL, client.nickString, "SASL authentication failed: Mechanism not yet implemented")
|
splitValue := bytes.Split(value, []byte{'\000'})
|
||||||
|
|
||||||
|
if len(splitValue) != 3 {
|
||||||
|
client.Send(nil, server.nameString, ERR_SASLFAIL, client.nickString, "SASL authentication failed: Invalid auth blob")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
accountString := string(splitValue[0])
|
||||||
|
authzid := string(splitValue[1])
|
||||||
|
|
||||||
|
if accountString != authzid {
|
||||||
|
client.Send(nil, server.nameString, ERR_SASLFAIL, client.nickString, "SASL authentication failed: authcid and authzid should be the same")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// casefolding, rough for now bit will improve later.
|
||||||
|
// keep it the same as in the REG CREATE stage
|
||||||
|
accountString = NewName(accountString).String()
|
||||||
|
|
||||||
|
// load and check acct data all in one update to prevent races.
|
||||||
|
// as noted elsewhere, change to proper locking for Account type later probably
|
||||||
|
err := server.store.Update(func(tx *buntdb.Tx) error {
|
||||||
|
credText, err := tx.Get(fmt.Sprintf(keyAccountCredentials, accountString))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var creds AccountCredentials
|
||||||
|
err = json.Unmarshal([]byte(credText), &creds)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure creds are valid
|
||||||
|
password := string(splitValue[2])
|
||||||
|
if len(creds.PassphraseHash) < 1 || len(creds.PassphraseSalt) < 1 || len(password) < 1 {
|
||||||
|
return errSaslFail
|
||||||
|
}
|
||||||
|
err = server.passwords.CompareHashAndPassword(creds.PassphraseHash, creds.PassphraseSalt, password)
|
||||||
|
|
||||||
|
// succeeded, load account info if necessary
|
||||||
|
account, exists := server.accounts[accountString]
|
||||||
|
if !exists {
|
||||||
|
name, _ := tx.Get(fmt.Sprintf(keyAccountName, accountString))
|
||||||
|
regTime, _ := tx.Get(fmt.Sprintf(keyAccountRegTime, accountString))
|
||||||
|
regTimeInt, _ := strconv.ParseInt(regTime, 10, 64)
|
||||||
|
accountInfo := ClientAccount{
|
||||||
|
Name: name,
|
||||||
|
RegisteredAt: time.Unix(regTimeInt, 0),
|
||||||
|
Clients: []*Client{},
|
||||||
|
}
|
||||||
|
server.accounts[accountString] = &accountInfo
|
||||||
|
account = &accountInfo
|
||||||
|
}
|
||||||
|
|
||||||
|
account.Clients = append(account.Clients, client)
|
||||||
|
client.account = account
|
||||||
|
|
||||||
|
return err
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
client.Send(nil, server.nameString, ERR_SASLFAIL, client.nickString, "SASL authentication failed")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Send(nil, server.nameString, RPL_LOGGEDIN, client.nickString, client.nickMaskString, client.account.Name, fmt.Sprintf("You are now logged in as %s", client.account.Name))
|
||||||
|
client.Send(nil, server.nameString, RPL_SASLSUCCESS, client.nickString, "SASL authentication successful")
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ func regCreateHandler(server *Server, client *Client, msg ircmsg.IrcMessage) boo
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Could not marshal creds: %s", err)
|
return fmt.Errorf("Could not marshal creds: %s", err)
|
||||||
}
|
}
|
||||||
tx.Set(keyAccountCredentials, string(credText), nil)
|
tx.Set(fmt.Sprintf(keyAccountCredentials, account), string(credText), nil)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user