From 88f429802e2e9f3ee6065c26eae8459064555cf3 Mon Sep 17 00:00:00 2001 From: Joshua Martin Date: Thu, 17 Sep 2015 10:43:05 -0700 Subject: [PATCH] Add OAuth2 support Use provided host for certificate verification Remove redundant ANONYMOUS mechanism support --- xmpp.go | 37 +++++++++++++++++++++++-------------- xmpp_ping.go | 22 +++++++++++----------- xmpp_subscription.go | 20 ++++++++++---------- 3 files changed, 44 insertions(+), 35 deletions(-) diff --git a/xmpp.go b/xmpp.go index 73d87d6..629449e 100644 --- a/xmpp.go +++ b/xmpp.go @@ -127,6 +127,16 @@ type Options struct { // from the server. Use "" to let the server generate one for your client. Resource string + // OAuthScope provides go-xmpp the required scope for OAuth2 authentication. + OAuthScope string + + // OAuthToken provides go-xmpp with the required OAuth2 token used to authenticate + OAuthToken string + + // OAuthXmlNs provides go-xmpp with the required namespaced used for OAuth2 authentication. This is + // provided to the server as the xmlns:auth attribute of the OAuth2 authentication request. + OAuthXmlNs string + // TLS Config TLSConfig *tls.Config @@ -163,6 +173,9 @@ func (o Options) NewClient() (*Client, error) { if err != nil { return nil, err } + if strings.LastIndex(o.Host, ":") > 0 { + host = host[:strings.LastIndex(o.Host, ":")] + } client := new(Client) if o.NoTLS { @@ -172,15 +185,12 @@ func (o Options) NewClient() (*Client, error) { if o.TLSConfig != nil { tlsconn = tls.Client(c, o.TLSConfig) } else { - DefaultConfig.ServerName = strings.Split(o.User, "@")[1] + DefaultConfig.ServerName = host tlsconn = tls.Client(c, &DefaultConfig) } if err = tlsconn.Handshake(); err != nil { return nil, err } - if strings.LastIndex(o.Host, ":") > 0 { - host = host[:strings.LastIndex(o.Host, ":")] - } insecureSkipVerify := DefaultConfig.InsecureSkipVerify if o.TLSConfig != nil { insecureSkipVerify = o.TLSConfig.InsecureSkipVerify @@ -274,11 +284,13 @@ func (c *Client) init(o *Options) error { } var domain string + var user string a := strings.SplitN(o.User, "@", 2) if len(o.User) > 0 { if len(a) != 2 { return errors.New("xmpp: invalid username (want user@domain): " + o.User) } + user = a[0] domain = a[1] } // Otherwise, we'll be attempting ANONYMOUS @@ -315,19 +327,16 @@ func (c *Client) init(o *Options) error { mechanism := "" for _, m := range f.Mechanisms.Mechanism { - if m == "ANONYMOUS" { + if m == "X-OAUTH2" && o.OAuthToken != "" && o.OAuthScope != "" { mechanism = m - fmt.Fprintf(c.conn, "\n", nsSASL) + // Oauth authentication: send base64-encoded \x00 user \x00 token. + raw := "\x00" + user + "\x00" + o.OAuthToken + enc := make([]byte, base64.StdEncoding.EncodedLen(len(raw))) + base64.StdEncoding.Encode(enc, []byte(raw)) + fmt.Fprintf(c.conn, "%s\n", nsSASL, o.OAuthXmlNs, enc) break } - - a := strings.SplitN(o.User, "@", 2) - if len(a) != 2 { - return errors.New("xmpp: invalid username (want user@domain): " + o.User) - } - user := a[0] - domain := a[1] - if m == "PLAIN" { mechanism = m // Plain authentication: send base64-encoded \x00 user \x00 password. diff --git a/xmpp_ping.go b/xmpp_ping.go index 88b07cc..05a3a84 100644 --- a/xmpp_ping.go +++ b/xmpp_ping.go @@ -1,19 +1,19 @@ package xmpp import ( - "fmt" + "fmt" ) -func (c* Client) PingC2S(jid, server string) { - fmt.Fprintf(c.conn, "\n" + - "\n" + - "", - xmlEscape(jid), xmlEscape(server)) +func (c *Client) PingC2S(jid, server string) { + fmt.Fprintf(c.conn, "\n"+ + "\n"+ + "", + xmlEscape(jid), xmlEscape(server)) } -func (c* Client) PingS2S(fromServer, toServer string) { - fmt.Fprintf(c.conn, "\n" + - "\n" + - "", - xmlEscape(fromServer), xmlEscape(toServer)) +func (c *Client) PingS2S(fromServer, toServer string) { + fmt.Fprintf(c.conn, "\n"+ + "\n"+ + "", + xmlEscape(fromServer), xmlEscape(toServer)) } diff --git a/xmpp_subscription.go b/xmpp_subscription.go index b714c12..eb29314 100644 --- a/xmpp_subscription.go +++ b/xmpp_subscription.go @@ -1,20 +1,20 @@ package xmpp import ( - "fmt" + "fmt" ) -func (c* Client) ApproveSubscription(jid string) { - fmt.Fprintf(c.conn, "", - xmlEscape(jid)) +func (c *Client) ApproveSubscription(jid string) { + fmt.Fprintf(c.conn, "", + xmlEscape(jid)) } -func (c* Client) RevokeSubscription(jid string) { - fmt.Fprintf(c.conn, "", - xmlEscape(jid)) +func (c *Client) RevokeSubscription(jid string) { + fmt.Fprintf(c.conn, "", + xmlEscape(jid)) } -func (c* Client) RequestSubscription(jid string) { - fmt.Fprintf(c.conn, "", - xmlEscape(jid)) +func (c *Client) RequestSubscription(jid string) { + fmt.Fprintf(c.conn, "", + xmlEscape(jid)) }