2
0
mirror of https://github.com/VinylDNS/vinyldns synced 2025-08-30 22:05:21 +00:00

Merge branch 'feature/groupemailvalidations' of https://github.com/ssranjani06/vinyldns into feature/groupemailvalidations

To push the changes
This commit is contained in:
ssranjani06
2023-03-14 12:03:39 +05:30
7 changed files with 116 additions and 35 deletions

View File

@@ -27,6 +27,7 @@ import scala.util.matching.Regex
Object to house common domain validations
*/
object DomainValidations {
val validReverseZoneFQDNRegex: Regex =
"""^(?:([0-9a-zA-Z\-\/_]{1,63}|[0-9a-zA-Z\-\/_]{1}[0-9a-zA-Z\-\/_]{0,61}[0-9a-zA-Z\-\/_]{1}|[*.]{2}[0-9a-zA-Z\-\/_]{0,60}[0-9a-zA-Z\-\/_]{1})\.)*$""".r
val validForwardZoneFQDNRegex: Regex =
@@ -61,13 +62,20 @@ object DomainValidations {
val MX_PREFERENCE_MIN_VALUE: Int = 0
val MX_PREFERENCE_MAX_VALUE: Int = 65535
// Cname check - Cname should not be IP address
def validateCname(name: Fqdn, isReverse: Boolean): ValidatedNel[DomainValidationError, Fqdn] =
validateIpv4Address(name.fqdn.dropRight(1)).isValid match {
case true => InvalidIPv4CName(name.toString).invalidNel
case false => validateIsReverseCname(name, isReverse)
}
def validateHostName(name: Fqdn): ValidatedNel[DomainValidationError, Fqdn] =
validateHostName(name.fqdn).map(_ => name)
def validateCname(name: Fqdn, isReverse: Boolean): ValidatedNel[DomainValidationError, Fqdn] =
validateCname(name.fqdn, isReverse).map(_ => name)
def validateIsReverseCname(name: Fqdn, isReverse: Boolean): ValidatedNel[DomainValidationError, Fqdn] =
validateIsReverseCname(name.fqdn, isReverse).map(_ => name)
def validateCname(name: String, isReverse: Boolean): ValidatedNel[DomainValidationError, String] = {
def validateIsReverseCname(name: String, isReverse: Boolean): ValidatedNel[DomainValidationError, String] = {
isReverse match {
case true =>
val checkRegex = validReverseZoneFQDNRegex

View File

@@ -1938,7 +1938,8 @@ def test_cname_recordtype_add_checks(shared_zone_test_context):
get_change_CNAME_json(existing_forward_fqdn),
get_change_CNAME_json(existing_cname_fqdn),
get_change_CNAME_json(f"0.{ip4_zone_name}", cname="duplicate.in.db."),
get_change_CNAME_json(f"user-add-unauthorized.{dummy_zone_name}")
get_change_CNAME_json(f"user-add-unauthorized.{dummy_zone_name}"),
get_change_CNAME_json(f"invalid-ipv4-{parent_zone_name}", cname="1.2.3.4")
]
}
@@ -2014,6 +2015,9 @@ def test_cname_recordtype_add_checks(shared_zone_test_context):
assert_failed_change_in_error_response(response[16], input_name=f"user-add-unauthorized.{dummy_zone_name}",
record_type="CNAME", record_data="test.com.",
error_messages=[f"User \"ok\" is not authorized. Contact zone owner group: {dummy_group_name} at test@test.com to make DNS changes."])
assert_failed_change_in_error_response(response[17], input_name=f"invalid-ipv4-{parent_zone_name}", record_type="CNAME", record_data="1.2.3.4.",
error_messages=[f'Invalid Cname: "Fqdn(1.2.3.4.)", Valid CNAME record data should not be an IP address'])
finally:
clear_recordset_list(to_delete, client)

View File

@@ -22,7 +22,7 @@ import org.scalatestplus.scalacheck.ScalaCheckDrivenPropertyChecks
import org.scalatest.propspec.AnyPropSpec
import org.scalatest.matchers.should.Matchers
import vinyldns.api.ValidationTestImprovements._
import vinyldns.core.domain.{InvalidDomainName, InvalidCname, InvalidLength}
import vinyldns.core.domain.{InvalidDomainName, Fqdn, InvalidCname, InvalidLength}
class DomainValidationsSpec
extends AnyPropSpec
@@ -77,6 +77,54 @@ class DomainValidationsSpec
validateHostName("asterisk.domain*.name.") shouldBe invalid
}
property("Shortest fqdn name should be valid") {
val fqdn = Fqdn("a.")
validateCname(fqdn, false) shouldBe valid
}
property("Ip address in cname should be invalid") {
val fqdn = Fqdn("1.2.3.4")
validateCname(fqdn, false) shouldBe invalid
}
property("Longest fqdn name should be valid") {
val fqdn = Fqdn(("a" * 50 + ".") * 5)
validateCname(fqdn, false) shouldBe valid
}
property("fqdn name should pass property-based testing") {
forAll(domainGenerator) { domain: String =>
val domains= Fqdn(domain)
whenever(validateHostName(domains).isValid) {
domains.fqdn.length should be > 0
domains.fqdn.length should be < 256
(domains.fqdn should fullyMatch).regex(validFQDNRegex)
domains.fqdn should endWith(".")
}
}
}
property("fqdn names beginning with invalid characters should fail with InvalidCname") {
validateCname(Fqdn("/slash.domain.name."), false).failWith[InvalidCname]
validateCname(Fqdn("-hyphen.domain.name."), false).failWith[InvalidCname]
}
property("fqdn names with underscores should pass property-based testing") {
validateCname(Fqdn("_underscore.domain.name."), false).isValid
validateCname(Fqdn("under_score.domain.name."), false).isValid
validateCname(Fqdn("underscore._domain.name."), false).isValid
}
// For wildcard records. '*' can only be in the beginning followed by '.' and domain name
property("fqdn names beginning with asterisk should pass property-based testing") {
validateCname(Fqdn("*.domain.name."), false) shouldBe valid
validateCname(Fqdn("aste*risk.domain.name."),false) shouldBe invalid
validateCname(Fqdn("*asterisk.domain.name."),false) shouldBe invalid
validateCname(Fqdn("asterisk*.domain.name."),false) shouldBe invalid
validateCname(Fqdn("asterisk.*domain.name."),false)shouldBe invalid
validateCname(Fqdn("asterisk.domain*.name."),false) shouldBe invalid
}
property("Valid Ipv4 addresses should pass property-based testing") {
forAll(validIpv4Gen) { validIp: String =>
val res = validateIpv4Address(validIp)
@@ -112,50 +160,50 @@ class DomainValidationsSpec
}
property("Shortest cname should be valid") {
validateCname("a.",true) shouldBe valid
validateCname("a.",false) shouldBe valid
validateIsReverseCname("a.",true) shouldBe valid
validateIsReverseCname("a.",false) shouldBe valid
}
property("Longest cname should be valid") {
val name = ("a" * 50 + ".") * 5
validateCname(name,true) shouldBe valid
validateCname(name,false) shouldBe valid
validateIsReverseCname(name,true) shouldBe valid
validateIsReverseCname(name,false) shouldBe valid
}
property("Cnames with underscores should pass property-based testing") {
validateCname("_underscore.domain.name.",true).isValid
validateCname("under_score.domain.name.",true).isValid
validateCname("underscore._domain.name.",true).isValid
validateCname("_underscore.domain.name.",false).isValid
validateCname("under_score.domain.name.",false).isValid
validateCname("underscore._domain.name.",false).isValid
validateIsReverseCname("_underscore.domain.name.",true).isValid
validateIsReverseCname("under_score.domain.name.",true).isValid
validateIsReverseCname("underscore._domain.name.",true).isValid
validateIsReverseCname("_underscore.domain.name.",false).isValid
validateIsReverseCname("under_score.domain.name.",false).isValid
validateIsReverseCname("underscore._domain.name.",false).isValid
}
// For wildcard records. '*' can only be in the beginning followed by '.' and domain name
property("Cnames beginning with asterisk should pass property-based testing") {
validateCname("*.domain.name.",true) shouldBe valid
validateCname("aste*risk.domain.name.",true) shouldBe invalid
validateCname("*asterisk.domain.name.",true) shouldBe invalid
validateCname("asterisk*.domain.name.",true) shouldBe invalid
validateCname("asterisk.*domain.name.",true) shouldBe invalid
validateCname("asterisk.domain*.name.",true) shouldBe invalid
validateCname("*.domain.name.",false) shouldBe valid
validateCname("aste*risk.domain.name.",false) shouldBe invalid
validateCname("*asterisk.domain.name.",false) shouldBe invalid
validateCname("asterisk*.domain.name.",false) shouldBe invalid
validateCname("asterisk.*domain.name.",false) shouldBe invalid
validateCname("asterisk.domain*.name.",false) shouldBe invalid
validateIsReverseCname("*.domain.name.",true) shouldBe valid
validateIsReverseCname("aste*risk.domain.name.",true) shouldBe invalid
validateIsReverseCname("*asterisk.domain.name.",true) shouldBe invalid
validateIsReverseCname("asterisk*.domain.name.",true) shouldBe invalid
validateIsReverseCname("asterisk.*domain.name.",true) shouldBe invalid
validateIsReverseCname("asterisk.domain*.name.",true) shouldBe invalid
validateIsReverseCname("*.domain.name.",false) shouldBe valid
validateIsReverseCname("aste*risk.domain.name.",false) shouldBe invalid
validateIsReverseCname("*asterisk.domain.name.",false) shouldBe invalid
validateIsReverseCname("asterisk*.domain.name.",false) shouldBe invalid
validateIsReverseCname("asterisk.*domain.name.",false) shouldBe invalid
validateIsReverseCname("asterisk.domain*.name.",false) shouldBe invalid
}
property("Cname names with forward slash should pass with reverse zone") {
validateCname("/slash.cname.name.",true).isValid
validateCname("slash./cname.name.",true).isValid
validateCname("slash.cname./name.",true).isValid
validateIsReverseCname("/slash.cname.name.",true).isValid
validateIsReverseCname("slash./cname.name.",true).isValid
validateIsReverseCname("slash.cname./name.",true).isValid
}
property("Cname names with forward slash should fail with forward zone") {
validateCname("/slash.cname.name.",false).failWith[InvalidCname]
validateCname("slash./cname.name.",false).failWith[InvalidCname]
validateCname("slash.cname./name.",false).failWith[InvalidCname]
validateIsReverseCname("/slash.cname.name.",false).failWith[InvalidCname]
validateIsReverseCname("slash./cname.name.",false).failWith[InvalidCname]
validateIsReverseCname("slash.cname./name.",false).failWith[InvalidCname]
}
}

View File

@@ -717,6 +717,21 @@ class BatchChangeValidationsSpec
result should haveInvalid[DomainValidationError](InvalidCname(s"$invalidCNAMERecordData.",false))
}
property("""validateAddChangeInput: should fail with Invalid CNAME
|if validateRecordData fails for IPv4 Address in CNAME record data""".stripMargin) {
val invalidCNAMERecordData = "1.2.3.4"
val change =
AddChangeInput(
"test.comcast.com.",
RecordType.CNAME,
ttl,
CNAMEData(Fqdn(invalidCNAMERecordData))
)
val result = validateAddChangeInput(change, false)
result should haveInvalid[DomainValidationError](InvalidIPv4CName(s"Fqdn($invalidCNAMERecordData.)"))
}
property("""validateAddChangeInput: should fail with InvalidLength
|if validateRecordData fails for invalid CNAME record data""".stripMargin) {
val invalidCNAMERecordData = "s" * 256

View File

@@ -52,6 +52,11 @@ final case class InvalidDomainName(param: String) extends DomainValidationError
"joined by dots, and terminated with a dot."
}
final case class InvalidIPv4CName(param: String) extends DomainValidationError {
def message: String =
s"""Invalid Cname: "$param", Valid CNAME record data should not be an IP address"""
}
final case class InvalidCname(param: String, isReverseZone: Boolean) extends DomainValidationError {
def message: String =
isReverseZone match {

View File

@@ -36,7 +36,7 @@ object DomainValidationErrorType extends Enumeration {
CnameIsNotUniqueError, UserIsNotAuthorized, UserIsNotAuthorizedError, RecordNameNotUniqueInBatch,
RecordInReverseZoneError, HighValueDomainError, MissingOwnerGroupId, ExistingMultiRecordError,
NewMultiRecordError, CnameAtZoneApexError, RecordRequiresManualReview, UnsupportedOperation,
DeleteRecordDataDoesNotExist = Value
DeleteRecordDataDoesNotExist, InvalidIPv4CName = Value
// $COVERAGE-OFF$
def from(error: DomainValidationError): DomainValidationErrorType =
@@ -74,6 +74,7 @@ object DomainValidationErrorType extends Enumeration {
case _: RecordRequiresManualReview => RecordRequiresManualReview
case _: UnsupportedOperation => UnsupportedOperation
case _: DeleteRecordDataDoesNotExist => DeleteRecordDataDoesNotExist
case _: InvalidIPv4CName => InvalidIPv4CName
}
// $COVERAGE-ON$
}