Skip to content

Commit d7042a0

Browse files
cquirosjngallegos
andauthored
# Fix hostname validation in SCMU (#5241)
# Fix hostname validation in SCMU ## Summary This PR completes the fix for issue #5190 by adding proper hostname validation to ServiceControl.Config. While PR #5238 partially addressed the issue by allowing dashes in hostnames, it didn't implement comprehensive hostname validation, leaving users able to enter invalid hostnames that would cause configuration issues. ## Background **Original Issue**: #5190 reported that ServiceControl.Config was not properly validating hostname fields, allowing users to enter invalid values that would cause runtime failures. **Previous Fix**: PR #5238 addressed part of the problem by allowing dashes in hostnames, but the validation was still incomplete and didn't prevent other invalid hostname formats. **This Fix**: Implements comprehensive RFC-compliant hostname validation using .NET's built-in `Uri.CheckHostName()` method. ## Validation Behavior The new validation accepts: - ✅ Valid DNS hostnames (server01, myhost.domain.com) - ✅ localhost - ✅ Hostnames with dashes (server-01, my-host.domain.com) - *previously fixed by PR #5238* * test case for IPV6 * fixing broken implementation for ips * adding missing test cases * Update src/ServiceControl.Config.Tests/Validation/EditAuditInstanceValidationTests.cs Co-authored-by: Nick Gallegos <[email protected]>
1 parent ad39952 commit d7042a0

13 files changed

+201
-6
lines changed

src/ServiceControl.Config.Tests/Validation/AddAuditInstanceValidationTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,8 @@ public void Audit_hostname_can_not_be_null_when_adding_audit_instance()
321321

322322
[TestCase("192.168.1.1")]
323323
[TestCase("256.0.0.0")]
324+
[TestCase("::1")]
325+
[TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")]
324326
public void Audit_hostname_can_be_an_ip_address_when_adding_audit_instance(string ipAddress)
325327
{
326328
var viewModel = new ServiceControlAddViewModel
@@ -337,6 +339,33 @@ public void Audit_hostname_can_be_an_ip_address_when_adding_audit_instance(strin
337339
Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.AuditHostName)), Is.Empty);
338340
}
339341

342+
[TestCase("hostname with spaces")]
343+
[TestCase("bad@hostname")]
344+
[TestCase("bad#hostname")]
345+
[TestCase("badhostname...")]
346+
[TestCase("badhostname[/")]
347+
public void Audit_hostname_cannot_contain_invalid_characters_when_adding_audit_instance(string invalidHostname)
348+
{
349+
var viewModel = new ServiceControlAddViewModel
350+
{
351+
InstallAuditInstance = true,
352+
SubmitAttempted = true,
353+
AuditHostName = invalidHostname
354+
};
355+
356+
viewModel.NotifyOfPropertyChange(nameof(viewModel.AuditHostName));
357+
358+
var notifyErrorInfo = GetNotifyErrorInfo(viewModel);
359+
var errors = notifyErrorInfo.GetErrors(nameof(viewModel.AuditHostName));
360+
361+
Assert.Multiple(() =>
362+
{
363+
Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames");
364+
Assert.That(errors.Cast<string>().Any(error => error.Contains("Hostname is not valid")), Is.True,
365+
"Hostname validation should display the exact error message 'Hostname is not valid'");
366+
});
367+
}
368+
340369
#endregion
341370

342371
#region Portnumber

src/ServiceControl.Config.Tests/Validation/AddErrorInstanceValidationTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ public void Error_hostname_can_not_be_null_when_adding_error_instance()
320320

321321
[TestCase("192.168.1.1")]
322322
[TestCase("256.0.0.0")]
323+
[TestCase("::1")]
324+
[TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")]
323325
public void Error_hostname_can_be_an_ip_address_when_adding_error_instance(string ipAddress)
324326
{
325327
var viewModel = new ServiceControlAddViewModel
@@ -336,6 +338,33 @@ public void Error_hostname_can_be_an_ip_address_when_adding_error_instance(strin
336338
Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.ErrorHostName)), Is.Empty);
337339
}
338340

341+
[TestCase("hostname with spaces")]
342+
[TestCase("bad@hostname")]
343+
[TestCase("bad#hostname")]
344+
[TestCase("badhostname...")]
345+
[TestCase("badhostname[/")]
346+
public void Error_hostname_cannot_contain_invalid_characters_when_adding_error_instance(string invalidHostname)
347+
{
348+
var viewModel = new ServiceControlAddViewModel
349+
{
350+
InstallErrorInstance = true,
351+
SubmitAttempted = true,
352+
ErrorHostName = invalidHostname
353+
};
354+
355+
viewModel.NotifyOfPropertyChange(nameof(viewModel.ErrorHostName));
356+
357+
var notifyErrorInfo = GetNotifyErrorInfo(viewModel);
358+
var errors = notifyErrorInfo.GetErrors(nameof(viewModel.ErrorHostName));
359+
360+
Assert.Multiple(() =>
361+
{
362+
Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames");
363+
Assert.That(errors.Cast<string>().Any(error => error.Contains("Hostname is not valid")), Is.True,
364+
"Hostname validation should display the exact error message 'Hostname is not valid'");
365+
});
366+
}
367+
339368
#endregion
340369

341370
#region Portnumber

src/ServiceControl.Config.Tests/Validation/AddMonitoringInstanceValidationTests.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ public void Monitoring_hostname_cannot_be_null_when_adding_monitoring_instance()
127127

128128
[TestCase("192.168.1.1")]
129129
[TestCase("256.0.0.0")]
130+
[TestCase("::1")]
131+
[TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")]
130132
public void Monitoring_hostname_can_be_an_ip_address_when_adding_monitoring_instance(string ipAddress)
131133
{
132134
var viewModel = new MonitoringAddViewModel
@@ -142,6 +144,32 @@ public void Monitoring_hostname_can_be_an_ip_address_when_adding_monitoring_inst
142144
Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty);
143145
}
144146

147+
[TestCase("hostname with spaces")]
148+
[TestCase("bad@hostname")]
149+
[TestCase("bad#hostname")]
150+
[TestCase("badhostname...")]
151+
[TestCase("badhostname[/")]
152+
public void Monitoring_hostname_cannot_contain_invalid_characters_when_adding_monitoring_instance(string invalidHostname)
153+
{
154+
var viewModel = new MonitoringAddViewModel
155+
{
156+
SubmitAttempted = true,
157+
HostName = invalidHostname
158+
};
159+
160+
viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName));
161+
162+
var notifyErrorInfo = GetNotifyErrorInfo(viewModel);
163+
var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName));
164+
165+
Assert.Multiple(() =>
166+
{
167+
Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames");
168+
Assert.That(errors.Cast<string>().Any(error => error.Contains("Hostname is not valid")), Is.True,
169+
"Hostname validation should display the exact error message 'Hostname is not valid'");
170+
});
171+
}
172+
145173
#endregion
146174

147175
#region Portnumber

src/ServiceControl.Config.Tests/Validation/EditAuditInstanceValidationTests.cs

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace ServiceControl.Config.Tests.Validation
22
{
33
using System.ComponentModel;
4+
using System.Linq;
45
using NUnit.Framework;
56
using ServiceControlInstaller.Engine.Instances;
67
using UI.InstanceAdd;
@@ -127,7 +128,9 @@ public void Audit_hostname_can_not_be_null_when_editing_audit_instance()
127128

128129
[TestCase("192.168.1.1")]
129130
[TestCase("256.0.0.0")]
130-
public void Audi_hostname_can_be_an_ip_address_when_editing_an_audit_instance(string ipAddress)
131+
[TestCase("::1")]
132+
[TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")]
133+
public void Audit_hostname_can_be_an_ip_address_when_editing_an_audit_instance(string ipAddress)
131134
{
132135
var viewModel = new ServiceControlAuditEditViewModel
133136
{
@@ -142,6 +145,32 @@ public void Audi_hostname_can_be_an_ip_address_when_editing_an_audit_instance(st
142145
Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty);
143146
}
144147

148+
[TestCase("hostname with spaces")]
149+
[TestCase("bad@hostname")]
150+
[TestCase("bad#hostname")]
151+
[TestCase("badhostname...")]
152+
[TestCase("badhostname[/")]
153+
public void Audit_hostname_cannot_contain_invalid_characters_when_editing_audit_instance(string invalidHostname)
154+
{
155+
var viewModel = new ServiceControlAuditEditViewModel
156+
{
157+
SubmitAttempted = true,
158+
HostName = invalidHostname
159+
};
160+
161+
viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName));
162+
163+
var notifyErrorInfo = GetNotifyErrorInfo(viewModel);
164+
var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName));
165+
166+
Assert.Multiple(() =>
167+
{
168+
Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames");
169+
Assert.That(errors.Cast<string>().Any(error => error.Contains("Hostname is not valid")), Is.True,
170+
"Hostname validation should display the exact error message 'Hostname is not valid'");
171+
});
172+
}
173+
145174
#endregion
146175

147176
#region Portnumber

src/ServiceControl.Config.Tests/Validation/EditErrorInstanceValidationTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace ServiceControl.Config.Tests.Validation
22
{
33
using System.ComponentModel;
4+
using System.Linq;
45
using NUnit.Framework;
56
using ServiceControlInstaller.Engine.Instances;
67
using UI.InstanceAdd;
@@ -120,6 +121,8 @@ public void Error_hostname_can_not_be_null_when_editing_error_instance()
120121

121122
[TestCase("192.168.1.1")]
122123
[TestCase("256.0.0.0")]
124+
[TestCase("::1")]
125+
[TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")]
123126
public void Error_hostname_can_be_an_ip_address_when_editing_an_error_instance(string ipAddress)
124127
{
125128
var viewModel = new ServiceControlEditViewModel
@@ -135,6 +138,32 @@ public void Error_hostname_can_be_an_ip_address_when_editing_an_error_instance(s
135138
Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty);
136139
}
137140

141+
[TestCase("hostname with spaces")]
142+
[TestCase("bad@hostname")]
143+
[TestCase("bad#hostname")]
144+
[TestCase("badhostname...")]
145+
[TestCase("badhostname[/")]
146+
public void Error_hostname_cannot_contain_invalid_characters_when_editing_error_instance(string invalidHostname)
147+
{
148+
var viewModel = new ServiceControlEditViewModel
149+
{
150+
SubmitAttempted = true,
151+
HostName = invalidHostname
152+
};
153+
154+
viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName));
155+
156+
var notifyErrorInfo = GetNotifyErrorInfo(viewModel);
157+
var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName));
158+
159+
Assert.Multiple(() =>
160+
{
161+
Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames");
162+
Assert.That(errors.Cast<string>().Any(error => error.Contains("Hostname is not valid")), Is.True,
163+
"Hostname validation should display the exact error message 'Hostname is not valid'");
164+
});
165+
}
166+
138167
#endregion
139168

140169
#region Portnumber

src/ServiceControl.Config.Tests/Validation/EditMonitoringInstanceValidationTests.cs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace ServiceControl.Config.Tests.Validation
22
{
33
using System.ComponentModel;
4+
using System.Linq;
45
using NUnit.Framework;
56
using UI.InstanceEdit;
67

@@ -42,6 +43,8 @@ public void Monitoring_hostname_cannot_be_null_when_editing_monitoring_instance(
4243

4344
[TestCase("192.168.1.1")]
4445
[TestCase("256.0.0.0")]
46+
[TestCase("::1")]
47+
[TestCase("2001:0db8:85a3:0000:0000:8a2e:0370:7334")]
4548
public void Monitoring_hostname_can_be_an_ip_address_when_editing_a_monitoring_instance(string ipAddress)
4649
{
4750
var viewModel = new MonitoringEditViewModel
@@ -56,6 +59,32 @@ public void Monitoring_hostname_can_be_an_ip_address_when_editing_a_monitoring_i
5659

5760
Assert.That(notifyErrorInfo.GetErrors(nameof(viewModel.HostName)), Is.Empty);
5861
}
62+
63+
[TestCase("hostname with spaces")]
64+
[TestCase("bad@hostname")]
65+
[TestCase("bad#hostname")]
66+
[TestCase("badhostname...")]
67+
[TestCase("badhostname[/")]
68+
public void Monitoring_hostname_cannot_contain_invalid_characters_when_editing_monitoring_instance(string invalidHostname)
69+
{
70+
var viewModel = new MonitoringEditViewModel
71+
{
72+
SubmitAttempted = true,
73+
HostName = invalidHostname
74+
};
75+
76+
viewModel.NotifyOfPropertyChange(nameof(viewModel.HostName));
77+
78+
var notifyErrorInfo = GetNotifyErrorInfo(viewModel);
79+
var errors = notifyErrorInfo.GetErrors(nameof(viewModel.HostName));
80+
81+
Assert.Multiple(() =>
82+
{
83+
Assert.That(errors, Is.Not.Empty, "Hostname validation should exist and trigger for invalid hostnames");
84+
Assert.That(errors.Cast<string>().Any(error => error.Contains("Hostname is not valid")), Is.True,
85+
"Hostname validation should display the exact error message 'Hostname is not valid'");
86+
});
87+
}
5988
#endregion
6089

6190
#region Portnumber

src/ServiceControl.Config/UI/InstanceAdd/ServiceControlAddViewModelValidator.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ public ServiceControlAddViewModelValidator()
5252

5353
RuleFor(viewModel => viewModel.ErrorHostName)
5454
.NotEmpty()
55+
.ValidHostname()
5556
.When(viewModel => viewModel.InstallErrorInstance);
5657

5758
RuleFor(x => x.ErrorPortNumber)
@@ -155,6 +156,7 @@ public ServiceControlAddViewModelValidator()
155156

156157
RuleFor(viewModel => viewModel.AuditHostName)
157158
.NotEmpty()
159+
.ValidHostname()
158160
.When(viewModel => viewModel.InstallAuditInstance);
159161

160162
RuleFor(x => x.AuditPortNumber)

src/ServiceControl.Config/UI/InstanceEdit/MonitoringEditViewModelValidator.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@ public MonitoringEditViewModelValidator()
1212
.NotEmpty()
1313
.When(x => x.SubmitAttempted);
1414

15-
RuleFor(x => x.HostName)
16-
.NotEmpty()
17-
.When(x => x.SubmitAttempted);
18-
1915
RuleFor(x => x.PortNumber)
2016
.NotEmpty()
2117
.ValidPort()

src/ServiceControl.Config/UI/InstanceEdit/ServiceControlAuditEditViewModelValidator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public ServiceControlAuditEditViewModelValidator()
1414

1515
RuleFor(x => x.HostName)
1616
.NotEmpty()
17+
.ValidHostname()
1718
.When(x => x.SubmitAttempted);
1819

1920
RuleFor(x => x.PortNumber)

src/ServiceControl.Config/UI/InstanceEdit/ServiceControlEditViewModelValidator.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public ServiceControlEditViewModelValidator()
1414

1515
RuleFor(x => x.HostName)
1616
.NotEmpty()
17+
.ValidHostname()
1718
.When(x => x.SubmitAttempted);
1819

1920
RuleFor(x => x.PortNumber)

0 commit comments

Comments
 (0)