Introduce Credential structure to define auth type
For now we are planning to support Password and OAuthToken. In the future, we would like to add certificate-based authentication.
This commit is contained in:
parent
3b66e31888
commit
9c8353d081
|
@ -34,8 +34,8 @@ Here is an example code to configure a client to allow connecting to a server wi
|
||||||
config := xmpp.Config{
|
config := xmpp.Config{
|
||||||
Address: "localhost:5222",
|
Address: "localhost:5222",
|
||||||
Jid: "test@localhost",
|
Jid: "test@localhost",
|
||||||
Password: "test",
|
Credential: xmpp.Password("Test"),
|
||||||
TLSConfig: tls.Config{InsecureSkipVerify: true},
|
TLSConfig: tls.Config{InsecureSkipVerify: true},
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ func main() {
|
||||||
config := xmpp.Config{
|
config := xmpp.Config{
|
||||||
Address: "localhost:5222",
|
Address: "localhost:5222",
|
||||||
Jid: "test@localhost",
|
Jid: "test@localhost",
|
||||||
Password: "test",
|
Credential: xmpp.Password("Test"),
|
||||||
StreamLogger: os.Stdout,
|
StreamLogger: os.Stdout,
|
||||||
Insecure: true,
|
Insecure: true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func main() {
|
||||||
config := xmpp.Config{
|
config := xmpp.Config{
|
||||||
Address: "localhost:5222",
|
Address: "localhost:5222",
|
||||||
Jid: "test@localhost",
|
Jid: "test@localhost",
|
||||||
Password: "test",
|
Credential: xmpp.Password("test"),
|
||||||
StreamLogger: os.Stdout,
|
StreamLogger: os.Stdout,
|
||||||
Insecure: true,
|
Insecure: true,
|
||||||
// TLSConfig: tls.Config{InsecureSkipVerify: true},
|
// TLSConfig: tls.Config{InsecureSkipVerify: true},
|
||||||
|
|
|
@ -32,9 +32,9 @@ func main() {
|
||||||
|
|
||||||
// 2. Prepare XMPP client
|
// 2. Prepare XMPP client
|
||||||
config := xmpp.Config{
|
config := xmpp.Config{
|
||||||
Address: *address,
|
Address: *address,
|
||||||
Jid: *jid,
|
Jid: *jid,
|
||||||
Password: *password,
|
Credential: xmpp.Password(*password),
|
||||||
// StreamLogger: os.Stdout,
|
// StreamLogger: os.Stdout,
|
||||||
Insecure: true,
|
Insecure: true,
|
||||||
}
|
}
|
||||||
|
|
36
auth.go
36
auth.go
|
@ -10,8 +10,34 @@ import (
|
||||||
"gosrc.io/xmpp/stanza"
|
"gosrc.io/xmpp/stanza"
|
||||||
)
|
)
|
||||||
|
|
||||||
func authSASL(socket io.ReadWriter, decoder *xml.Decoder, f stanza.StreamFeatures, user string, password string) (err error) {
|
// Credential is used to pass the type of secret that will be used to connect to XMPP server.
|
||||||
// TODO: Implement other type of SASL Authentication
|
// It can be either a password or an OAuth 2 bearer token.
|
||||||
|
type Credential struct {
|
||||||
|
secret string
|
||||||
|
mechanisms []string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Password(pwd string) Credential {
|
||||||
|
credential := Credential{
|
||||||
|
secret: pwd,
|
||||||
|
mechanisms: []string{"PLAIN"},
|
||||||
|
}
|
||||||
|
return credential
|
||||||
|
}
|
||||||
|
|
||||||
|
func OAuthToken(token string) Credential {
|
||||||
|
credential := Credential{
|
||||||
|
secret: token,
|
||||||
|
mechanisms: []string{"X-OAUTH2"},
|
||||||
|
}
|
||||||
|
return credential
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Authentication flow for SASL mechanisms
|
||||||
|
|
||||||
|
func authSASL(socket io.ReadWriter, decoder *xml.Decoder, f stanza.StreamFeatures, user string, credential Credential) (err error) {
|
||||||
|
// TODO: Implement other type of SASL mechanisms
|
||||||
havePlain := false
|
havePlain := false
|
||||||
for _, m := range f.Mechanisms.Mechanism {
|
for _, m := range f.Mechanisms.Mechanism {
|
||||||
if m == "PLAIN" {
|
if m == "PLAIN" {
|
||||||
|
@ -24,12 +50,12 @@ func authSASL(socket io.ReadWriter, decoder *xml.Decoder, f stanza.StreamFeature
|
||||||
return NewConnError(err, true)
|
return NewConnError(err, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return authPlain(socket, decoder, user, password)
|
return authPlain(socket, decoder, user, credential)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plain authentication: send base64-encoded \x00 user \x00 password
|
// Plain authentication: send base64-encoded \x00 user \x00 password
|
||||||
func authPlain(socket io.ReadWriter, decoder *xml.Decoder, user string, password string) error {
|
func authPlain(socket io.ReadWriter, decoder *xml.Decoder, user string, credential Credential) error {
|
||||||
raw := "\x00" + user + "\x00" + password
|
raw := "\x00" + user + "\x00" + credential.secret
|
||||||
enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
|
enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw)))
|
||||||
base64.StdEncoding.Encode(enc, []byte(raw))
|
base64.StdEncoding.Encode(enc, []byte(raw))
|
||||||
fmt.Fprintf(socket, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>", stanza.NSSASL, enc)
|
fmt.Fprintf(socket, "<auth xmlns='%s' mechanism='PLAIN'>%s</auth>", stanza.NSSASL, enc)
|
||||||
|
|
|
@ -111,8 +111,8 @@ func NewClient(config Config, r *Router) (c *Client, err error) {
|
||||||
return nil, NewConnError(err, true)
|
return nil, NewConnError(err, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Password == "" {
|
if config.Credential.secret == "" {
|
||||||
err = errors.New("missing password")
|
err = errors.New("missing credential")
|
||||||
return nil, NewConnError(err, true)
|
return nil, NewConnError(err, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ func TestClient_Connect(t *testing.T) {
|
||||||
mock.Start(t, testXMPPAddress, handlerConnectSuccess)
|
mock.Start(t, testXMPPAddress, handlerConnectSuccess)
|
||||||
|
|
||||||
// Test / Check result
|
// Test / Check result
|
||||||
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Password: "test", Insecure: true}
|
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Credential: Password("test"), Insecure: true}
|
||||||
|
|
||||||
var client *Client
|
var client *Client
|
||||||
var err error
|
var err error
|
||||||
|
@ -47,7 +47,7 @@ func TestClient_NoInsecure(t *testing.T) {
|
||||||
mock.Start(t, testXMPPAddress, handlerAbortTLS)
|
mock.Start(t, testXMPPAddress, handlerAbortTLS)
|
||||||
|
|
||||||
// Test / Check result
|
// Test / Check result
|
||||||
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Password: "test"}
|
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Credential: Password("test")}
|
||||||
|
|
||||||
var client *Client
|
var client *Client
|
||||||
var err error
|
var err error
|
||||||
|
@ -71,7 +71,7 @@ func TestClient_FeaturesTracking(t *testing.T) {
|
||||||
mock.Start(t, testXMPPAddress, handlerAbortTLS)
|
mock.Start(t, testXMPPAddress, handlerAbortTLS)
|
||||||
|
|
||||||
// Test / Check result
|
// Test / Check result
|
||||||
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Password: "test"}
|
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Credential: Password("test")}
|
||||||
|
|
||||||
var client *Client
|
var client *Client
|
||||||
var err error
|
var err error
|
||||||
|
@ -94,7 +94,7 @@ func TestClient_RFC3921Session(t *testing.T) {
|
||||||
mock.Start(t, testXMPPAddress, handlerConnectWithSession)
|
mock.Start(t, testXMPPAddress, handlerConnectWithSession)
|
||||||
|
|
||||||
// Test / Check result
|
// Test / Check result
|
||||||
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Password: "test", Insecure: true}
|
config := Config{Address: testXMPPAddress, Jid: "test@localhost", Credential: Password("test"), Insecure: true}
|
||||||
|
|
||||||
var client *Client
|
var client *Client
|
||||||
var err error
|
var err error
|
||||||
|
|
|
@ -32,9 +32,9 @@ func sendxmpp(cmd *cobra.Command, args []string) {
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
client, err := xmpp.NewClient(xmpp.Config{
|
client, err := xmpp.NewClient(xmpp.Config{
|
||||||
Jid: viper.GetString("jid"),
|
Jid: viper.GetString("jid"),
|
||||||
Address: viper.GetString("addr"),
|
Address: viper.GetString("addr"),
|
||||||
Password: viper.GetString("password"),
|
Credential: xmpp.Password(viper.GetString("password")),
|
||||||
}, xmpp.NewRouter())
|
}, xmpp.NewRouter())
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -143,6 +143,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522 h1:bhOzK9QyoD0ogCnFro1m2mz41+Ib0oOhfJnBp5MR4K4=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522 h1:bhOzK9QyoD0ogCnFro1m2mz41+Ib0oOhfJnBp5MR4K4=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
|
|
@ -10,7 +10,7 @@ type Config struct {
|
||||||
Address string
|
Address string
|
||||||
Jid string
|
Jid string
|
||||||
parsedJid *Jid // For easier manipulation
|
parsedJid *Jid // For easier manipulation
|
||||||
Password string
|
Credential Credential
|
||||||
StreamLogger *os.File // Used for debugging
|
StreamLogger *os.File // Used for debugging
|
||||||
Lang string // TODO: should default to 'en'
|
Lang string // TODO: should default to 'en'
|
||||||
ConnectTimeout int // Client timeout in seconds. Default to 15
|
ConnectTimeout int // Client timeout in seconds. Default to 15
|
||||||
|
|
|
@ -168,7 +168,7 @@ func (s *Session) auth(o Config) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s.err = authSASL(s.streamLogger, s.decoder, s.Features, o.parsedJid.Node, o.Password)
|
s.err = authSASL(s.streamLogger, s.decoder, s.Features, o.parsedJid.Node, o.Credential)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to resume session using stream management
|
// Attempt to resume session using stream management
|
||||||
|
|
Loading…
Reference in a new issue