예제 #1
0
        protected override void OnConnected(bool bSuccess, string strErrors)
        {
            try
            {
                if ((bSuccess == true) && (Client.Connected == true))
                {
                    this.Client.NoDelay = true;

#if !WINDOWS_PHONE
                    this.Client.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, Windows.Networking.Sockets.SocketOptionName.KeepAlive, true);
#endif
#if WINDOWS_PHONE
                    var cancellationTokenSource = new System.Threading.CancellationTokenSource();
                    var task = Repeat.Interval(
                        TimeSpan.FromSeconds(60),
                        () => OnKeepAlive(),
                        cancellationTokenSource.Token
                        );
                    //  this.Client.SetSocketOption(System.Net.Sockets.SocketOptionLevel.Socket, Windows.Networking.Sockets.SocketOptionName.KeepAlive, true);
#endif

                    XMPPClient.XMPPState = XMPPState.Connected;
                    XMPPClient.FireConnectAttemptFinished(true);
                    System.Diagnostics.Debug.WriteLine(string.Format("Successful TCP connection"));
                }
                else
                {
                    XMPPClient.XMPPState = XMPPState.Unknown;
                    XMPPClient.FireConnectAttemptFinished(false);
                    System.Diagnostics.Debug.WriteLine(string.Format("Failed to connect: {0}", strErrors));
                    return;
                }

                if (XMPPClient.UseOldStyleTLS == true)
                {
                    StartTLS();
                }


                /// Send stream header if we haven't yet
                XMPPClient.XMPPState = XMPPState.Authenticating;

                OpenStreamStanza open    = new OpenStreamStanza(this.XMPPClient);
                string           strSend = open.XML;
                byte[]           bStanza = System.Text.UTF8Encoding.UTF8.GetBytes(strSend);
                this.Send(bStanza);
            }
            catch (TimeoutException tx)
            {
                Console.WriteLine(tx.InnerException.ToString());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="stanza"></param>
        /// <returns></returns>
        public override bool NewXMLFragment(XMPPStanza stanza)
        {
            /// Looks like the crippled windows phone 7 libraries can't use output from xsd.exe, have to do this the hard way
            ///
            //XDocument doc = XDocument.Load(new StringReader(stanza.XML));
            //XmlReader reader = XmlReader.Create(new StringReader(stanza.XML));


            stanza.XML = stanza.XML.Replace("stream:", "");  // no support for namespaces in windows phone 7, remove them

            XElement xmlElem = XElement.Parse(stanza.XML);

            if (XMPPClient.XMPPState >= XMPPState.Authenticated)
            {
                //if (xmlElem.Name == "features")
                //    return true;  /// If we hit this and parse the stream featurs a second time we re-authenticate.  Just return for now

                ////if (xmlElem.Name == "stream")
                ////{
                ////     XMPPClient.XMPPState = XMPPState.CanBind;
                ////}
                ///// TODO.. see if this new stream supports bind
            }


            if (xmlElem.Name == "features")
            {
                //foreach (XElement node in xmlElem.Descendants())
                //{
                //    System.Diagnostics.Debug.WriteLine(node.Name);
                //}
                var Mechanisms = from mech in xmlElem.Descendants("{urn:ietf:params:xml:ns:xmpp-sasl}mechanism")
                                 select new Mechanism
                {
                    Name = mech.Value,
                };

                AuthMethodsSupported = AuthMethod.NotSpecified;
                foreach (Mechanism mech in Mechanisms)
                {
                    if (mech.Name == "DIGEST-MD5")
                    {
                        AuthMethodsSupported |= AuthMethod.MD5;
                    }
                    else if (mech.Name == "PLAIN")
                    {
                        AuthMethodsSupported |= AuthMethod.Plain;
                    }
                    //  else if (mech.Name == "X-GOOGLE-TOKEN")
                    //    AuthMethodsSupported |= AuthMethod.googletoken;
                }

                if ((AuthMethodsSupported == AuthMethod.NotSpecified) && (XMPPClient.XMPPState < XMPPState.Authenticated))
                {
                    throw new Exception("No acceptable authentication method was supplied");
                }

                var tls = xmlElem.Descendants("{urn:ietf:params:xml:ns:xmpp-tls}starttls");
                if (tls.Count() > 0)
                {
                    FeatureTLS = true;
                }

                var session = xmlElem.Descendants("{urn:ietf:params:xml:ns:xmpp-session}session");
                if (session.Count() > 0)
                {
                    XMPPClient.ShouldDoSession = true;
                }

                var bind = xmlElem.Descendants("{urn:ietf:params:xml:ns:xmpp-bind}bind");
                if (bind.Count() > 0)
                {
                    XMPPClient.XMPPState = XMPPState.CanBind;
                    return(true);
                }



                if ((FeatureTLS == true) && (XMPPClient.UseTLS == true))
                {
                    /// Tell the man we want to negotiate TLS
                    XMPPClient.SendRawXML(StartTLS);
                }
                else
                {
                    StartAuthentication();
                }

                return(true);
            }
            else if (xmlElem.Name == "{urn:ietf:params:xml:ns:xmpp-tls}proceed")
            {
                XMPPClient.XMPPConnection.StartTLS();

                /// After starting TLS, start our normal digest authentication (or plain)
                ///
                /// Bug or something changed after RFC.  Now 6120 says we must reopen the stream, our response should not have a TLS option in it
                ///
                FeatureTLS = false;
                OpenStreamStanza open = new OpenStreamStanza(this.XMPPClient);
                XMPPClient.SendRawXML(open.XML);

                //StartAuthentication();
            }
            else if (xmlElem.Name == "{urn:ietf:params:xml:ns:xmpp-sasl}challenge")
            {
                /// Build and send response
                ///
                string strChallenge        = xmlElem.Value;
                byte[] bData               = Convert.FromBase64String(strChallenge);
                string strUnbasedChallenge = System.Text.UTF8Encoding.UTF8.GetString(bData, 0, bData.Length);

                if (strUnbasedChallenge.IndexOf("rspauth") == 0)
                {
                    string ResponseMessage = MD5Response.Replace("##RESPONSE##", "=");
                    XMPPClient.SendRawXML(ResponseMessage);
                    return(false);
                }
                //realm="ninethumbs.com",nonce="oFun3YWfVm/6nHCkNI/9a4XpcWIdQ5RH9E0IDVKH",qop="auth",charset=utf-8,algorithm=md5-sess

                //string strExampleResponse = "dXNlcm5hbWU9InRlc3QiLHJlYWxtPSJuaW5ldGh1bWJzLmNvbSIsbm9uY2U9InJaNjgreS9BeGp2SjJ6cjBCVUNxVUhQcG9ocFE4ZFkzR29JclpJcFkiLGNub25jZT0iVkdFRDNqNHUrUHE1M3IxYzNab2NhcGFzaWp1eTh2NjhoYXFzRC9IWjVKTT0iLG5jPTAwMDAwMDAxLGRpZ2VzdC11cmk9InhtcHAvbmluZXRodW1icy5jb20iLHFvcD1hdXRoLHJlc3BvbnNlPTdiM2MzOTVjZjU2MDA2Njg5MDg5MzdlYTk2YjEzZjI2LGNoYXJzZXQ9dXRmLTg=";
                //bData = Convert.FromBase64String(strExampleResponse);
                //string strUnbasedResponse = System.Text.UTF8Encoding.UTF8.GetString(bData, 0, bData.Length);
                //"username=\"test\",realm=\"ninethumbs.com\",nonce=\"rZ68+y/AxjvJ2zr0BUCqUHPpohpQ8dY3GoIrZIpY\",cnonce=\"VGED3j4u+Pq53r1c3Zocapasijuy8v68haqsD/HZ5JM=\",nc=00000001,digest-uri=\"xmpp/ninethumbs.com\",qop=auth,response=7b3c395cf5600668908937ea96b13f26,charset=utf-8";

                if (AuthMethodUsed == AuthMethod.MD5)
                {
                    string strRealm   = XMPPClient.Domain;
                    Match  matchrealm = Regex.Match(strUnbasedChallenge, @"realm=""([^""]+)""", RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
                    if (matchrealm.Success == true)
                    {
                        strRealm = matchrealm.Groups[1].Value;
                    }

                    string strNonce   = "";
                    Match  matchnonce = Regex.Match(strUnbasedChallenge, @"nonce=""([^""]+)""", RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline);
                    if (matchnonce.Success == true)
                    {
                        strNonce = matchnonce.Groups[1].Value;
                    }


                    string strQop   = "auth";
                    Match  matchqop = Regex.Match(strUnbasedChallenge, @"qop=""([^""]+)""", RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
                    if (matchqop.Success == true)
                    {
                        strQop = matchqop.Groups[1].Value;
                    }

                    string strAlgo   = "md5-sess";
                    Match  matchalgo = Regex.Match(strUnbasedChallenge, @"algorithm=([^\s,]+)", RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
                    if (matchalgo.Success == true)
                    {
                        strAlgo = matchalgo.Groups[1].Value;
                    }

                    Random rand      = new Random();
                    string strCnonce = rand.Next().ToString("X8").ToLower();
                    // Compute our MD5 response, then base64 it
                    string strResponse = GenerateMD5Response(strAlgo, XMPPClient.UserName, XMPPClient.Domain, XMPPClient.Password, strNonce, strCnonce);

                    string ResponseMessage = MD5Response.Replace("##RESPONSE##", strResponse);
                    XMPPClient.SendRawXML(ResponseMessage);
                }
                else if (AuthMethodUsed == AuthMethod.Plain)
                {
                    /// Send plain text stuff
                    ///
                }
            }
            else if (xmlElem.Name == "{urn:ietf:params:xml:ns:xmpp-sasl}success") /// Success
            {
                XMPPClient.XMPPState = XMPPState.Authenticated;

                OpenStreamStanza open = new OpenStreamStanza(this.XMPPClient);
                XMPPClient.SendRawXML(open.XML);

                //if (XMPPClient.UseTLS == true)
                //{
                //    /// Start a new stream for some strange reason, but don't close the old one.
                //    ///
                //    OpenStreamStanza open = new OpenStreamStanza(this.XMPPClient);
                //    XMPPClient.SendRawXML(open.XML);
                //}
                //else
                //{
                //XMPPClient.XMPPState = XMPPState.CanBind;
                //}
            }
            else if (xmlElem.Name == "{urn:ietf:params:xml:ns:xmpp-sasl}failure")  /// Failed to authorize
            {
                XMPPClient.XMPPState = XMPPState.AuthenticationFailed;
            }


            return(false);
        }