public void TestAuthenticateCredentialNotFound()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=DIGEST-MD5] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            Assert.IsFalse((bool)session.Authenticate(new NullCredential(), ImapAuthenticationMechanism.DigestMD5));
            Assert.IsFalse((bool)session.Authenticate(new NullCredential(), "user", ImapAuthenticationMechanism.DigestMD5));
              }
        }
        public void TestAuthenticateCancelExchanging()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=DIGEST-MD5] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            server.EnqueueResponse("+ eD0xLHk9Mix6PTM=\r\n"); // x=1,y=2,z=3
            server.EnqueueResponse("0000 NO AUTHENTICATE failed.\r\n");

            session.Authenticate(new NetworkCredential("test", "test", "test"),
                             ImapAuthenticationMechanism.DigestMD5);

            Assert.AreEqual("0000 AUTHENTICATE DIGEST-MD5\r\n",
                        server.DequeueRequest());
            Assert.AreEqual("*\r\n",
                        server.DequeueRequest());
              }
        }
        private void AuthenticateSpecificMechanism(bool saslIRCapable, SaslClientMechanism authMechanism)
        {
            if (saslIRCapable)
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 SASL-IR] ImapSimulatedServer ready\r\n");
              else
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            session.HandlesIncapableAsException = true;

            if (!saslIRCapable)
              server.EnqueueResponse("+ \r\n");
            server.EnqueueResponse("+ \r\n");
            server.EnqueueResponse("0000 OK done\r\n");

            Assert.IsTrue((bool)session.Authenticate(authMechanism));

            if (saslIRCapable) {
              Assert.AreEqual("0000 AUTHENTICATE X-PSEUDO-MECHANISM c3RlcDA=\r\n",
                          server.DequeueRequest());
              Assert.AreEqual("c3RlcDE=\r\n",
                          server.DequeueRequest());
            }
            else {
              Assert.AreEqual("0000 AUTHENTICATE X-PSEUDO-MECHANISM\r\n",
                          server.DequeueRequest());
              Assert.AreEqual("c3RlcDA=\r\n",
                          server.DequeueRequest());
              Assert.AreEqual("c3RlcDE=\r\n",
                          server.DequeueRequest());
            }

            // not disposed
            Assert.AreEqual(SaslExchangeStatus.Succeeded,
                        authMechanism.ExchangeStatus);

            Assert.AreEqual(new Uri(string.Format("imap://{0};AUTH=X-PSEUDO-MECHANISM@{1}:{2}/",
                                              (authMechanism.Credential == null) ? null : authMechanism.Credential.UserName,
                                              host,
                                              port)),
                        session.Authority);
              }
        }
        private void AuthenticateSelectAppropriateCredential(bool specifyUsername)
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=LOGIN] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            server.EnqueueResponse("+ " + Convert.ToBase64String(NetworkTransferEncoding.Transfer8Bit.GetBytes("Username:"******"\r\n");
            server.EnqueueResponse("+ " + Convert.ToBase64String(NetworkTransferEncoding.Transfer8Bit.GetBytes("Password:"******"\r\n");
            server.EnqueueResponse("0000 OK authenticated\r\n");

            var credentials = new CredentialCache();

            credentials.Add("imap.example.net", 143, "LOGIN", new NetworkCredential("user", "pass1"));
            credentials.Add(server.Host, server.Port, "LOGIN", new NetworkCredential("user", "pass2"));
            credentials.Add(server.Host, server.Port, "PLAIN", new NetworkCredential("user", "pass3"));
            credentials.Add(server.Host, server.Port, string.Empty, new NetworkCredential("user", "pass4"));

            server.EnqueueResponse("0000 OK authenticated\r\n");

            if (specifyUsername)
              Assert.IsTrue((bool)session.Authenticate(credentials, "user", ImapAuthenticationMechanism.Login));
            else
              Assert.IsTrue((bool)session.Authenticate(credentials, ImapAuthenticationMechanism.Login));

            Assert.AreEqual("0000 AUTHENTICATE LOGIN\r\n",
                        server.DequeueRequest());

            var requested = server.DequeueRequest();

            Assert.AreEqual("user",
                        NetworkTransferEncoding.Transfer8Bit.GetString(Convert.FromBase64String(requested.Substring(0, requested.Length - 2))));

            requested = server.DequeueRequest();

            Assert.AreEqual("pass2",
                        NetworkTransferEncoding.Transfer8Bit.GetString(Convert.FromBase64String(requested.Substring(0, requested.Length - 2))));

            Assert.AreEqual(new Uri(string.Format("imap://user;AUTH=LOGIN@{0}:{1}/", host, port)), session.Authority);
            Assert.AreEqual(ImapSessionState.Authenticated, session.State);
              }
        }
        private void AuthenticateCredentialPropertyNullSaslIRCapable(ICredentialsByHost credential)
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=PLAIN SASL-IR] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            Assert.IsFalse((bool)session.Authenticate(credential,
                                                  ImapAuthenticationMechanism.Plain));
              }
        }
        private void AuthenticateCredentialPropertyNull(ICredentialsByHost credential)
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=PLAIN] ImapSimulatedServer ready\r\n");
              server.EnqueueResponse("+ \r\n");
              server.EnqueueResponse("0000 NO failed\r\n");

              using (var session = new ImapSession(host, port)) {
            Assert.IsFalse((bool)session.Authenticate(credential,
                                                  ImapAuthenticationMechanism.Plain));

            Assert.AreEqual("0000 AUTHENTICATE PLAIN\r\n",
                        server.DequeueRequest());
            Assert.AreEqual("*\r\n",
                        server.DequeueRequest());
              }
        }
        private void AuthenticateCramMd5(bool saslIRCapable)
        {
            if (saslIRCapable)
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=CRAM-MD5] ImapSimulatedServer ready\r\n");
              else
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=CRAM-MD5 SASL-IR] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            var timestamp = ((long)DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds).ToString();
            var challenge = NetworkTransferEncoding.Transfer8Bit.GetBytes(string.Format("<{0}@{1}>", timestamp, host));

            server.EnqueueResponse("+ " + Convert.ToBase64String(challenge) + "\r\n");
            server.EnqueueResponse("0000 OK authenticated\r\n");

            Assert.IsTrue((bool)session.Authenticate(credential, ImapAuthenticationMechanism.CRAMMD5));

            Assert.AreEqual("0000 AUTHENTICATE CRAM-MD5\r\n",
                                   server.DequeueRequest());

            /*
            var requested = server.DequeueRequest();
            var userkeyed = NetworkTransferEncoding.Transfer8Bit.GetString(Convert.FromBase64String(requested.Substring(0, requested.Length - 2))).Split(' ');

            Assert.AreEqual(username, userkeyed[0]);

            var keyed = new List<byte>();

            for (var index = 0; index < userkeyed[1].Length; index += 2) {
              keyed.Add(Convert.ToByte(userkeyed[1].Substring(index, 2), 16));
            }

            Assert.AreEqual(Convert.ToBase64String((new HMACMD5(NetworkTransferEncoding.Transfer8Bit.GetBytes(password))).ComputeHash(challenge)),
                        Convert.ToBase64String(keyed.ToArray()));
            */

            Assert.AreEqual(new Uri(string.Format("imap://{0};AUTH=CRAM-MD5@{1}:{2}/", username, host, port)), session.Authority);
            Assert.AreEqual(ImapSessionState.Authenticated, session.State);
              }
        }
        public void TestAuthenticateLogin()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=LOGIN] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            server.EnqueueResponse("+ " + Convert.ToBase64String(NetworkTransferEncoding.Transfer8Bit.GetBytes("Username:"******"\r\n");
            server.EnqueueResponse("+ " + Convert.ToBase64String(NetworkTransferEncoding.Transfer8Bit.GetBytes("Password:"******"\r\n");
            server.EnqueueResponse("0000 OK authenticated\r\n");

            Assert.IsTrue((bool)session.Authenticate(credential, ImapAuthenticationMechanism.Login));

            Assert.AreEqual("0000 AUTHENTICATE LOGIN\r\n",
                        server.DequeueRequest());

            var requested = server.DequeueRequest();

            Assert.AreEqual(username,
                        NetworkTransferEncoding.Transfer8Bit.GetString(Convert.FromBase64String(requested.Substring(0, requested.Length - 2))));

            requested = server.DequeueRequest();

            Assert.AreEqual(password,
                        NetworkTransferEncoding.Transfer8Bit.GetString(Convert.FromBase64String(requested.Substring(0, requested.Length - 2))));

            Assert.AreEqual(new Uri(string.Format("imap://{0};AUTH=LOGIN@{1}:{2}/", username, host, port)), session.Authority);
            Assert.AreEqual(ImapSessionState.Authenticated, session.State);
              }
        }
 private static ImapCommandResult AuthenticateWithSuppliedMechanism(ImapSession session,
                                                                ICredentialsByHost credentials,
                                                                string username,
                                                                ImapAuthenticationMechanism authMechanism)
 {
     /*
        * http://tools.ietf.org/html/rfc5092
        * 3.2. IMAP User Name and Authentication Mechanism
        *
        *    An authentication mechanism (as used by the IMAP AUTHENTICATE
        *    command) can be expressed by adding ";AUTH=<enc-auth-type>" to the
        *    end of the user name in an IMAP URL.  When such an <enc-auth-type> is
        *    indicated, the client SHOULD request appropriate credentials from
        *    that mechanism and use the "AUTHENTICATE" command instead of the
        *    "LOGIN" command.  If no user name is specified, one MUST be obtained
        *    from the mechanism or requested from the user/configuration as
        *    appropriate.
        */
       return session.Authenticate(credentials, username, authMechanism, true);
 }
        public void TestAuthenticateSelectAppropriateCredentialNotFound()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=LOGIN] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            var credentials = new CredentialCache();

            credentials.Add("imap.example.net", 143, "LOGIN", new NetworkCredential("user", "pass1"));
            credentials.Add(server.Host, server.Port, "LOGIN", new NetworkCredential("user", "pass2"));
            credentials.Add(server.Host, server.Port, "PLAIN", new NetworkCredential("user", "pass3"));
            credentials.Add(server.Host, server.Port, string.Empty, new NetworkCredential("user", "pass4"));

            var result = session.Authenticate(credentials, "xxxx", ImapAuthenticationMechanism.Login);

            Assert.IsFalse((bool)result);
            Assert.AreEqual(ImapCommandResultCode.RequestError, result.Code);
            Assert.AreEqual(ImapSessionState.NotAuthenticated, session.State);
              }
        }
        public void TestAuthenticateReissueCapabilityResponseCodeAdvertised()
        {
            server.EnqueueResponse("* OK ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            server.EnqueueResponse("+ \r\n");
            server.EnqueueResponse("+ \r\n");
            server.EnqueueResponse("0000 OK [CAPABILITY IMAP4rev1] authenticated\r\n");

            Assert.IsTrue((bool)session.Authenticate(credential, ImapAuthenticationMechanism.Login, true));

            StringAssert.StartsWith("0000 AUTHENTICATE ", server.DequeueRequest());

            Assert.AreEqual(1, session.ServerCapabilities.Count);
            Assert.IsTrue(session.ServerCapabilities.Has(ImapCapability.Imap4Rev1));
              }
        }
        public void TestAuthenticatePlainSaslIRCapable()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=PLAIN SASL-IR] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            server.EnqueueResponse("0000 OK authenticated\r\n");

            Assert.IsTrue((bool)session.Authenticate(new NetworkCredential("test", "test", "test"),
                                                 ImapAuthenticationMechanism.Plain));

            Assert.AreEqual("0000 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=\r\n",
                        server.DequeueRequest());

            Assert.AreEqual(new Uri(string.Format("imap://test;AUTH=PLAIN@{0}:{1}/", host, port)), session.Authority);
              }
        }
        public void TestAuthenticatePlain()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=PLAIN] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            server.EnqueueResponse("+ \r\n");
            server.EnqueueResponse("0000 OK authenticated\r\n");

            Assert.IsTrue((bool)session.Authenticate(credential, ImapAuthenticationMechanism.Plain));

            Assert.AreEqual("0000 AUTHENTICATE PLAIN\r\n",
                        server.DequeueRequest());

            var requested = server.DequeueRequest();
            var userpass = NetworkTransferEncoding.Transfer8Bit.GetString(Convert.FromBase64String(requested.Substring(0, requested.Length - 2))).Split(new[] {"\0"}, StringSplitOptions.RemoveEmptyEntries);

            Assert.AreEqual(credential.Domain, userpass[0]);
            Assert.AreEqual(credential.UserName, userpass[1]);
            Assert.AreEqual(credential.Password, userpass[2]);

            Assert.AreEqual(new Uri(string.Format("imap://{0};AUTH=PLAIN@{1}:{2}/", username, host, port)), session.Authority);
            Assert.AreEqual(ImapSessionState.Authenticated, session.State);
              }
        }
        public void TestAuthenticateOkWithCapabilityResponse()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=PLAIN SASL-IR] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            Assert.AreEqual(3, session.ServerCapabilities.Count);
            Assert.IsTrue(session.ServerCapabilities.Has(ImapCapability.Imap4Rev1));
            Assert.IsTrue(session.ServerCapabilities.Has(ImapCapability.SaslIR));
            Assert.IsTrue(session.ServerCapabilities.IsCapable(ImapAuthenticationMechanism.Plain));

            //server.EnqueueResponse();
            server.EnqueueResponse("0000 OK [CAPABILITY IMAP4rev1] authenticated\r\n");

            Assert.IsTrue((bool)session.Authenticate(new NetworkCredential("test", "test", "test"),
                                                 ImapAuthenticationMechanism.Plain));

            Assert.AreEqual("0000 AUTHENTICATE PLAIN dGVzdAB0ZXN0AHRlc3Q=\r\n",
                        server.DequeueRequest());

            Assert.AreEqual(new Uri(string.Format("imap://test;AUTH=PLAIN@{0}:{1}/", host, port)), session.Authority);

            Assert.AreEqual(1, session.ServerCapabilities.Count);
            Assert.IsTrue(session.ServerCapabilities.Has(ImapCapability.Imap4Rev1));

            try {
              session.ServerCapabilities.Add(ImapCapability.Imap4);
              Assert.Fail("NotSupportedException not thrown");
            }
            catch (NotSupportedException) {
            }
              }
        }
        public void TestAuthenticateMailboxReferralAsException()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=LOGIN LOGIN-REFERRALS] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port, true)) {
            server.EnqueueResponse("0000 NO [REFERRAL IMAP://user;AUTH=GSSAPI@SERVER2/] Specified user is invalid on this server. Try SERVER2.\r\n");

            try {
              session.Authenticate(credential, ImapAuthenticationMechanism.Login);

              Assert.Fail("authentcated without exception");
            }
            catch (ImapLoginReferralException ex) {
              Assert.IsTrue(ex.Message.Contains("Specified user is invalid on this server. Try SERVER2."));
              Assert.AreEqual(new Uri("IMAP://user;AUTH=GSSAPI@SERVER2/"), ex.ReferToUri);
            }
              }
        }
        private static ImapCommandResult AuthenticateAsAnonymous(ImapSession session,
                                                             string username,
                                                             bool canFallback)
        {
            /*
               * http://tools.ietf.org/html/rfc5092
               * 3.2. IMAP User Name and Authentication Mechanism
               *
               *    If no user name and no authentication mechanism are supplied, the
               *    client MUST authenticate as anonymous to the server.  If the server
               *    advertises AUTH=ANONYMOUS IMAP capability, the client MUST use the
               *    AUTHENTICATE command with ANONYMOUS [ANONYMOUS] SASL mechanism.  If
               *    SASL ANONYMOUS is not available, the (case-insensitive) user name
               *    "anonymous" is used with the "LOGIN" command and the Internet email
               *    address of the end user accessing the resource is supplied as the
               *    password.  The latter option is given in order to provide for
               *    interoperability with deployed servers.
               *
               *    Note that, as described in RFC 3501, the "LOGIN" command MUST NOT be
               *    used when the IMAP server advertises the LOGINDISABLED capability.
               */
              ImapCommandResult result = null;

              if (string.IsNullOrEmpty(username))
            username = "******";

              if (session.ServerCapabilities.IsCapable(ImapAuthenticationMechanism.Anonymous))
            // try AUTHENTICATE ANONYUMOUS
            result = session.Authenticate(new NetworkCredential(username, string.Empty),
                                      null,
                                      ImapAuthenticationMechanism.Anonymous,
                                      true);

              if ((result == null || (result.Failed && canFallback)) &&
              !session.ServerCapabilities.Has(ImapCapability.LoginDisabled))
            // try anonymous LOGIN
            result = session.Login(new NetworkCredential("anonymous", username),
                               null,
                               true);

              return result;
        }
        private static ImapCommandResult AuthenticateWithAppropriateMechanism(ImapSession session,
                                                                          bool allowPlainTextMechanism,
                                                                          ICredentialsByHost credentials,
                                                                          string username,
                                                                          IEnumerable<string> usingSaslMechanisms)
        {
            ImapCommandResult result = null;

              foreach (var mechanism in usingSaslMechanisms) {
            if (!allowPlainTextMechanism && SaslClientMechanism.IsMechanismPlainText(mechanism))
              // disallow plain text mechanism
              continue;

            if (string.Equals(mechanism, SaslMechanisms.Anonymous, StringComparison.OrdinalIgnoreCase))
              // disallow 'ANONYMOUS' mechanism
              continue;

            var authMechanism = ImapAuthenticationMechanism.GetKnownOrCreate(mechanism);

            if (session.ServerCapabilities.IsCapable(authMechanism)) {
              result = session.Authenticate(credentials, username, authMechanism, true);

              if (result.Succeeded)
            break;
            }
              }

              if ((result == null || result.Failed) &&
              allowPlainTextMechanism &&
              !session.ServerCapabilities.Has(ImapCapability.LoginDisabled))
            result = session.Login(credentials, username, true);

              return result;
        }
        public void TestAuthenticateSpecificMechanismArgumentNull()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            session.HandlesIncapableAsException = true;

            SaslClientMechanism authMechanism = null;

            session.Authenticate(authMechanism);
              }
        }
        public static ImapCommandResult CreateSession(IImapSessionProfile profile,
                                                  SaslClientMechanism authMechanismSpecified,
                                                  UpgradeConnectionStreamCallback createSslStreamCallback,
                                                  out ImapSession session)
        {
            if (profile == null)
            throw new ArgumentNullException("profile");

              var authority = profile.Authority;
              var securePort = string.Equals(authority.Scheme, ImapUri.UriSchemeImaps, StringComparison.OrdinalIgnoreCase);

              if (securePort && createSslStreamCallback == null)
            throw new ArgumentNullException("createSslStreamCallback");

              ImapCommandResult result;
              session = null;

              session = new ImapSession(authority.Host,
                                authority.Port,
                                true,
                                profile.Timeout,
                                securePort
                                  ? createSslStreamCallback
                                  : null);

              session.HandlesIncapableAsException = false;
              session.HandlesReferralAsException = false;
              session.TransactionTimeout  = profile.Timeout;
              session.SendTimeout         = profile.SendTimeout;
              session.ReceiveTimeout      = profile.ReceiveTimeout;

              if (session.ServerCapabilities.Count == 0)
            // try querying server capability (ignore error)
            session.Capability();

              if (!session.ServerCapabilities.Has(ImapCapability.Imap4Rev1))
            throw new ImapIncapableException(ImapCapability.Imap4Rev1);

              if (profile.UseTlsIfAvailable && session.ServerCapabilities.Has(ImapCapability.StartTls) && !session.IsSecureConnection) {
            var r = session.StartTls(createSslStreamCallback, true);

            if (r.Failed)
              throw new ImapSecureConnectionException(r.ResultText);
            else if (!session.ServerCapabilities.Has(ImapCapability.Imap4Rev1))
              throw new ImapIncapableException(ImapCapability.Imap4Rev1);
              }

              if (profile.UseDeflateIfAvailable && session.ServerCapabilities.Has(ImapCapability.CompressDeflate)) {
            var r = session.Compress(ImapCompressionMechanism.Deflate);

            if (r.Failed)
              throw new WebException(r.ResultText, null, WebExceptionStatus.RequestCanceled, null);
              }

              if (authMechanismSpecified == null)
            result = Authenticate(session, profile);
              else
            result = session.Authenticate(authMechanismSpecified);

              if (result == null) {
            throw new ImapAuthenticationException("appropriate authentication mechanism not found");
              }
              else if (result.Failed) {
            try {
              try {
            session.Disconnect(false);
              }
              catch (ImapConnectionException) {
            // ignore
              }
            }
            finally {
              session = null;
            }
              }

              return result;
        }
        public void TestAuthenticateInvalidResponse()
        {
            server.EnqueueResponse("* OK [CAPABILITY IMAP4rev1 AUTH=DIGEST-MD5] ImapSimulatedServer ready\r\n");

              using (var session = new ImapSession(host, port)) {
            server.EnqueueResponse("+ xxxxx-invalid-response-xxxxx\r\n");

            try {
              session.Authenticate(new NetworkCredential("test", "test", "test"),
                               ImapAuthenticationMechanism.DigestMD5);
              Assert.Fail("ImapException not thrown");
            }
            catch (ImapException) {
            }

            Assert.AreEqual(ImapSessionState.NotConnected, session.State);
              }
        }