forked from jshiffer/go-xmpp
Authentication improvements. (#165)
* Add XEP-0474 support. * Add missing error handling.
This commit is contained in:
parent
31c7eb6919
commit
39f5b80375
54
xmpp.go
54
xmpp.go
@ -34,6 +34,7 @@ import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"slices"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@ -46,6 +47,7 @@ const (
|
||||
nsTLS = "urn:ietf:params:xml:ns:xmpp-tls"
|
||||
nsSASL = "urn:ietf:params:xml:ns:xmpp-sasl"
|
||||
nsBind = "urn:ietf:params:xml:ns:xmpp-bind"
|
||||
nsSASLCB = "urn:xmpp:sasl-cb:0"
|
||||
nsClient = "jabber:client"
|
||||
nsSession = "urn:ietf:params:xml:ns:xmpp-session"
|
||||
)
|
||||
@ -521,7 +523,7 @@ func (c *Client) init(o *Options) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var serverNonce string
|
||||
var serverNonce, dgProtect string
|
||||
var salt []byte
|
||||
var iterations int
|
||||
for _, serverReply := range strings.Split(string(b), ",") {
|
||||
@ -533,6 +535,9 @@ func (c *Client) init(o *Options) error {
|
||||
}
|
||||
case strings.HasPrefix(serverReply, "s="):
|
||||
salt, err = base64.StdEncoding.DecodeString(strings.SplitN(serverReply, "=", 2)[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if string(salt) == "" {
|
||||
return errors.New("SCRAM: server sent empty salt")
|
||||
}
|
||||
@ -542,6 +547,37 @@ func (c *Client) init(o *Options) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case strings.HasPrefix(serverReply, "d="):
|
||||
serverDgProtectHash := strings.SplitN(serverReply, "=", 2)[1]
|
||||
slices.Sort(f.Mechanisms.Mechanism)
|
||||
for _, mech := range f.Mechanisms.Mechanism {
|
||||
if dgProtect == "" {
|
||||
dgProtect = mech
|
||||
} else {
|
||||
dgProtect = dgProtect + "," + mech
|
||||
}
|
||||
}
|
||||
dgProtect = dgProtect + "|"
|
||||
var cbsSlice []string
|
||||
for _, cbs := range f.ChannelBindings.ChannelBinding {
|
||||
cbsSlice = append(cbsSlice, cbs.Type)
|
||||
}
|
||||
slices.Sort(cbsSlice)
|
||||
for i, cb := range cbsSlice {
|
||||
if i == 0 {
|
||||
dgProtect = dgProtect + cb
|
||||
} else {
|
||||
dgProtect = dgProtect + "," + cb
|
||||
}
|
||||
}
|
||||
dgh := shaNewFn()
|
||||
dgh.Write([]byte(dgProtect))
|
||||
dHash := dgh.Sum(nil)
|
||||
dHashb64 := base64.StdEncoding.EncodeToString(dHash)
|
||||
if dHashb64 != serverDgProtectHash {
|
||||
return errors.New("SCRAM: downgrade protection hash mismatch")
|
||||
}
|
||||
dgh.Reset()
|
||||
default:
|
||||
return errors.New("unexpected content in SCRAM challenge")
|
||||
}
|
||||
@ -1194,12 +1230,12 @@ func (c *Client) Roster() error {
|
||||
|
||||
// RFC 3920 C.1 Streams name space
|
||||
type streamFeatures struct {
|
||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
|
||||
StartTLS *tlsStartTLS
|
||||
Mechanisms saslMechanisms
|
||||
ChannelBinding saslChannelBinding
|
||||
Bind bindBind
|
||||
Session bool
|
||||
XMLName xml.Name `xml:"http://etherx.jabber.org/streams features"`
|
||||
StartTLS *tlsStartTLS
|
||||
Mechanisms saslMechanisms
|
||||
ChannelBindings saslChannelBindings
|
||||
Bind bindBind
|
||||
Session bool
|
||||
}
|
||||
|
||||
type streamError struct {
|
||||
@ -1233,7 +1269,7 @@ type saslAuth struct {
|
||||
Mechanism string `xml:",attr"`
|
||||
}
|
||||
|
||||
type saslChannelBinding struct {
|
||||
type saslChannelBindings struct {
|
||||
XMLName xml.Name `xml:"sasl-channel-binding"`
|
||||
Text string `xml:",chardata"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
@ -1436,6 +1472,8 @@ func next(p *xml.Decoder) (xml.Name, interface{}, error) {
|
||||
nv = &saslSuccess{}
|
||||
case nsSASL + " failure":
|
||||
nv = &saslFailure{}
|
||||
case nsSASLCB + " sasl-channel-binding":
|
||||
nv = &saslChannelBindings{}
|
||||
case nsBind + " bind":
|
||||
nv = &bindBind{}
|
||||
case nsClient + " message":
|
||||
|
Loading…
Reference in New Issue
Block a user