/// <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(); }
/// <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); }
/// <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); }
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); } }