Skip to content

Commit cfe53a3

Browse files
committed
Fine tuned data validation
1 parent 4cab4e6 commit cfe53a3

5 files changed

Lines changed: 106 additions & 22 deletions

File tree

AzureFunctions/AnalyzeRequestIP.cs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Microsoft.Extensions.Logging;
22
using System.Net;
3-
using System.Runtime.CompilerServices;
3+
using System.Net.Sockets;
44

55
namespace AzureFunctions
66
{
@@ -26,21 +26,38 @@ public static bool IsIpAllowed(IPAddress? ipAddress, ILogger logger)
2626
logger.LogInformation("Request not allowed as there are no ALLOWED_HOSTS configured");
2727
return false;
2828
}
29+
30+
if ((String.Equals(_allowedHostsString, "ALL", StringComparison.OrdinalIgnoreCase) == true) ||
31+
(String.Equals(_allowedHostsString, "ANY", StringComparison.OrdinalIgnoreCase) == true) ||
32+
(String.Equals(_allowedHostsString, "*", StringComparison.OrdinalIgnoreCase) == true))
33+
{
34+
logger.LogInformation("Request allowed as ALLOWED_HOSTS is set to any of ALL/ANY/* which permits requests from any client");
35+
return true;
36+
}
37+
2938
_allowedHosts = _allowedHostsString.Split(',', StringSplitOptions.RemoveEmptyEntries).ToList();
3039

3140
foreach (string host in _allowedHosts)
3241
{
3342
logger.LogInformation(String.Format(" Resolving hosts: {0}", host));
34-
IPAddress[] resolvedIPs = Dns.GetHostAddresses(host);
35-
foreach (var resolvedIP in resolvedIPs)
43+
try
3644
{
37-
logger.LogInformation(String.Format(" Analysing IP: {0}", resolvedIP.ToString()));
38-
if (!_allowedIPs.Contains(resolvedIP.ToString()))
45+
IPAddress[] resolvedIPs = Dns.GetHostAddresses(host);
46+
foreach (var resolvedIP in resolvedIPs)
3947
{
40-
logger.LogInformation(String.Format(" Adding IP {0} to the allowed hosts", resolvedIP.ToString()));
41-
_allowedIPs.Add(resolvedIP.ToString());
48+
logger.LogInformation(String.Format(" Analysing IP: {0}", resolvedIP.ToString()));
49+
if (!_allowedIPs.Contains(resolvedIP.ToString()))
50+
{
51+
logger.LogInformation(String.Format(" Adding IP {0} to the allowed hosts", resolvedIP.ToString()));
52+
_allowedIPs.Add(resolvedIP.ToString());
53+
}
4254
}
4355
}
56+
catch (SocketException ex)
57+
{
58+
logger.LogError(ex, String.Format("Failed to resolve host {0} with exception: {1}. This host will not be added to the list of allowed IPs.", host, ex.Message));
59+
continue;
60+
}
4461
}
4562

4663
if (!_allowedIPs.Contains(ipAddress.ToString()))
@@ -49,7 +66,7 @@ public static bool IsIpAllowed(IPAddress? ipAddress, ILogger logger)
4966
return false;
5067
}
5168

52-
logger.LogInformation("Request IP is is allowed to make requests");
69+
logger.LogInformation("Request IP is allowed to make requests");
5370
return true;
5471
}
5572

AzureFunctions/AssertConfiguration.cs

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using Microsoft.Extensions.Hosting;
2-
using Microsoft.Extensions.Logging;
1+
using Microsoft.Extensions.Logging;
32

43
namespace AzureFunctions
54
{
@@ -20,13 +19,17 @@ internal class AssertConfiguration
2019
"EXCHANGE_SMTP_USERNAME",
2120
"EXCHANGE_SMTP_PASSWORD"
2221
};
23-
24-
public static bool ValidateConfigurationEntries(ILogger logger, List<string> variablesToValidate = null)
22+
private static List<string> _numericConfiguration = new List<string> {
23+
"ACS_SMTP_PORT",
24+
"EXCHANGE_SMTP_PORT"
25+
};
26+
27+
public static bool VerifyConfiguratiopnEntriesExistence(ILogger logger, List<string>? variablesToValidate = null)
2528
{
26-
logger.LogInformation("Entering AzureFunctions:ValidateConfigurationEntries");
29+
logger.LogInformation("Entering AzureFunctions:VerifyConfiguratiopnEntriesExistence");
2730
if (variablesToValidate != null)
2831
{
29-
logger.LogInformation("Checking all variables as no subset of them is provided");
32+
logger.LogInformation("Checking provided variables instead of all config entries");
3033
_mandatoryConfiguration = variablesToValidate;
3134
}
3235

@@ -43,5 +46,42 @@ public static bool ValidateConfigurationEntries(ILogger logger, List<string> var
4346
logger.LogInformation("Configuration validation completed successfully");
4447
return true;
4548
}
49+
50+
public static bool VerifyNumericConfigurationEntries(ILogger logger, List<string>? variablesToValidate = null)
51+
{
52+
logger.LogInformation("Entering AzureFunctions:VerifyNumericConfigurationEntries");
53+
if (variablesToValidate != null)
54+
{
55+
logger.LogInformation("Checking provided variables instead of all numeric config entries");
56+
_numericConfiguration = variablesToValidate;
57+
}
58+
59+
foreach (string configValue in _numericConfiguration)
60+
{
61+
string? configValueFromEnv = Environment.GetEnvironmentVariable(configValue);
62+
logger.LogInformation(String.Format(" Verifying environment variable {0} with value {1}", configValue, configValueFromEnv));
63+
if (string.IsNullOrEmpty(configValueFromEnv))
64+
{
65+
logger.LogInformation(String.Format(" Environment variable {0} is not configured", configValue));
66+
return false;
67+
}
68+
69+
int numericValue = 0;
70+
bool conversionSuccessed = int.TryParse(configValueFromEnv, out numericValue);
71+
if (!conversionSuccessed)
72+
{
73+
logger.LogInformation(String.Format(" Unable to convert variable {0} to Integer", configValue));
74+
return false;
75+
}
76+
if (numericValue <= 0)
77+
{
78+
logger.LogInformation(String.Format(" Environment variable {0} is not a positive Integer", configValue));
79+
return false;
80+
}
81+
}
82+
83+
logger.LogInformation("Interger configuration validation completed successfully");
84+
return true;
85+
}
4686
}
4787
}

AzureFunctions/SendMailViaEXCH.cs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class SendMailViaEXCH
1515
private readonly ILogger<SendMailViaEXCH> _logger;
1616
private EmailMessageRequest? _emailMessageRequest = null!;
1717
private readonly List<string> _mandatoryConfigurationEntries = new List<string> { "ALLOWED_HOSTS", "EXCHANGE_SMTP_ENDPOINT", "EXCHANGE_SMTP_PORT", "EXCHANGE_SMTP_USERNAME", "EXCHANGE_SMTP_PASSWORD" };
18+
private readonly List<string> _mandatoryNumericConfigurationEntries = new List<string> { "EXCHANGE_SMTP_PORT" };
1819
private readonly string? _smtpEndpoint = Environment.GetEnvironmentVariable("EXCHANGE_SMTP_ENDPOINT");
1920
private readonly string? _smtpPort = Environment.GetEnvironmentVariable("EXCHANGE_SMTP_PORT");
2021
private readonly string? _smtpUsername = Environment.GetEnvironmentVariable("EXCHANGE_SMTP_USERNAME");
@@ -33,13 +34,21 @@ public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous,
3334
_logger.LogInformation(String.Format("Host: {0}.", req.Host));
3435
_logger.LogInformation(String.Format("Method: {0}..", req.Method));
3536

36-
if (!AssertConfiguration.ValidateConfigurationEntries(_logger, _mandatoryConfigurationEntries))
37+
if (!AssertConfiguration.VerifyConfiguratiopnEntriesExistence(_logger, _mandatoryConfigurationEntries))
3738
{
38-
return new ObjectResult(String.Format("One or more of the following environment variables are missing: {0}.", _mandatoryConfigurationEntries))
39+
return new ObjectResult(String.Format("One or more of the following environment variables are missing: {0}.", String.Join(",", _mandatoryConfigurationEntries)))
3940
{
4041
StatusCode = 500,
4142
};
4243
}
44+
if (!AssertConfiguration.VerifyNumericConfigurationEntries(_logger, _mandatoryNumericConfigurationEntries))
45+
{
46+
return new ObjectResult(String.Format("One or more of the following environment variables is not an Integer: {0}.", String.Join(",", _mandatoryConfigurationEntries)))
47+
{
48+
StatusCode = 500,
49+
};
50+
}
51+
4352
if (!AnalyzeRequestIP.IsIpAllowed(req.HttpContext.Connection.RemoteIpAddress, _logger))
4453
{
4554
return new UnauthorizedObjectResult(String.Format("Requests coming from IP {0} are not allowed.", req.HttpContext.Connection.RemoteIpAddress));
@@ -49,12 +58,17 @@ public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous,
4958
return new BadRequestObjectResult(String.Format("Requests method {0} is not allowed.", req.Method));
5059
}
5160

52-
int.TryParse(_smtpPort, out _numericSmtpPort);
61+
bool conversionSuccessed = int.TryParse(_smtpPort, out _numericSmtpPort);
62+
if (!conversionSuccessed)
63+
{
64+
return new UnprocessableEntityObjectResult(String.Format("Unable to convert SMTP port number: {0}.", _smtpPort));
65+
}
5366
if (_numericSmtpPort <= 0)
5467
{
5568
return new UnprocessableEntityObjectResult(String.Format("Invalid SMTP port number: {0}.", _smtpPort));
5669
}
5770

71+
5872
if (String.Equals(req.Method, "POST", StringComparison.OrdinalIgnoreCase))
5973
{
6074
if (req.ContentType != "application/json")

AzureFunctions/SendMailViaREST.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ public async Task<IActionResult> Run( [HttpTrigger(AuthorizationLevel.Anonymous,
2828
_logger.LogInformation(String.Format("Host: {0}.", req.Host));
2929
_logger.LogInformation(String.Format("Method: {0}.", req.Method));
3030

31-
if (!AssertConfiguration.ValidateConfigurationEntries(_logger, _mandatoryConfigurationEntries))
31+
if (!AssertConfiguration.VerifyConfiguratiopnEntriesExistence(_logger, _mandatoryConfigurationEntries))
3232
{
33-
return new ObjectResult(String.Format("One or more of the following environment variables are missing: {0}.", _mandatoryConfigurationEntries))
33+
return new ObjectResult(String.Format("One or more of the following environment variables are missing: {0}.", String.Join(",", _mandatoryConfigurationEntries)))
3434
{
3535
StatusCode = 500,
3636
};

AzureFunctions/SendMailViaSMTP.cs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ public class SendMailViaSMTP
1515
private readonly ILogger<SendMailViaSMTP> _logger;
1616
private EmailMessageRequest? _emailMessageRequest = null!;
1717
private readonly List<string> _mandatoryConfigurationEntries = new List<string> { "ALLOWED_HOSTS", "ACS_SMTP_ENDPOINT", "ACS_SMTP_PORT", "ACS_SMTP_USERNAME", "ACS_SMTP_PASSWORD" };
18+
private readonly List<string> _mandatoryNumericConfigurationEntries = new List<string> { "ACS_SMTP_PORT" };
1819
private readonly string? _smtpEndpoint = Environment.GetEnvironmentVariable("ACS_SMTP_ENDPOINT");
1920
private readonly string? _smtpPort = Environment.GetEnvironmentVariable("ACS_SMTP_PORT");
2021
private readonly string? _smtpUsername = Environment.GetEnvironmentVariable("ACS_SMTP_USERNAME");
@@ -33,13 +34,21 @@ public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous,
3334
_logger.LogInformation(String.Format("Host: {0}.", req.Host));
3435
_logger.LogInformation(String.Format("Method: {0}.", req.Method));
3536

36-
if (!AssertConfiguration.ValidateConfigurationEntries(_logger, _mandatoryConfigurationEntries))
37+
if (!AssertConfiguration.VerifyConfiguratiopnEntriesExistence(_logger, _mandatoryConfigurationEntries))
3738
{
38-
return new ObjectResult(String.Format("One or more of the following environment variables are missing: {0}.", _mandatoryConfigurationEntries))
39+
return new ObjectResult(String.Format("One or more of the following environment variables are missing: {0}.", String.Join(",", _mandatoryConfigurationEntries)))
3940
{
4041
StatusCode = 500,
4142
};
4243
}
44+
if (!AssertConfiguration.VerifyNumericConfigurationEntries(_logger, _mandatoryNumericConfigurationEntries))
45+
{
46+
return new ObjectResult(String.Format("One or more of the following environment variables is not an Integer: {0}.", String.Join(",", _mandatoryConfigurationEntries)))
47+
{
48+
StatusCode = 500,
49+
};
50+
}
51+
4352
if (!AnalyzeRequestIP.IsIpAllowed(req.HttpContext.Connection.RemoteIpAddress, _logger))
4453
{
4554
return new UnauthorizedObjectResult(String.Format("Requests coming from IP {0} are not allowed.", req.HttpContext.Connection.RemoteIpAddress));
@@ -49,7 +58,11 @@ public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous,
4958
return new BadRequestObjectResult(String.Format("Requests method {0} is not allowed.", req.Method));
5059
}
5160

52-
int.TryParse(_smtpPort, out _numericSmtpPort);
61+
bool conversionSuccessed = int.TryParse(_smtpPort, out _numericSmtpPort);
62+
if (!conversionSuccessed)
63+
{
64+
return new UnprocessableEntityObjectResult(String.Format("Unable to convert SMTP port number: {0}.", _smtpPort));
65+
}
5366
if (_numericSmtpPort <= 0)
5467
{
5568
return new UnprocessableEntityObjectResult(String.Format("Invalid SMTP port number: {0}.", _smtpPort));

0 commit comments

Comments
 (0)