Esempio n. 1
0
        /// <summary>
        /// Authenticates using the supplied credentials.
        /// </summary>
        /// <remarks>
        /// <para>If the SMTP server supports authentication, then the SASL mechanisms
        /// that both the client and server support are tried in order of greatest
        /// security to weakest security. Once a SASL authentication mechanism is
        /// found that both client and server support, the credentials are used to
        /// authenticate.</para>
        /// <para>If, on the other hand, authentication is not supported, then
        /// this method simply returns without attempting to authenticate.</para>
        /// </remarks>
        /// <param name="credentials">The user's credentials.</param>
        /// <param name="cancellationToken">A cancellation token.</param>
        /// <exception cref="System.ArgumentNullException">
        /// <paramref name="credentials"/> is <c>null</c>.
        /// </exception>
        /// <exception cref="System.InvalidOperationException">
        /// The <see cref="SmtpClient"/> is not connected or is already authenticated.
        /// </exception>
        /// <exception cref="System.NotSupportedException">
        /// The SMTP server does not support authentication.
        /// </exception>
        /// <exception cref="System.OperationCanceledException">
        /// The operation was canceled via the cancellation token.
        /// </exception>
        /// <exception cref="System.Security.Authentication.AuthenticationException">
        /// Authentication using the supplied credentials has failed.
        /// </exception>
        /// <exception cref="MailKit.Security.SaslException">
        /// A SASL authentication error occurred.
        /// </exception>
        /// <exception cref="System.IO.IOException">
        /// An I/O error occurred.
        /// </exception>
        /// <exception cref="SmtpCommandException">
        /// The SMTP command failed.
        /// </exception>
        /// <exception cref="SmtpProtocolException">
        /// An SMTP protocol error occurred.
        /// </exception>
        public void Authenticate(ICredentials credentials, CancellationToken cancellationToken)
        {
            if (!IsConnected)
            {
                throw new InvalidOperationException("The SmtpClient must be connected before you can authenticate.");
            }

            if (authenticated)
            {
                throw new InvalidOperationException("The SmtpClient is already authenticated.");
            }

            if ((Capabilities & SmtpCapabilities.Authentication) == 0)
            {
                throw new NotSupportedException("The SMTP server does not support authentication.");
            }

            if (credentials == null)
            {
                throw new ArgumentNullException("credentials");
            }

            var          uri = new Uri("smtp://" + host);
            SmtpResponse response;
            string       challenge;
            string       command;

            foreach (var authmech in SaslMechanism.AuthMechanismRank)
            {
                if (!AuthenticationMechanisms.Contains(authmech))
                {
                    continue;
                }

                var sasl = SaslMechanism.Create(authmech, uri, credentials);

                cancellationToken.ThrowIfCancellationRequested();

                // send an initial challenge if the mechanism supports it
                if ((challenge = sasl.Challenge(null)) != null)
                {
                    command = string.Format("AUTH {0} {1}", authmech, challenge);
                }
                else
                {
                    command = string.Format("AUTH {0}", authmech);
                }

                response = SendCommand(command, cancellationToken);

                if (response.StatusCode == SmtpStatusCode.AuthenticationMechanismTooWeak)
                {
                    continue;
                }

                while (!sasl.IsAuthenticated)
                {
                    if (response.StatusCode != SmtpStatusCode.AuthenticationChallenge)
                    {
                        throw new SmtpCommandException(SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response);
                    }

                    challenge = sasl.Challenge(response.Response);
                    response  = SendCommand(challenge, cancellationToken);
                }

                if (response.StatusCode == SmtpStatusCode.AuthenticationSuccessful)
                {
                    Ehlo(cancellationToken);
                    authenticated = true;
                    return;
                }

                throw new AuthenticationException();
            }

            throw new NotSupportedException("No compatible authentication mechanisms found.");
        }