Clean-up & refactor

This commit is contained in:
Mickael Remond 2019-06-29 16:49:54 +02:00
parent 838c059398
commit 40e907e8ee
No known key found for this signature in database
GPG key ID: E6F6045D79965AA3
5 changed files with 81 additions and 27 deletions

View file

@ -161,7 +161,7 @@ func readAuth(t *testing.T, decoder *xml.Decoder) string {
} }
var nv interface{} var nv interface{}
nv = &stanza.Auth{} nv = &stanza.SASLAuth{}
// Decode element into pointer storage // Decode element into pointer storage
if err = decoder.DecodeElement(nv, &se); err != nil { if err = decoder.DecodeElement(nv, &se); err != nil {
t.Errorf("cannot decode auth: %s", err) t.Errorf("cannot decode auth: %s", err)
@ -169,14 +169,14 @@ func readAuth(t *testing.T, decoder *xml.Decoder) string {
} }
switch v := nv.(type) { switch v := nv.(type) {
case *stanza.Auth: case *stanza.SASLAuth:
return v.Value return v.Value
} }
return "" return ""
} }
func sendBindFeature(t *testing.T, c net.Conn, _ *xml.Decoder) { func sendBindFeature(t *testing.T, c net.Conn, _ *xml.Decoder) {
// This is a basic server, supporting only 1 stream feature: SASL Plain Auth // This is a basic server, supporting only 1 stream feature after auth: session binding
features := `<stream:features> features := `<stream:features>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
</stream:features>` </stream:features>`
@ -201,7 +201,7 @@ func bind(t *testing.T, c net.Conn, decoder *xml.Decoder) {
// TODO Check all elements // TODO Check all elements
switch iq.Payload.(type) { switch iq.Payload.(type) {
case *stanza.BindBind: case *stanza.Bind:
result := `<iq id='%s' type='result'> result := `<iq id='%s' type='result'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>
<jid>%s</jid> <jid>%s</jid>

View file

@ -167,7 +167,7 @@ func (s *Session) bind(o Config) {
// TODO Check all elements // TODO Check all elements
switch payload := iq.Payload.(type) { switch payload := iq.Payload.(type) {
case *stanza.BindBind: case *stanza.Bind:
s.BindJid = payload.Jid // our local id (with possibly randomly generated resource s.BindJid = payload.Jid // our local id (with possibly randomly generated resource
default: default:
s.err = errors.New("iq bind result missing") s.err = errors.New("iq bind result missing")
@ -176,15 +176,14 @@ func (s *Session) bind(o Config) {
return return
} }
// TODO: remove when ejabberd is fixed: https://github.com/processone/ejabberd/issues/869 // After the bind, if the session is not optional (as per old RFC 3921), we send the session open iq.
// After the bind, if the session is required (as per old RFC 3921), we send the session open iq
func (s *Session) rfc3921Session(o Config) { func (s *Session) rfc3921Session(o Config) {
if s.err != nil { if s.err != nil {
return return
} }
var iq stanza.IQ var iq stanza.IQ
if s.Features.Session.Optional.Local != "" { if s.Features.Session.XMLName.Local == "session" && !s.Features.Session.Optional {
fmt.Fprintf(s.streamLogger, "<iq type='set' id='%s'><session xmlns='%s'/></iq>", s.PacketId(), stanza.NSSession) fmt.Fprintf(s.streamLogger, "<iq type='set' id='%s'><session xmlns='%s'/></iq>", s.PacketId(), stanza.NSSession)
if s.err = s.decoder.Decode(&iq); s.err != nil { if s.err = s.decoder.Decode(&iq); s.err != nil {
s.err = errors.New("expecting iq result after session open: " + s.err.Error()) s.err = errors.New("expecting iq result after session open: " + s.err.Error())

View file

@ -3,8 +3,20 @@ package stanza
import "encoding/xml" import "encoding/xml"
// ============================================================================ // ============================================================================
// SASLSuccess
// SASLAuth implements SASL Authentication initiation.
// Reference: https://tools.ietf.org/html/rfc6120#section-6.4.2
type SASLAuth struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"`
Mechanism string `xml:"mechanism,attr"`
Value string `xml:",innerxml"`
}
// ============================================================================
// SASLSuccess implements SASL Success nonza, sent by server as a result of the
// SASL auth negotiation.
// Reference: https://tools.ietf.org/html/rfc6120#section-6.4.6
type SASLSuccess struct { type SASLSuccess struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"` XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"`
} }
@ -13,6 +25,7 @@ func (SASLSuccess) Name() string {
return "sasl:success" return "sasl:success"
} }
// SASLSuccess decoding
type saslSuccessDecoder struct{} type saslSuccessDecoder struct{}
var saslSuccess saslSuccessDecoder var saslSuccess saslSuccessDecoder
@ -24,8 +37,8 @@ func (saslSuccessDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLSucce
} }
// ============================================================================ // ============================================================================
// SASLFailure
// SASLFailure
type SASLFailure struct { type SASLFailure struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl failure"` XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl failure"`
Any xml.Name // error reason is a subelement Any xml.Name // error reason is a subelement
@ -35,6 +48,7 @@ func (SASLFailure) Name() string {
return "sasl:failure" return "sasl:failure"
} }
// SASLFailure decoding
type saslFailureDecoder struct{} type saslFailureDecoder struct{}
var saslFailure saslFailureDecoder var saslFailure saslFailureDecoder
@ -45,35 +59,46 @@ func (saslFailureDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLFailu
return packet, err return packet, err
} }
// ============================================================================ // ===========================================================================
// Resource binding
type Auth struct { // Bind is an IQ payload used during session negotiation to bind user resource
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"` // to the current XMPP stream.
Mechanism string `xml:"mecanism,attr"` // Reference: https://tools.ietf.org/html/rfc6120#section-7
Value string `xml:",innerxml"` type Bind struct {
}
type BindBind struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"` XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
Resource string `xml:"resource,omitempty"` Resource string `xml:"resource,omitempty"`
Jid string `xml:"jid,omitempty"` Jid string `xml:"jid,omitempty"`
} }
func (b *BindBind) Namespace() string { func (b *Bind) Namespace() string {
return b.XMLName.Space return b.XMLName.Space
} }
// Session is obsolete in RFC 6121. // ============================================================================
// Added for compliance with RFC 3121. // Session (Obsolete)
// Remove when ejabberd purely conforms to RFC 6121.
type sessionSession struct { // Session is both a stream feature and an obsolete IQ Payload, used to bind a
// resource to the current XMPP stream on RFC 3121 only XMPP servers.
// Session is obsolete in RFC 6121. It is added to Fluux XMPP for compliance
// with RFC 3121.
// Reference: https://xmpp.org/rfcs/rfc3921.html#session
//
// This is the draft defining how to handle the transition:
// https://tools.ietf.org/html/draft-cridland-xmpp-session-01
type StreamSession struct {
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-session session"` XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-session session"`
Optional xml.Name // If it does exist, it mean we are not required to open session Optional bool // If element does exist, it mean we are not required to open session
}
func (s *StreamSession) Namespace() string {
return s.XMLName.Space
} }
// ============================================================================ // ============================================================================
// Registry init // Registry init
func init() { func init() {
TypeRegistry.MapExtension(PKTIQ, xml.Name{"urn:ietf:params:xml:ns:xmpp-bind", "bind"}, BindBind{}) TypeRegistry.MapExtension(PKTIQ, xml.Name{"urn:ietf:params:xml:ns:xmpp-bind", "bind"}, Bind{})
TypeRegistry.MapExtension(PKTIQ, xml.Name{"urn:ietf:params:xml:ns:xmpp-session", "bind"}, StreamSession{})
} }

29
stanza/sasl_auth_test.go Normal file
View file

@ -0,0 +1,29 @@
package stanza_test
import (
"encoding/xml"
"testing"
"gosrc.io/xmpp/stanza"
)
// Check that we can detect optional session from advertised stream features
func TestSession(t *testing.T) {
streamFeatures := stanza.StreamFeatures{Session: stanza.StreamSession{Optional: true}}
data, err := xml.Marshal(streamFeatures)
if err != nil {
t.Errorf("cannot marshal xml structure: %s", err)
}
parsedStream := stanza.StreamFeatures{}
if err = xml.Unmarshal(data, &parsedStream); err != nil {
t.Errorf("Unmarshal(%s) returned error", data)
}
if !parsedStream.Session.Optional {
t.Error("Session should be optional")
}
}
// TODO Test Sasl mechanism

View file

@ -17,9 +17,10 @@ type StreamFeatures struct {
// Stream features // Stream features
StartTLS tlsStartTLS StartTLS tlsStartTLS
Mechanisms saslMechanisms Mechanisms saslMechanisms
Bind BindBind Bind Bind
Session sessionSession
StreamManagement streamManagement StreamManagement streamManagement
// Obsolete
Session StreamSession
// ProcessOne Stream Features // ProcessOne Stream Features
P1Push p1Push P1Push p1Push
P1Rebind p1Rebind P1Rebind p1Rebind