mirror of
https://github.com/VinylDNS/vinyldns
synced 2025-09-01 06:45:21 +00:00
Merge branch 'master' into disallow_ipv4_in_cname_manage_records
This commit is contained in:
@@ -131,6 +131,9 @@ vinyldns {
|
|||||||
from = ${?EMAIL_FROM}
|
from = ${?EMAIL_FROM}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
valid-email-config{
|
||||||
|
email-domains = ["test.com","*dummy.com"]
|
||||||
|
}
|
||||||
|
|
||||||
sns {
|
sns {
|
||||||
class-name = "vinyldns.apadi.notifier.sns.SnsNotifierProvider"
|
class-name = "vinyldns.apadi.notifier.sns.SnsNotifierProvider"
|
||||||
|
@@ -169,7 +169,9 @@ vinyldns {
|
|||||||
from = "VinylDNS <do-not-reply@vinyldns.io>"
|
from = "VinylDNS <do-not-reply@vinyldns.io>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
valid-email-config{
|
||||||
|
email-domains = ["test.com","*dummy.com"]
|
||||||
|
}
|
||||||
sns {
|
sns {
|
||||||
class-name = "vinyldns.api.notifier.sns.SnsNotifierProvider"
|
class-name = "vinyldns.api.notifier.sns.SnsNotifierProvider"
|
||||||
settings {
|
settings {
|
||||||
|
@@ -142,7 +142,7 @@ object Boot extends App {
|
|||||||
vinyldnsConfig.batchChangeConfig,
|
vinyldnsConfig.batchChangeConfig,
|
||||||
vinyldnsConfig.scheduledChangesConfig
|
vinyldnsConfig.scheduledChangesConfig
|
||||||
)
|
)
|
||||||
val membershipService = MembershipService(repositories)
|
val membershipService = MembershipService(repositories,vinyldnsConfig.validEmailConfig)
|
||||||
|
|
||||||
val connectionValidator =
|
val connectionValidator =
|
||||||
new ZoneConnectionValidator(
|
new ZoneConnectionValidator(
|
||||||
|
@@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 Comcast Cable Communications Management, LLC
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package vinyldns.api.config
|
||||||
|
|
||||||
|
import pureconfig.ConfigReader
|
||||||
|
|
||||||
|
case class ValidEmailConfig(
|
||||||
|
valid_domains : List[String]
|
||||||
|
)
|
||||||
|
object ValidEmailConfig {
|
||||||
|
implicit val configReader: ConfigReader[ValidEmailConfig] =
|
||||||
|
ConfigReader.forProduct1[ValidEmailConfig,List[String]](
|
||||||
|
"email-domains"
|
||||||
|
|
||||||
|
) {
|
||||||
|
case valid_domains => ValidEmailConfig(valid_domains)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -38,6 +38,7 @@ import scala.reflect.ClassTag
|
|||||||
final case class VinylDNSConfig(
|
final case class VinylDNSConfig(
|
||||||
serverConfig: ServerConfig,
|
serverConfig: ServerConfig,
|
||||||
limitsconfig: LimitsConfig,
|
limitsconfig: LimitsConfig,
|
||||||
|
validEmailConfig: ValidEmailConfig,
|
||||||
httpConfig: HttpConfig,
|
httpConfig: HttpConfig,
|
||||||
highValueDomainConfig: HighValueDomainConfig,
|
highValueDomainConfig: HighValueDomainConfig,
|
||||||
manualReviewConfig: ManualReviewConfig,
|
manualReviewConfig: ManualReviewConfig,
|
||||||
@@ -83,6 +84,7 @@ object VinylDNSConfig {
|
|||||||
for {
|
for {
|
||||||
config <- IO.delay(ConfigFactory.load())
|
config <- IO.delay(ConfigFactory.load())
|
||||||
limitsconfig <- loadIO[LimitsConfig](config, "vinyldns.api.limits") //Added Limitsconfig to fetch data from the reference.config and pass to LimitsConfig.config
|
limitsconfig <- loadIO[LimitsConfig](config, "vinyldns.api.limits") //Added Limitsconfig to fetch data from the reference.config and pass to LimitsConfig.config
|
||||||
|
validEmailConfig <- loadIO[ValidEmailConfig](config, path="vinyldns.valid-email-config")
|
||||||
serverConfig <- loadIO[ServerConfig](config, "vinyldns")
|
serverConfig <- loadIO[ServerConfig](config, "vinyldns")
|
||||||
batchChangeConfig <- loadIO[BatchChangeConfig](config, "vinyldns")
|
batchChangeConfig <- loadIO[BatchChangeConfig](config, "vinyldns")
|
||||||
backendConfigs <- loadIO[BackendConfigs](config, "vinyldns.backend")
|
backendConfigs <- loadIO[BackendConfigs](config, "vinyldns.backend")
|
||||||
@@ -103,6 +105,7 @@ object VinylDNSConfig {
|
|||||||
} yield VinylDNSConfig(
|
} yield VinylDNSConfig(
|
||||||
serverConfig,
|
serverConfig,
|
||||||
limitsconfig,
|
limitsconfig,
|
||||||
|
validEmailConfig,
|
||||||
httpConfig,
|
httpConfig,
|
||||||
hvdConfig,
|
hvdConfig,
|
||||||
manualReviewConfig,
|
manualReviewConfig,
|
||||||
|
@@ -178,6 +178,8 @@ final case class GroupAlreadyExistsError(msg: String) extends Throwable(msg)
|
|||||||
|
|
||||||
final case class GroupValidationError(msg: String) extends Throwable(msg)
|
final case class GroupValidationError(msg: String) extends Throwable(msg)
|
||||||
|
|
||||||
|
final case class EmailValidationError(msg: String) extends Throwable(msg)
|
||||||
|
|
||||||
final case class UserNotFoundError(msg: String) extends Throwable(msg)
|
final case class UserNotFoundError(msg: String) extends Throwable(msg)
|
||||||
|
|
||||||
final case class InvalidGroupError(msg: String) extends Throwable(msg)
|
final case class InvalidGroupError(msg: String) extends Throwable(msg)
|
||||||
|
@@ -20,6 +20,7 @@ import cats.effect.IO
|
|||||||
import cats.implicits._
|
import cats.implicits._
|
||||||
import scalikejdbc.DB
|
import scalikejdbc.DB
|
||||||
import vinyldns.api.Interfaces._
|
import vinyldns.api.Interfaces._
|
||||||
|
import vinyldns.api.config.ValidEmailConfig
|
||||||
import vinyldns.api.repository.ApiDataAccessor
|
import vinyldns.api.repository.ApiDataAccessor
|
||||||
import vinyldns.core.domain.auth.AuthPrincipal
|
import vinyldns.core.domain.auth.AuthPrincipal
|
||||||
import vinyldns.core.domain.membership.LockStatus.LockStatus
|
import vinyldns.core.domain.membership.LockStatus.LockStatus
|
||||||
@@ -30,14 +31,15 @@ import vinyldns.core.Messages._
|
|||||||
import vinyldns.mysql.TransactionProvider
|
import vinyldns.mysql.TransactionProvider
|
||||||
|
|
||||||
object MembershipService {
|
object MembershipService {
|
||||||
def apply(dataAccessor: ApiDataAccessor): MembershipService =
|
def apply(dataAccessor: ApiDataAccessor,emailConfig:ValidEmailConfig): MembershipService =
|
||||||
new MembershipService(
|
new MembershipService(
|
||||||
dataAccessor.groupRepository,
|
dataAccessor.groupRepository,
|
||||||
dataAccessor.userRepository,
|
dataAccessor.userRepository,
|
||||||
dataAccessor.membershipRepository,
|
dataAccessor.membershipRepository,
|
||||||
dataAccessor.zoneRepository,
|
dataAccessor.zoneRepository,
|
||||||
dataAccessor.groupChangeRepository,
|
dataAccessor.groupChangeRepository,
|
||||||
dataAccessor.recordSetRepository
|
dataAccessor.recordSetRepository,
|
||||||
|
emailConfig
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,7 +49,8 @@ class MembershipService(
|
|||||||
membershipRepo: MembershipRepository,
|
membershipRepo: MembershipRepository,
|
||||||
zoneRepo: ZoneRepository,
|
zoneRepo: ZoneRepository,
|
||||||
groupChangeRepo: GroupChangeRepository,
|
groupChangeRepo: GroupChangeRepository,
|
||||||
recordSetRepo: RecordSetRepository
|
recordSetRepo: RecordSetRepository,
|
||||||
|
validDomains: ValidEmailConfig
|
||||||
) extends MembershipServiceAlgebra with TransactionProvider {
|
) extends MembershipServiceAlgebra with TransactionProvider {
|
||||||
|
|
||||||
import MembershipValidations._
|
import MembershipValidations._
|
||||||
@@ -58,6 +61,7 @@ class MembershipService(
|
|||||||
val nonAdminMembers = inputGroup.memberIds.diff(adminMembers)
|
val nonAdminMembers = inputGroup.memberIds.diff(adminMembers)
|
||||||
for {
|
for {
|
||||||
_ <- groupValidation(newGroup)
|
_ <- groupValidation(newGroup)
|
||||||
|
_ <- emailValidation(newGroup.email)
|
||||||
_ <- hasMembersAndAdmins(newGroup).toResult
|
_ <- hasMembersAndAdmins(newGroup).toResult
|
||||||
_ <- groupWithSameNameDoesNotExist(newGroup.name)
|
_ <- groupWithSameNameDoesNotExist(newGroup.name)
|
||||||
_ <- usersExist(newGroup.memberIds)
|
_ <- usersExist(newGroup.memberIds)
|
||||||
@@ -78,6 +82,7 @@ class MembershipService(
|
|||||||
existingGroup <- getExistingGroup(groupId)
|
existingGroup <- getExistingGroup(groupId)
|
||||||
newGroup = existingGroup.withUpdates(name, email, description, memberIds, adminUserIds)
|
newGroup = existingGroup.withUpdates(name, email, description, memberIds, adminUserIds)
|
||||||
_ <- groupValidation(newGroup)
|
_ <- groupValidation(newGroup)
|
||||||
|
_ <- emailValidation(newGroup.email)
|
||||||
_ <- canEditGroup(existingGroup, authPrincipal).toResult
|
_ <- canEditGroup(existingGroup, authPrincipal).toResult
|
||||||
addedAdmins = newGroup.adminUserIds.diff(existingGroup.adminUserIds)
|
addedAdmins = newGroup.adminUserIds.diff(existingGroup.adminUserIds)
|
||||||
// new non-admin members ++ admins converted to non-admins
|
// new non-admin members ++ admins converted to non-admins
|
||||||
@@ -381,6 +386,29 @@ class MembershipService(
|
|||||||
().asRight
|
().asRight
|
||||||
}
|
}
|
||||||
}.toResult
|
}.toResult
|
||||||
|
// Validate email details.Email domains details are fetched from the config file.
|
||||||
|
def emailValidation(email: String): Result[Unit] = {
|
||||||
|
val emailDomains = validDomains.valid_domains
|
||||||
|
val splitEmailDomains = emailDomains.mkString(",")
|
||||||
|
val emailRegex ="""^(?!\.)(?!.*\.$)(?!.*\.\.)[a-zA-Z0-9._]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$""".r
|
||||||
|
val index = email.indexOf('@');
|
||||||
|
val emailSplit = if(index != -1){
|
||||||
|
email.substring(index+1,email.length)}
|
||||||
|
val wildcardEmailDomains=if(splitEmailDomains.contains("*")){
|
||||||
|
emailDomains.map(x=>x.replaceAllLiterally("*",""))}
|
||||||
|
else emailDomains
|
||||||
|
|
||||||
|
Option(email) match {
|
||||||
|
case Some(value) if (emailRegex.findFirstIn(value) != None)=>
|
||||||
|
|
||||||
|
if (emailDomains.contains(emailSplit) || emailDomains.isEmpty || wildcardEmailDomains.exists(x => emailSplit.toString.endsWith(x)))
|
||||||
|
().asRight
|
||||||
|
else
|
||||||
|
EmailValidationError(EmailValidationErrorMsg + " " + wildcardEmailDomains.mkString(",")).asLeft
|
||||||
|
case _ =>
|
||||||
|
EmailValidationError(InvalidEmailValidationErrorMsg).asLeft
|
||||||
|
}}.toResult
|
||||||
|
|
||||||
|
|
||||||
def groupWithSameNameDoesNotExist(name: String): Result[Unit] =
|
def groupWithSameNameDoesNotExist(name: String): Result[Unit] =
|
||||||
groupRepo
|
groupRepo
|
||||||
|
@@ -49,6 +49,7 @@ class MembershipRoute(
|
|||||||
case InvalidGroupError(msg) => complete(StatusCodes.BadRequest, msg)
|
case InvalidGroupError(msg) => complete(StatusCodes.BadRequest, msg)
|
||||||
case UserNotFoundError(msg) => complete(StatusCodes.NotFound, msg)
|
case UserNotFoundError(msg) => complete(StatusCodes.NotFound, msg)
|
||||||
case InvalidGroupRequestError(msg) => complete(StatusCodes.BadRequest, msg)
|
case InvalidGroupRequestError(msg) => complete(StatusCodes.BadRequest, msg)
|
||||||
|
case EmailValidationError(msg) => complete(StatusCodes.BadRequest, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
val membershipRoute: Route = path("groups" / Segment) { groupId =>
|
val membershipRoute: Route = path("groups" / Segment) { groupId =>
|
||||||
|
@@ -10,7 +10,7 @@ def test_create_group_success(shared_zone_test_context):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
new_group = {
|
new_group = {
|
||||||
"name": f"test-create-group-success{shared_zone_test_context.partition_id}",
|
"name": "test-create-group-success{shared_zone_test_context.partition_id}",
|
||||||
"email": "test@test.com",
|
"email": "test@test.com",
|
||||||
"description": "this is a description",
|
"description": "this is a description",
|
||||||
"members": [{"id": "ok"}],
|
"members": [{"id": "ok"}],
|
||||||
@@ -32,6 +32,36 @@ def test_create_group_success(shared_zone_test_context):
|
|||||||
if result:
|
if result:
|
||||||
client.delete_group(result["id"], status=(200, 404))
|
client.delete_group(result["id"], status=(200, 404))
|
||||||
|
|
||||||
|
def test_create_group_success_wildcard(shared_zone_test_context):
|
||||||
|
"""
|
||||||
|
Tests that creating a group works
|
||||||
|
"""
|
||||||
|
client = shared_zone_test_context.ok_vinyldns_client
|
||||||
|
result = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
new_group = {
|
||||||
|
"name": "test-create-group-success_wildcard{shared_zone_test_context.partition_id}",
|
||||||
|
"email": "test@ok.dummy.com",
|
||||||
|
"description": "this is a description",
|
||||||
|
"members": [{"id": "ok"}],
|
||||||
|
"admins": [{"id": "ok"}]
|
||||||
|
}
|
||||||
|
result = client.create_group(new_group, status=200)
|
||||||
|
|
||||||
|
assert_that(result["name"], is_(new_group["name"]))
|
||||||
|
assert_that(result["email"], is_(new_group["email"]))
|
||||||
|
assert_that(result["description"], is_(new_group["description"]))
|
||||||
|
assert_that(result["status"], is_("Active"))
|
||||||
|
assert_that(result["created"], not_none())
|
||||||
|
assert_that(result["id"], not_none())
|
||||||
|
assert_that(result["members"], has_length(1))
|
||||||
|
assert_that(result["members"][0]["id"], is_("ok"))
|
||||||
|
assert_that(result["admins"], has_length(1))
|
||||||
|
assert_that(result["admins"][0]["id"], is_("ok"))
|
||||||
|
finally:
|
||||||
|
if result:
|
||||||
|
client.delete_group(result["id"], status=(200, 404))
|
||||||
|
|
||||||
def test_creator_is_an_admin(shared_zone_test_context):
|
def test_creator_is_an_admin(shared_zone_test_context):
|
||||||
"""
|
"""
|
||||||
@@ -114,8 +144,36 @@ def test_create_group_without_name_or_email(shared_zone_test_context):
|
|||||||
"Missing Group.name",
|
"Missing Group.name",
|
||||||
"Missing Group.email"
|
"Missing Group.email"
|
||||||
))
|
))
|
||||||
|
def test_create_group_with_invalid_email_domain(shared_zone_test_context):
|
||||||
|
"""
|
||||||
|
Tests that creating a group With Invalid email fails
|
||||||
|
"""
|
||||||
|
client = shared_zone_test_context.ok_vinyldns_client
|
||||||
|
|
||||||
|
new_group = {
|
||||||
|
"name": "invalid-email",
|
||||||
|
"email": "test@abc.com",
|
||||||
|
"description": "this is a description",
|
||||||
|
"members": [{"id": "ok"}],
|
||||||
|
"admins": [{"id": "ok"}]
|
||||||
|
}
|
||||||
|
error = client.create_group(new_group, status=400)
|
||||||
|
assert_that(error, is_("Please enter a valid Email ID. Valid domains should end with test.com,dummy.com"))
|
||||||
|
def test_create_group_with_invalid_email(shared_zone_test_context):
|
||||||
|
"""
|
||||||
|
Tests that creating a group With Invalid email fails
|
||||||
|
"""
|
||||||
|
client = shared_zone_test_context.ok_vinyldns_client
|
||||||
|
|
||||||
|
new_group = {
|
||||||
|
"name": "invalid-email",
|
||||||
|
"email": "test.abc.com",
|
||||||
|
"description": "this is a description",
|
||||||
|
"members": [{"id": "ok"}],
|
||||||
|
"admins": [{"id": "ok"}]
|
||||||
|
}
|
||||||
|
error = client.create_group(new_group, status=400)
|
||||||
|
assert_that(error, is_("Please enter a valid Email ID."))
|
||||||
def test_create_group_without_members_or_admins(shared_zone_test_context):
|
def test_create_group_without_members_or_admins(shared_zone_test_context):
|
||||||
"""
|
"""
|
||||||
Tests that creating a group without members or admins fails
|
Tests that creating a group without members or admins fails
|
||||||
|
@@ -127,7 +127,9 @@ vinyldns {
|
|||||||
from = ${?EMAIL_FROM}
|
from = ${?EMAIL_FROM}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
valid-email-config{
|
||||||
|
email-domains = ["test.com","*dummy.com","*ok.com"]
|
||||||
|
}
|
||||||
sns {
|
sns {
|
||||||
class-name = "vinyldns.apadi.notifier.sns.SnsNotifierProvider"
|
class-name = "vinyldns.apadi.notifier.sns.SnsNotifierProvider"
|
||||||
class-name = ${?SNS_CLASS_NAME}
|
class-name = ${?SNS_CLASS_NAME}
|
||||||
|
@@ -29,6 +29,7 @@ import vinyldns.core.domain.auth.AuthPrincipal
|
|||||||
import vinyldns.core.domain.zone.ZoneRepository
|
import vinyldns.core.domain.zone.ZoneRepository
|
||||||
import cats.effect._
|
import cats.effect._
|
||||||
import scalikejdbc.{ConnectionPool, DB}
|
import scalikejdbc.{ConnectionPool, DB}
|
||||||
|
import vinyldns.api.config.ValidEmailConfig
|
||||||
import vinyldns.api.domain.zone.NotAuthorizedError
|
import vinyldns.api.domain.zone.NotAuthorizedError
|
||||||
import vinyldns.core.TestMembershipData._
|
import vinyldns.core.TestMembershipData._
|
||||||
import vinyldns.core.TestZoneData._
|
import vinyldns.core.TestZoneData._
|
||||||
@@ -48,6 +49,8 @@ class MembershipServiceSpec
|
|||||||
private val mockZoneRepo = mock[ZoneRepository]
|
private val mockZoneRepo = mock[ZoneRepository]
|
||||||
private val mockGroupChangeRepo = mock[GroupChangeRepository]
|
private val mockGroupChangeRepo = mock[GroupChangeRepository]
|
||||||
private val mockRecordSetRepo = mock[RecordSetRepository]
|
private val mockRecordSetRepo = mock[RecordSetRepository]
|
||||||
|
private val mockValidEmailConfig = ValidEmailConfig(valid_domains = List("test.com","*dummy.com"))
|
||||||
|
private val mockValidEmailConfigNew = ValidEmailConfig(valid_domains = List())
|
||||||
|
|
||||||
private val backingService = new MembershipService(
|
private val backingService = new MembershipService(
|
||||||
mockGroupRepo,
|
mockGroupRepo,
|
||||||
@@ -55,9 +58,20 @@ class MembershipServiceSpec
|
|||||||
mockMembershipRepo,
|
mockMembershipRepo,
|
||||||
mockZoneRepo,
|
mockZoneRepo,
|
||||||
mockGroupChangeRepo,
|
mockGroupChangeRepo,
|
||||||
mockRecordSetRepo
|
mockRecordSetRepo,
|
||||||
|
mockValidEmailConfig
|
||||||
|
)
|
||||||
|
private val backingServiceNew = new MembershipService(
|
||||||
|
mockGroupRepo,
|
||||||
|
mockUserRepo,
|
||||||
|
mockMembershipRepo,
|
||||||
|
mockZoneRepo,
|
||||||
|
mockGroupChangeRepo,
|
||||||
|
mockRecordSetRepo,
|
||||||
|
mockValidEmailConfigNew
|
||||||
)
|
)
|
||||||
private val underTest = spy(backingService)
|
private val underTest = spy(backingService)
|
||||||
|
private val underTestNew = spy(backingServiceNew)
|
||||||
|
|
||||||
private val okUserInfo: UserInfo = UserInfo(okUser)
|
private val okUserInfo: UserInfo = UserInfo(okUser)
|
||||||
private val dummyUserInfo: UserInfo = UserInfo(dummyUser)
|
private val dummyUserInfo: UserInfo = UserInfo(dummyUser)
|
||||||
@@ -82,7 +96,7 @@ class MembershipServiceSpec
|
|||||||
// the update will remove users 3 and 4, add users 5 and 6, as well as a new admin user 7 and remove user2 as admin
|
// the update will remove users 3 and 4, add users 5 and 6, as well as a new admin user 7 and remove user2 as admin
|
||||||
private val updatedInfo = Group(
|
private val updatedInfo = Group(
|
||||||
name = "new.name",
|
name = "new.name",
|
||||||
email = "new.email",
|
email = "test@test.com",
|
||||||
description = Some("new desc"),
|
description = Some("new desc"),
|
||||||
id = "id",
|
id = "id",
|
||||||
memberIds = Set("user1", "user2", "user5", "user6", "user7"),
|
memberIds = Set("user1", "user2", "user5", "user6", "user7"),
|
||||||
@@ -282,8 +296,162 @@ class MembershipServiceSpec
|
|||||||
verify(mockMembershipRepo, never())
|
verify(mockMembershipRepo, never())
|
||||||
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"return an error if an invalid domain is entered" in {
|
||||||
|
val error = underTest.createGroup(groupInfo.copy(email = "test@ok.com"), okAuth).value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an invalid email is entered" in {
|
||||||
|
val error = underTest.createGroup(groupInfo.copy(email = "test.ok.com"), okAuth).value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an invalid email with * is entered" in {
|
||||||
|
val error = underTest.createGroup(groupInfo.copy(email = "test@*dummy.com"), okAuth).value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"return an error if an email is invalid test case 1" in {
|
||||||
|
val error = underTest.emailValidation(email = "test.ok.com").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if a domain is invalid test case 1" in {
|
||||||
|
val error = underTest.emailValidation(email = "test@ok.com").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an email is invalid test case 2" in {
|
||||||
|
val error = underTest.emailValidation(email = "test@.@.test.com").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an email is invalid test case 3" in {
|
||||||
|
val error = underTest.emailValidation(email = "test@.@@.test.com").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an email is invalid test case 4" in {
|
||||||
|
val error = underTest.emailValidation(email = "@te@st@test.com").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an email is invalid test case 5" in {
|
||||||
|
val error = underTest.emailValidation(email = ".test@test.com").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an email is invalid test case 6" in {
|
||||||
|
val error = underTest.emailValidation(email = "te.....st@test.com").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"return an error if an email is invalid test case 7" in {
|
||||||
|
val error = underTest.emailValidation(email = "test@test.com.").value.unsafeRunSync().swap.toOption.get
|
||||||
|
error shouldBe a[EmailValidationError]
|
||||||
|
}
|
||||||
|
|
||||||
|
"Check whether *dummy.com is a valid email" in {
|
||||||
|
val result = underTest.emailValidation(email = "test@ok.dummy.com").value.unsafeRunSync()
|
||||||
|
result shouldBe Right(())
|
||||||
|
}
|
||||||
|
|
||||||
|
"Check whether test.com is a valid email" in {
|
||||||
|
val result = underTest.emailValidation(email = "test@test.com").value.unsafeRunSync()
|
||||||
|
result shouldBe Right(())
|
||||||
|
}
|
||||||
|
|
||||||
|
"Check whether it is allowing any domain when the config is empty" in {
|
||||||
|
val result = underTestNew.emailValidation(email = "test@abc.com").value.unsafeRunSync()
|
||||||
|
result shouldBe Right(())
|
||||||
|
}
|
||||||
|
|
||||||
|
"Create Group when email has domain *dummy.com" in {
|
||||||
|
doReturn(IO.pure(Some(okUser))).when(mockUserRepo).getUser("ok")
|
||||||
|
doReturn(().toResult).when(underTest).groupValidation(groupInfo)
|
||||||
|
doReturn(().toResult).when(underTest).groupWithSameNameDoesNotExist(groupInfo.name)
|
||||||
|
doReturn(().toResult).when(underTest).usersExist(groupInfo.memberIds)
|
||||||
|
doReturn(IO.pure(okGroup)).when(mockGroupRepo).save(any[DB], any[Group])
|
||||||
|
doReturn(IO.pure(Set(okUser.id)))
|
||||||
|
.when(mockMembershipRepo)
|
||||||
|
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
||||||
|
doReturn(IO.pure(okGroupChange)).when(mockGroupChangeRepo).save(any[DB], any[GroupChange])
|
||||||
|
|
||||||
|
val result = underTest.createGroup(groupInfo.copy(email = "test@ok.dummy.com"), okAuth).value.unsafeRunSync().toOption.get
|
||||||
|
result shouldBe groupInfo.copy(email = "test@ok.dummy.com")
|
||||||
|
|
||||||
|
val groupCaptor = ArgumentCaptor.forClass(classOf[Group])
|
||||||
|
|
||||||
|
verify(mockMembershipRepo, times(2))
|
||||||
|
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
||||||
|
verify(mockGroupRepo).save(any[DB], groupCaptor.capture())
|
||||||
|
|
||||||
|
val savedGroup = groupCaptor.getValue
|
||||||
|
(savedGroup.memberIds should contain).only(okUser.id)
|
||||||
|
(savedGroup.adminUserIds should contain).only(okUser.id)
|
||||||
|
savedGroup.name shouldBe groupInfo.name
|
||||||
|
savedGroup.email shouldBe groupInfo.copy(email = "test@ok.dummy.com").email
|
||||||
|
savedGroup.description shouldBe groupInfo.description
|
||||||
|
}
|
||||||
|
|
||||||
|
"Create Group when email with any domain when config is empty" in {
|
||||||
|
doReturn(IO.pure(Some(okUser))).when(mockUserRepo).getUser("ok")
|
||||||
|
doReturn(().toResult).when(underTestNew).groupValidation(groupInfo)
|
||||||
|
doReturn(().toResult).when(underTestNew).groupWithSameNameDoesNotExist(groupInfo.name)
|
||||||
|
doReturn(().toResult).when(underTestNew).usersExist(groupInfo.memberIds)
|
||||||
|
doReturn(IO.pure(okGroup)).when(mockGroupRepo).save(any[DB], any[Group])
|
||||||
|
doReturn(IO.pure(Set(okUser.id)))
|
||||||
|
.when(mockMembershipRepo)
|
||||||
|
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
||||||
|
doReturn(IO.pure(okGroupChange)).when(mockGroupChangeRepo).save(any[DB], any[GroupChange])
|
||||||
|
|
||||||
|
val result = underTestNew.createGroup(groupInfo.copy(email = "test@abc.com"), okAuth).value.unsafeRunSync().toOption.get
|
||||||
|
result shouldBe groupInfo.copy(email = "test@abc.com")
|
||||||
|
|
||||||
|
val groupCaptor = ArgumentCaptor.forClass(classOf[Group])
|
||||||
|
|
||||||
|
verify(mockMembershipRepo, times(2))
|
||||||
|
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
||||||
|
verify(mockGroupRepo).save(any[DB], groupCaptor.capture())
|
||||||
|
|
||||||
|
val savedGroup = groupCaptor.getValue
|
||||||
|
(savedGroup.memberIds should contain).only(okUser.id)
|
||||||
|
(savedGroup.adminUserIds should contain).only(okUser.id)
|
||||||
|
savedGroup.name shouldBe groupInfo.name
|
||||||
|
savedGroup.email shouldBe groupInfo.copy(email = "test@abc.com").email
|
||||||
|
savedGroup.description shouldBe groupInfo.description
|
||||||
|
}
|
||||||
|
|
||||||
|
"Create Group when email has domain test.com" in {
|
||||||
|
doReturn(IO.pure(Some(okUser))).when(mockUserRepo).getUser("ok")
|
||||||
|
doReturn(().toResult).when(underTest).groupValidation(groupInfo)
|
||||||
|
doReturn(().toResult).when(underTest).groupWithSameNameDoesNotExist(groupInfo.name)
|
||||||
|
doReturn(().toResult).when(underTest).usersExist(groupInfo.memberIds)
|
||||||
|
doReturn(IO.pure(okGroup)).when(mockGroupRepo).save(any[DB], any[Group])
|
||||||
|
doReturn(IO.pure(Set(okUser.id)))
|
||||||
|
.when(mockMembershipRepo)
|
||||||
|
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
||||||
|
doReturn(IO.pure(okGroupChange)).when(mockGroupChangeRepo).save(any[DB], any[GroupChange])
|
||||||
|
|
||||||
|
val result = underTest.createGroup(groupInfo.copy(email = "test@test.com"), okAuth).value.unsafeRunSync().toOption.get
|
||||||
|
result shouldBe groupInfo.copy(email = "test@test.com")
|
||||||
|
|
||||||
|
val groupCaptor = ArgumentCaptor.forClass(classOf[Group])
|
||||||
|
|
||||||
|
verify(mockMembershipRepo, times(2))
|
||||||
|
.saveMembers(any[DB], anyString, any[Set[String]], isAdmin = anyBoolean)
|
||||||
|
verify(mockGroupRepo).save(any[DB], groupCaptor.capture())
|
||||||
|
|
||||||
|
val savedGroup = groupCaptor.getValue
|
||||||
|
(savedGroup.memberIds should contain).only(okUser.id)
|
||||||
|
(savedGroup.adminUserIds should contain).only(okUser.id)
|
||||||
|
savedGroup.name shouldBe groupInfo.name
|
||||||
|
savedGroup.email shouldBe groupInfo.copy(email = "test@test.com").email
|
||||||
|
savedGroup.description shouldBe groupInfo.description
|
||||||
|
}
|
||||||
|
|
||||||
"update an existing group" should {
|
"update an existing group" should {
|
||||||
"save the update and add new members and remove deleted members" in {
|
"save the update and add new members and remove deleted members" in {
|
||||||
doReturn(IO.pure(Some(existingGroup))).when(mockGroupRepo).getGroup(any[String])
|
doReturn(IO.pure(Some(existingGroup))).when(mockGroupRepo).getGroup(any[String])
|
||||||
|
@@ -81,4 +81,8 @@ object Messages {
|
|||||||
|
|
||||||
// Error displayed when group name or email is empty
|
// Error displayed when group name or email is empty
|
||||||
val GroupValidationErrorMsg = "Group name and email cannot be empty."
|
val GroupValidationErrorMsg = "Group name and email cannot be empty."
|
||||||
|
|
||||||
|
val EmailValidationErrorMsg = "Please enter a valid Email ID. Valid domains should end with"
|
||||||
|
|
||||||
|
val InvalidEmailValidationErrorMsg = "Please enter a valid Email ID."
|
||||||
}
|
}
|
||||||
|
@@ -475,6 +475,16 @@ sns {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
### Email Domain Configuration
|
||||||
|
This configuration setting determines the valid domains which are
|
||||||
|
allowed in the email fields. `*dummy.com` means it will allow any
|
||||||
|
subdomain within dummy.com like apac.dummy.com. If email-domains is
|
||||||
|
left empty then it will accept any domain name.
|
||||||
|
```yaml
|
||||||
|
valid-email-config {
|
||||||
|
email-domains = ["test.com","*dummy.com"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Batch Manual Review Enabled <a id="manual-review" />
|
### Batch Manual Review Enabled <a id="manual-review" />
|
||||||
|
|
||||||
@@ -752,6 +762,11 @@ dotted-hosts = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Valid Email Domains
|
||||||
|
valid-email-config {
|
||||||
|
email-domains = ["test.com","*dummy.com"]
|
||||||
|
}
|
||||||
|
|
||||||
sns {
|
sns {
|
||||||
# Path to notifier provider implementation
|
# Path to notifier provider implementation
|
||||||
class-name = "vinyldns.api.notifier.sns.SnsNotifierProvider"
|
class-name = "vinyldns.api.notifier.sns.SnsNotifierProvider"
|
||||||
|
Reference in New Issue
Block a user