Index: client/JabberClient.cs
===================================================================
--- client/JabberClient.cs (revision 761)
+++ client/JabberClient.cs (working copy)
@@ -62,6 +62,7 @@
new object[] {Options.AUTO_IQ_ERRORS, true},
new object[] {Options.AUTO_PRESENCE, true},
new object[] {Options.PROXY_PORT, 1080},
+ new object[] {Options.LOGIN_X_OAUTH2, false},
new object[] {Options.SRV_PREFIX, "_xmpp-client._tcp."},
};
@@ -193,6 +194,17 @@
}
/// <summary>
+ /// Retrieves/Sets the oauth2 token to connect as.
+ /// </summary>
+ [Description("The x-oath2 token to connect.")]
+ [Category("Jabber")]
+ public string XOAuth2
+ {
+ get { return this[Options.X_OAUTH2] as string; }
+ set { this[Options.X_OAUTH2] = value; }
+ }
+
+ /// <summary>
/// Gets the priority for this connection.
/// </summary>
[Description("Priority for this connection.")]
@@ -234,6 +246,18 @@
}
/// <summary>
+ /// Allows login with X-OAUth2
+ /// </summary>
+ [Description("Automatically log in on connection.")]
+ [DefaultValue(false)]
+ [Category("Automation")]
+ public bool XOAuth2Login
+ {
+ get { return (bool)this[Options.LOGIN_X_OAUTH2]; }
+ set { this[Options.LOGIN_X_OAUTH2] = value; }
+ }
+
+ /// <summary>
/// Retrieves the roster on connection.
/// </summary>
[Description("Retrieves the roster on connection.")]
@@ -867,8 +891,13 @@
}
else
{
- if ((bool)this[Options.AUTO_LOGIN_THISPASS])
+ if ((bool)this[Options.LOGIN_X_OAUTH2])
{
+ proc[SASLProcessor.USERNAME] = User;
+ proc[SASLProcessor.X_OAUTH2_TOKEN] = XOAuth2;
+ }
+ else if ((bool)this[Options.AUTO_LOGIN_THISPASS])
+ {
// TODO: integrate SASL params into XmppStream params
proc[SASLProcessor.USERNAME] = User;
proc[SASLProcessor.PASSWORD] = Password;
Index: connection/sasl/SASLProcessor.cs
===================================================================
--- connection/sasl/SASLProcessor.cs (revision 761)
+++ connection/sasl/SASLProcessor.cs (working copy)
@@ -105,6 +105,10 @@
/// SASL password
/// </summary>
public const string PASSWORD = "password";
+ /// <summary>
+ /// SASL O-Auth2 token
+ /// </summary>
+ public const string X_OAUTH2_TOKEN = "oauth2_token";
/// <summary>
@@ -153,6 +157,11 @@
{
return new PlainProcessor();
}
+ else if ((mt & MechanismType.X_OAUTH2) == MechanismType.X_OAUTH2)
+ {
+ return new XOAuth2Processor();
+ }
+
return null;
}
Index: connection/sasl/XOAuth2Processor.cs
===================================================================
--- connection/sasl/XOAuth2Processor.cs (revision 0)
+++ connection/sasl/XOAuth2Processor.cs (working copy)
@@ -0,0 +1,43 @@
+using System.IO;
+using System.Diagnostics;
+using System.Xml;
+using jabber.protocol.stream;
+
+namespace jabber.connection.sasl
+{
+ /// <summary>
+ /// SASL Mechanism X-OAuth2.
+ /// </summary>
+ public class XOAuth2Processor : SASLProcessor
+ {
+ /// <summary>
+ /// Perform the next step
+ /// </summary>
+ /// <param name="s">Null if it's the initial response</param>
+ /// <param name="doc">Document to create Steps in</param>
+ /// <returns></returns>
+ public override Step step(Step s, XmlDocument doc)
+ {
+ Debug.Assert(s == null);
+ var a = new Auth(doc) {Mechanism = MechanismType.X_OAUTH2};
+ var ms = new MemoryStream();
+
+ // Skip authzid.
+ ms.WriteByte(0);
+ string u = this[USERNAME];
+ if (string.IsNullOrEmpty(u))
+ throw new SASLException("Username required");
+ byte[] bu = System.Text.Encoding.UTF8.GetBytes(u);
+ ms.Write(bu, 0, bu.Length);
+ ms.WriteByte(0);
+ string o = this[X_OAUTH2_TOKEN];
+ if (string.IsNullOrEmpty(o))
+ throw new SASLException("X-OAuth2 token required");
+ byte[] pu = System.Text.Encoding.UTF8.GetBytes(o);
+ ms.Write(pu, 0, pu.Length);
+
+ a.Bytes = ms.ToArray();
+ return a;
+ }
+ }
+}
Index: connection/XmppStream.cs
===================================================================
--- connection/XmppStream.cs (revision 761)
+++ connection/XmppStream.cs (working copy)
@@ -117,6 +117,10 @@
/// </summary>
public const string PASSWORD = "password";
/// <summary>
+ /// Contains the x-oath2 token to connect as.
+ /// </summary>
+ public const string X_OAUTH2 = "x_oauth2";
+ /// <summary>
/// Contains the connecting resource which is used to identify a unique connection.
/// </summary>
public const string RESOURCE = "resource";
@@ -140,6 +144,10 @@
/// </summary>
public const string AUTO_LOGIN_THISPASS = "auto.login.thispass";
/// <summary>
+ ///
+ /// </summary>
+ public const string LOGIN_X_OAUTH2 = "login.xoauth";
+ /// <summary>
/// Retrieves the roster items from the XMPP server on
/// connection if set to true.
/// </summary>
@@ -233,6 +241,7 @@
new object[] {Options.SASL, true},
new object[] {Options.REQUIRE_SASL, false},
new object[] {Options.PLAINTEXT, false},
+ new object[] {Options.LOGIN_X_OAUTH2, false},
new object[] {Options.AUTO_TLS, true},
new object[] {Options.AUTO_COMPRESS, true},
@@ -1175,7 +1184,11 @@
{
State = SASLState.Instance;
}
- m_saslProc = SASLProcessor.createProcessor(types, m_sslOn || (bool)this[Options.PLAINTEXT], ms);
+ if ((bool)this[Options.LOGIN_X_OAUTH2])
+ m_saslProc = SASLProcessor.createProcessor(types, false, ms);
+ else
+ m_saslProc = SASLProcessor.createProcessor(types, m_sslOn || (bool)this[Options.PLAINTEXT], ms);
+
if (m_saslProc == null)
{
FireOnError(new NotImplementedException("No implemented mechanisms in: " + types.ToString()));
Index: protocol/stream/SASL.cs
===================================================================
--- protocol/stream/SASL.cs (revision 761)
+++ protocol/stream/SASL.cs (working copy)
@@ -116,7 +116,11 @@
/// <summary>
/// </summary>
- NMAS_SAMBA_AUTH = (1 << 21)
+ NMAS_SAMBA_AUTH = (1 << 21),
+ /// <summary>
+ /// </summary>
+ X_OAUTH2 = (1 << 22)
}
/// <summary>
@@ -274,6 +278,8 @@
return MechanismType.KERBEROS_V5;
case "NMAS-SAMBA-AUTH":
return MechanismType.NMAS_SAMBA_AUTH;
+ case "X-OAUTH2":
+ return MechanismType.X_OAUTH2;
default:
return MechanismType.NONE;
}
@@ -330,6 +336,8 @@
return "KERBEROS_V5";
case MechanismType.NMAS_SAMBA_AUTH:
return "NMAS-SAMBA-AUTH";
+ case MechanismType.X_OAUTH2:
+ return "X-OAUTH2";
default:
return null;
}