Skip to content

Commit

Permalink
Add allow any creds (#1428)
Browse files Browse the repository at this point in the history
  • Loading branch information
rnwood authored Apr 24, 2024
1 parent 328ba34 commit 873dc9f
Show file tree
Hide file tree
Showing 12 changed files with 44 additions and 108 deletions.
1 change: 1 addition & 0 deletions Rnwood.Smtp4dev/ApiModel/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public class Server
public bool WebAuthenticationRequired { get; set; }
public bool DesktopMinimiseToTrayIcon { get; set; }
public bool IsDesktopApp { get; internal set; }
public bool SmtpAllowAnyCredentials { get; set; }
}

}
3 changes: 3 additions & 0 deletions Rnwood.Smtp4dev/ClientApp/src/ApiClient/Server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import User from './User';
export default class Server {
webAuthenticationRequired: boolean;
smtpAllowAnyCredentials: boolean;
minimiseToTrayIcon: boolean;
isDesktopApp: boolean;

Expand All @@ -16,6 +17,7 @@ export default class Server {
relayLogin: string,
relayPassword: string,
webAuthenticationRequired : boolean,
smtpAllowAnyCredentials: boolean,
lockedSettings: { [key: string]: string },
minimiseToTrayIcon: boolean,
isDesktopApp: boolean
Expand Down Expand Up @@ -50,6 +52,7 @@ export default class Server {
this.relayPassword = relayPassword;
this.lockedSettings = lockedSettings;
this.webAuthenticationRequired = webAuthenticationRequired;
this.smtpAllowAnyCredentials = smtpAllowAnyCredentials;
this.minimiseToTrayIcon = minimiseToTrayIcon;
this.isDesktopApp = isDesktopApp;
}
Expand Down
16 changes: 15 additions & 1 deletion Rnwood.Smtp4dev/ClientApp/src/components/settingsdialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<el-input-number :min=1 controls-position="right" v-model="server.numberOfSessionsToKeep" :disabled="server.lockedSettings.numberOfSessionsToKeep" />
</el-form-item>

<el-form-item label="Require Authentication (web, API)" prop="server.webAuthenticationRequired">
<el-form-item label="Require Authentication (web, API)" prop="server.webAuthenticationRequired" :rules="{validator: checkWebAuthHasUsers}">
<el-icon v-if="server.lockedSettings.webAuthenticationRequired" :title="`Locked: ${server.lockedSettings.webAuthenticationRequired}`"><Lock /></el-icon>

<el-switch v-model="server.webAuthenticationRequired" :disabled="server.lockedSettings.webAuthenticationRequired" />
Expand Down Expand Up @@ -91,6 +91,12 @@
<el-switch v-model="server.secureConnectionRequired" :disabled="server.lockedSettings.secureConnectionRequired" />
</el-form-item>

<el-form-item label="Allow Any Credentials (off = see 'Users')" prop="server.smtpAllowAnyCredentials">
<el-icon v-if="server.lockedSettings.smtpAllowAnyCredentials" :title="`Locked: ${server.lockedSettings.smtpAllowAnyCredentials}`"><Lock /></el-icon>

<el-switch v-model="server.smtpAllowAnyCredentials" :disabled="server.lockedSettings.smtpAllowAnyCredentials" />
</el-form-item>

<el-form-item label="Credentials validation expression (see comments in appsettings.json)" prop="server.credentialsValidationExpression">

<el-input v-model="server.credentialsValidationExpression" :disabled="server.lockedSettings.credentialsValidationExpression">
Expand Down Expand Up @@ -327,6 +333,14 @@
}
checkWebAuthHasUsers(rule: any, value: any, callback: any) {
if (value && !this.server?.users?.length) {
callback("You must add at least one user under 'Users' to enable this setting.")
} else {
callback();
}
}
@Prop()
visible: boolean = false;
Expand Down
3 changes: 2 additions & 1 deletion Rnwood.Smtp4dev/CommandLineParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ public static MapOptions<CommandLineOptions> TryParseCommandLine(IEnumerable<str
{ "applicationName=","", data => map.Add(data, x => x.ApplicationName), true},
{ "authenticationrequired", "Requires that SMTP and IMAP clients authenticate", data => map.Add((data != null).ToString(), x => x.ServerOptions.AuthenticationRequired) },
{ "secureconnectionrequired", "Requires that SMTP clients use SSL/TLS", data => map.Add((data != null).ToString(), x => x.ServerOptions.SecureConnectionRequired) },
{ "webauthenticationrequired", "Require authentication for web interface", data => map.Add((data != null).ToString(), x => x.ServerOptions.WebAuthenticationRequired) },
{ "smtpallowanycredentials", "True if the SMTP server will allow any credentials to be used without checking them again the 'Users'", data => map.Add((data != null).ToString(), x => x.ServerOptions.SmtpAllowAnyCredentials) },
{ "webauthenticationrequired", "Require authentication for web interface", data => map.Add((data != null).ToString(), x => x.ServerOptions.WebAuthenticationRequired) },
{ "user=", "Adds a user and password combination for web, SMTP and IMAP. Use format username=password. This option can be repeated to add multiple users.", data =>
map.Add(data, x => x.ServerOptions.Users)
}
Expand Down
2 changes: 2 additions & 0 deletions Rnwood.Smtp4dev/Controllers/ServerController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public ApiModel.Server GetServer()
DisableMessageSanitisation = serverOptions.CurrentValue.DisableMessageSanitisation,
TlsMode = serverOptions.CurrentValue.TlsMode.ToString(),
AuthenticationRequired = serverOptions.CurrentValue.AuthenticationRequired,
SmtpAllowAnyCredentials = serverOptions.CurrentValue.SmtpAllowAnyCredentials,
SecureConnectionRequired = serverOptions.CurrentValue.SecureConnectionRequired,
CredentialsValidationExpression = serverOptions.CurrentValue.CredentialsValidationExpression,
RecipientValidationExpression = serverOptions.CurrentValue.RecipientValidationExpression,
Expand Down Expand Up @@ -204,6 +205,7 @@ public ActionResult UpdateServer(ApiModel.Server serverUpdate)
newSettings.DisableIPv6 = serverUpdate.DisableIPv6;
newSettings.Users = serverUpdate.Users;
newSettings.WebAuthenticationRequired = serverUpdate.WebAuthenticationRequired;
newSettings.SmtpAllowAnyCredentials = serverUpdate.SmtpAllowAnyCredentials;

newRelaySettings.SmtpServer = serverUpdate.RelaySmtpServer;
newRelaySettings.SmtpPort = serverUpdate.RelaySmtpPort;
Expand Down
2 changes: 1 addition & 1 deletion Rnwood.Smtp4dev/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"profiles": {
"Rnwood.Smtp4dev": {
"commandName": "Project",
"commandLineArgs": "--hostname=BLAH --smtpport=2525 --user:u1=p1 --user:u2=p2",
"commandLineArgs": "",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
Expand Down
2 changes: 2 additions & 0 deletions Rnwood.Smtp4dev/Server/Settings/ServerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public record ServerOptions
public string CredentialsValidationExpression { get; set; }
public bool AuthenticationRequired { get; set; } = false;
public bool SecureConnectionRequired { get; set; } = false;

public bool SmtpAllowAnyCredentials { get; set; }
public string RecipientValidationExpression { get; set; }

public string MessageValidationExpression { get; set; }
Expand Down
2 changes: 2 additions & 0 deletions Rnwood.Smtp4dev/Server/Settings/ServerOptionsSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ public record ServerOptionsSource
public bool? DisableMessageSanitisation { get; set; }
public string CredentialsValidationExpression { get; set; }
public bool? AuthenticationRequired { get; set; }

public bool? SmtpAllowAnyCredentials { get; set; }
public bool? SecureConnectionRequired { get; set; }
public string RecipientValidationExpression { get; set; }

Expand Down
10 changes: 9 additions & 1 deletion Rnwood.Smtp4dev/Server/Smtp4devServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ private void QueueCleanup()

private Task OnAuthenticationCredentialsValidationRequired(object sender, AuthenticationCredentialsValidationEventArgs e)
{


var sessionId = activeSessionsToDbId[e.Session];
using var scope = serviceScopeFactory.CreateScope();
Smtp4devDbContext dbContext = scope.ServiceProvider.GetService<Smtp4devDbContext>();
Expand All @@ -205,6 +207,12 @@ private Task OnAuthenticationCredentialsValidationRequired(object sender, Authen

AuthenticationResult? result = scriptingHost.ValidateCredentials(apiSession, e.Credentials);

if (result == null && this.serverOptions.CurrentValue.SmtpAllowAnyCredentials)
{
this.log.Information("SMTP auth success (allow any credentials is on)");
result = AuthenticationResult.Success;
}

if (result == null)
{
if (e.Credentials is IAuthenticationCredentialsCanValidateWithPassword val)
Expand All @@ -213,7 +221,7 @@ private Task OnAuthenticationCredentialsValidationRequired(object sender, Authen
if (user != null && val.ValidateResponse(user.Password))
{
result = AuthenticationResult.Success;
this.log.Warning("SMTP auth success for user {user}", val.Username);
this.log.Information("SMTP auth success for user {user}", val.Username);

}
else
Expand Down
6 changes: 6 additions & 0 deletions Rnwood.Smtp4dev/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,12 @@
// See 'Users'
"AuthenticationRequired": false,


// True if the SMTP server will allow any credentials to be used without checking them again the 'Users'.
// If false credentials must match one of the users.
// 'AuthenticationRequired' must be on or the server will not enforce that authentication takes place.
"SmtpAllowAnyCredentials": true,

// True if the SMTP session will require a secure connection.
// The client will recieve an error if a message is attempted without TLS - this must be enabled separately.
"SecureConnectionRequired": false,
Expand Down
42 changes: 0 additions & 42 deletions smtpserver/Rnwood.SmtpServer/Rnwood.SmtpServer.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

63 changes: 1 addition & 62 deletions smtpserver/Rnwood.SmtpServer/ServerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,57 +27,6 @@ public class ServerOptions : IServerOptions
private readonly X509Certificate implcitTlsCertificate;
private readonly X509Certificate startTlsCertificate;

/// <summary>
/// Initializes a new instance of the <see cref="ServerOptions" /> class.
/// </summary>
/// <param name="allowRemoteConnections">if set to <c>true</c> remote connections to the server are allowed.</param>
/// <param name="enableIpV6">If IPV6 dual stack should be enabled</param>
public ServerOptions(bool allowRemoteConnections, bool enableIpV6, bool requireAuthentication)
: this(allowRemoteConnections, enableIpV6, 25, requireAuthentication, null, null)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ServerOptions" /> class.
/// </summary>
/// <param name="allowRemoteConnections">if set to <c>true</c> remote connections to the server are allowed.</param>
/// <param name="enableIpV6">If IPV6 dual stack should be enabled</param>
/// <param name="portNumber">The port number.</param>
public ServerOptions(bool allowRemoteConnections, bool enableIpV6, int portNumber , bool requireAuthentication)
: this(allowRemoteConnections, enableIpV6, portNumber, requireAuthentication, null, null)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ServerOptions" /> class.
/// </summary>
/// <param name="allowRemoteConnections">if set to <c>true</c> remote connections to the server are allowed.</param>
/// <param name="enableIpV6">If IPV6 dual stack should be enabled</param>
/// <param name="portNumber">The port number.</param>
/// <param name="implicitTlsCertificate">The TLS certificate to use for implicit TLS.</param>
public ServerOptions(bool allowRemoteConnections, bool enableIpV6, int portNumber, bool requireAuthentication, X509Certificate implicitTlsCertificate)
: this(allowRemoteConnections, enableIpV6, portNumber, requireAuthentication, implicitTlsCertificate, null)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ServerOptions" /> class.
/// </summary>
/// <param name="allowRemoteConnections">if set to <c>true</c> remote connections to the server are allowed.</param>
/// <param name="enableIpV6">If IPV6 dual stack should be enabled</param>
/// <param name="portNumber">The port number.</param>
/// <param name="implicitTlsCertificate">The TLS certificate to use for implicit TLS.</param>
/// <param name="startTlsCertificate">The TLS certificate to use for STARTTLS.</param>
public ServerOptions(
bool allowRemoteConnections,
bool enableIpV6,
int portNumber,
bool requireAuthentication,
X509Certificate implicitTlsCertificate,
X509Certificate startTlsCertificate)
: this(allowRemoteConnections, enableIpV6, Dns.GetHostName(), portNumber, requireAuthentication, implicitTlsCertificate, startTlsCertificate)
{
}

/// <summary>
/// Initializes a new instance of the <see cref="ServerOptions" /> class.
Expand Down Expand Up @@ -106,16 +55,6 @@ public ServerOptions(
this.requireAuthentication = requireAuthentication;
}

/// <summary>
/// Initializes a new instance of the <see cref="ServerOptions" /> class.
/// </summary>
/// <param name="allowRemoteConnections">if set to <c>true</c> remote connections to the server are allowed.</param>
/// <param name="enableIpV6">If IPV6 dual stack should be enabled</param>
/// <param name="implcitTlsCertificate">The TLS certificate to use for implicit TLS.</param>
public ServerOptions(bool allowRemoteConnections, bool enableIpV6, bool requireAuthentication, X509Certificate implcitTlsCertificate)
: this(allowRemoteConnections, enableIpV6, 587, requireAuthentication, implcitTlsCertificate, null)
{
}

/// <summary>
/// Gets or sets a List of active Auth Mechanism Identifiers.
Expand Down Expand Up @@ -190,7 +129,7 @@ public virtual Task<X509Certificate> GetSSLCertificate(IConnection connection) =

/// <inheritdoc />
public virtual Task<bool> IsAuthMechanismEnabled(IConnection connection, IAuthMechanism authMechanism) =>
Task.FromResult(this.requireAuthentication &&
Task.FromResult(
EnabledAuthMechanisms.Contains(authMechanism));

/// <inheritdoc />
Expand Down

0 comments on commit 873dc9f

Please sign in to comment.