Пример #1
0
        /// <summary>
        /// Execute the command.
        /// </summary>
        /// <param name="context">The execution context to operate on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>A task which asynchronously performs the execution.</returns>
        internal override async Task ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            switch (Method)
            {
            case AuthenticationMethod.Plain:
                if (await TryPlainAsync(context, cancellationToken).ReturnOnAnyThread() == false)
                {
                    await context.Client.ReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ReturnOnAnyThread();

                    return;
                }
                break;

            case AuthenticationMethod.Login:
                if (await TryLoginAsync(context, cancellationToken).ReturnOnAnyThread() == false)
                {
                    await context.Client.ReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ReturnOnAnyThread();

                    return;
                }
                break;
            }

            if (await Options.UserAuthenticator.AuthenticateAsync(_user, _password).ReturnOnAnyThread() == false)
            {
                await context.Client.ReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ReturnOnAnyThread();

                return;
            }

            await context.Client.ReplyAsync(SmtpResponse.AuthenticationSuccessful, cancellationToken).ReturnOnAnyThread();

            context.RaiseSessionAuthenticated();
        }
Пример #2
0
        /// <summary>
        /// Execute the command.
        /// </summary>
        /// <param name="context">The execution context to operate on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Returns true if the command executed successfully such that the transition to the next state should occur, false
        /// if the current state is to be maintained.</returns>
        internal override async Task <bool> ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            context.Authentication = AuthenticationContext.Unauthenticated;

            switch (Method)
            {
            case AuthenticationMethod.Plain:
                if (await TryPlainAsync(context, cancellationToken).ConfigureAwait(false) == false)
                {
                    await context.Pipe.Output.WriteReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ConfigureAwait(false);

                    return(false);
                }
                break;

            case AuthenticationMethod.Login:
                if (await TryLoginAsync(context, cancellationToken).ConfigureAwait(false) == false)
                {
                    await context.Pipe.Output.WriteReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ConfigureAwait(false);

                    return(false);
                }
                break;
            }

            var userAuthenticator = context.ServiceProvider.GetService <IUserAuthenticatorFactory, IUserAuthenticator>(context, UserAuthenticator.Default);

            using (var container = new DisposableContainer <IUserAuthenticator>(userAuthenticator))
            {
                if (await container.Instance.AuthenticateAsync(context, _user, _password, cancellationToken).ConfigureAwait(false) == false)
                {
                    var remaining = context.ServerOptions.MaxAuthenticationAttempts - ++context.AuthenticationAttempts;
                    var response  = new SmtpResponse(SmtpReplyCode.AuthenticationFailed, $"authentication failed, {remaining} attempt(s) remaining.");

                    await context.Pipe.Output.WriteReplyAsync(response, cancellationToken).ConfigureAwait(false);

                    if (remaining <= 0)
                    {
                        throw new SmtpResponseException(SmtpResponse.ServiceClosingTransmissionChannel, true);
                    }

                    return(false);
                }
            }

            await context.Pipe.Output.WriteReplyAsync(SmtpResponse.AuthenticationSuccessful, cancellationToken).ConfigureAwait(false);

            context.Authentication = new AuthenticationContext(_user);
            context.RaiseSessionAuthenticated();

            return(true);
        }
Пример #3
0
        /// <summary>
        /// Execute the command.
        /// </summary>
        /// <param name="context">The execution context to operate on.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>Returns true if the command executed successfully such that the transition to the next state should occurr, false
        /// if the current state is to be maintained.</returns>
        internal override async Task <bool> ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            context.IsAuthenticated = false;

            switch (Method)
            {
            case AuthenticationMethod.Plain:
                if (await TryPlainAsync(context, cancellationToken).ReturnOnAnyThread() == false)
                {
                    await context.NetworkClient.ReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ReturnOnAnyThread();

                    return(false);
                }
                break;

            case AuthenticationMethod.Login:
                if (await TryLoginAsync(context, cancellationToken).ReturnOnAnyThread() == false)
                {
                    await context.NetworkClient.ReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ReturnOnAnyThread();

                    return(false);
                }
                break;
            }

            using (var container = new DisposableContainer <IUserAuthenticator>(Options.UserAuthenticatorFactory.CreateInstance(context)))
            {
                if (await container.Instance.AuthenticateAsync(context, _user, _password, cancellationToken).ReturnOnAnyThread() == false)
                {
                    await context.NetworkClient.ReplyAsync(SmtpResponse.AuthenticationFailed, cancellationToken).ReturnOnAnyThread();

                    return(false);
                }
            }

            await context.NetworkClient.ReplyAsync(SmtpResponse.AuthenticationSuccessful, cancellationToken).ReturnOnAnyThread();

            context.IsAuthenticated   = true;
            context.AuthenticatedUser = _user;
            context.RaiseSessionAuthenticated();

            return(true);
        }
Пример #4
0
        internal override async Task <bool> ExecuteAsync(SmtpSessionContext context, CancellationToken cancellationToken)
        {
            context.ProxySourceEndpoint              = SourceEndpoint;
            context.ProxyDestinationEndpoint         = DestinationEndpoint;
            context.Properties["SourceAddress"]      = SourceEndpoint.Address.ToString();
            context.Properties["DestinationAddress"] = DestinationEndpoint.Address.ToString();

            using (var container =
                       new DisposableContainer <IEndpointAuthenticator>(
                           Options.EndpointAuthenticatorFactory.CreateInstance(context)))
            {
                if (await container.Instance.AuthenticateAsync(context, SourceEndpoint.Address.ToString(),
                                                               DestinationEndpoint.Address.ToString(),
                                                               Options.ProxyAddresses, cancellationToken).ReturnOnAnyThread() == false)
                {
                    var response = new SmtpResponse(SmtpReplyCode.ClientNotPermitted,
                                                    $"PROXY not permitted from {DestinationEndpoint.Address}");
                    await context.NetworkClient.ReplyAsync(response, cancellationToken).ReturnOnAnyThread();

                    context.IsQuitRequested = true;
                    return(false);
                }

                // IEndpointAuthenticator implementations are free to authenticate the
                // session based on the IPs delivered by the proxy command obviating the
                // need for further authentication. RaiseSessionAuthenticated() can be
                // called in this case to transition the state machine.
                context.Properties.TryGetValue("Authenticated", out object authenticated);

                if (authenticated != null)
                {
                    if ((bool)authenticated)
                    {
                        context.IsAuthenticated = true;
                        context.RaiseSessionAuthenticated();
                    }
                }

                return(true);
            }
        }