2019-06-18 14:28:30 +00:00
|
|
|
package xmpp
|
2016-01-06 15:51:12 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/xml"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2019-05-16 15:46:36 +00:00
|
|
|
func authSASL(socket io.ReadWriter, decoder *xml.Decoder, f StreamFeatures, user string, password string) (err error) {
|
2016-01-06 15:51:12 +00:00
|
|
|
// TODO: Implement other type of SASL Authentication
|
|
|
|
havePlain := false
|
|
|
|
for _, m := range f.Mechanisms.Mechanism {
|
|
|
|
if m == "PLAIN" {
|
|
|
|
havePlain = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !havePlain {
|
2019-06-07 13:23:23 +00:00
|
|
|
err := fmt.Errorf("PLAIN authentication is not supported by server: %v", f.Mechanisms.Mechanism)
|
|
|
|
return NewConnError(err, true)
|
2016-01-06 15:51:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return authPlain(socket, decoder, user, password)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Plain authentication: send base64-encoded \x00 user \x00 password
|
|
|
|
func authPlain(socket io.ReadWriter, decoder *xml.Decoder, user string, password string) error {
|
|
|
|
raw := "\x00" + user + "\x00" + password
|
|
|
|
enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
|
|
|
|
base64.StdEncoding.Encode(enc, []byte(raw))
|
|
|
|
fmt.Fprintf(socket, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>", nsSASL, enc)
|
|
|
|
|
|
|
|
// Next message should be either success or failure.
|
2018-01-13 17:50:17 +00:00
|
|
|
val, err := next(decoder)
|
2016-01-06 15:51:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
switch v := val.(type) {
|
2018-01-13 17:56:38 +00:00
|
|
|
case SASLSuccess:
|
|
|
|
case SASLFailure:
|
2016-01-06 15:51:12 +00:00
|
|
|
// v.Any is type of sub-element in failure, which gives a description of what failed.
|
2019-06-07 13:23:23 +00:00
|
|
|
err := errors.New("auth failure: " + v.Any.Local)
|
|
|
|
return NewConnError(err, true)
|
2016-01-06 15:51:12 +00:00
|
|
|
default:
|
2018-01-13 17:50:17 +00:00
|
|
|
return errors.New("expected SASL success or failure, got " + v.Name())
|
2016-01-06 15:51:12 +00:00
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-01-13 17:50:17 +00:00
|
|
|
// ============================================================================
|
|
|
|
// SASLSuccess
|
|
|
|
|
|
|
|
type SASLSuccess struct {
|
2016-01-06 15:51:12 +00:00
|
|
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl success"`
|
|
|
|
}
|
|
|
|
|
2018-01-13 17:50:17 +00:00
|
|
|
func (SASLSuccess) Name() string {
|
|
|
|
return "sasl:success"
|
|
|
|
}
|
|
|
|
|
|
|
|
type saslSuccessDecoder struct{}
|
|
|
|
|
|
|
|
var saslSuccess saslSuccessDecoder
|
|
|
|
|
|
|
|
func (saslSuccessDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLSuccess, error) {
|
|
|
|
var packet SASLSuccess
|
|
|
|
err := p.DecodeElement(&packet, &se)
|
|
|
|
return packet, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
// SASLFailure
|
|
|
|
|
|
|
|
type SASLFailure struct {
|
2016-01-06 15:51:12 +00:00
|
|
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl failure"`
|
|
|
|
Any xml.Name // error reason is a subelement
|
2017-10-04 23:27:35 +00:00
|
|
|
}
|
2016-01-06 15:51:12 +00:00
|
|
|
|
2018-01-13 17:50:17 +00:00
|
|
|
func (SASLFailure) Name() string {
|
|
|
|
return "sasl:failure"
|
|
|
|
}
|
|
|
|
|
|
|
|
type saslFailureDecoder struct{}
|
|
|
|
|
|
|
|
var saslFailure saslFailureDecoder
|
|
|
|
|
|
|
|
func (saslFailureDecoder) decode(p *xml.Decoder, se xml.StartElement) (SASLFailure, error) {
|
|
|
|
var packet SASLFailure
|
|
|
|
err := p.DecodeElement(&packet, &se)
|
|
|
|
return packet, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
|
|
|
2017-10-04 23:27:35 +00:00
|
|
|
type auth struct {
|
|
|
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-sasl auth"`
|
|
|
|
Mechanism string `xml:"mecanism,attr"`
|
|
|
|
Value string `xml:",innerxml"`
|
2016-01-06 15:51:12 +00:00
|
|
|
}
|
|
|
|
|
2018-01-16 21:33:21 +00:00
|
|
|
type BindBind struct {
|
2016-01-06 15:51:12 +00:00
|
|
|
XMLName xml.Name `xml:"urn:ietf:params:xml:ns:xmpp-bind bind"`
|
2016-02-15 14:22:51 +00:00
|
|
|
Resource string `xml:"resource,omitempty"`
|
|
|
|
Jid string `xml:"jid,omitempty"`
|
|
|
|
}
|
|
|
|
|
2019-06-13 15:22:39 +00:00
|
|
|
func (b *BindBind) Namespace() string {
|
|
|
|
return b.XMLName.Space
|
|
|
|
}
|
|
|
|
|
2016-01-06 15:51:12 +00:00
|
|
|
// Session is obsolete in RFC 6121.
|
|
|
|
// Added for compliance with RFC 3121.
|
|
|
|
// Remove when ejabberd purely conforms to RFC 6121.
|
|
|
|
type sessionSession struct {
|
|
|
|
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
|
|
|
|
}
|