mirror of
https://github.com/VinylDNS/vinyldns
synced 2025-08-22 10:10:12 +00:00
Record type filter for shared zones (#479)
This commit is contained in:
parent
c5c5bccfa9
commit
593fe45b52
@ -188,6 +188,9 @@ vinyldns {
|
||||
"fd69:27cc:fe91:0:0:0:ffff:0"
|
||||
]
|
||||
}
|
||||
|
||||
# types of unowned records that users can access in shared zones
|
||||
shared-approved-types = ["A", "AAAA", "CNAME", "PTR"]
|
||||
}
|
||||
|
||||
akka {
|
||||
|
@ -1874,28 +1874,44 @@ def test_create_in_shared_zone_without_owner_group_id_succeeds(shared_zone_test_
|
||||
delete_result = dummy_client.delete_recordset(create_rs['zoneId'], create_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
|
||||
def test_create_in_shared_zone_by_unassociated_user_succeeds(shared_zone_test_context):
|
||||
def test_create_in_shared_zone_by_unassociated_user_succeeds_if_record_type_is_approved(shared_zone_test_context):
|
||||
"""
|
||||
Test that creating a record in a shared zone by an unassociated user succeeds
|
||||
Test that creating a record in a shared zone by a user with no write permissions succeeds if the record type is approved
|
||||
"""
|
||||
|
||||
dummy_client = shared_zone_test_context.dummy_vinyldns_client
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
client = shared_zone_test_context.dummy_vinyldns_client
|
||||
zone = shared_zone_test_context.shared_zone
|
||||
group = shared_zone_test_context.dummy_group
|
||||
|
||||
record_json = get_recordset_json(zone, 'test_shared_approved_record_type', 'A', [{'address': '1.1.1.1'}])
|
||||
record_json['ownerGroupId'] = group['id']
|
||||
|
||||
create_rs = None
|
||||
|
||||
record_json = get_recordset_json(zone, 'test_shared_bad_user', 'A', [{'address': '1.1.1.1'}], ownergroup_id=group['id'])
|
||||
|
||||
try:
|
||||
create_response = dummy_client.create_recordset(record_json, status=202)
|
||||
create_rs = shared_client.wait_until_recordset_change_status(create_response, 'Complete')['recordSet']
|
||||
create_response = client.create_recordset(record_json, status=202)
|
||||
create_rs = client.wait_until_recordset_change_status(create_response, 'Complete')['recordSet']
|
||||
assert_that(create_rs['ownerGroupId'], is_(group['id']))
|
||||
|
||||
finally:
|
||||
if create_rs:
|
||||
delete_result = dummy_client.delete_recordset(create_rs['zoneId'], create_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
delete_result = client.delete_recordset(zone['id'], create_rs['id'], status=202)
|
||||
client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
|
||||
|
||||
def test_create_in_shared_zone_by_unassociated_user_fails_if_record_type_is_not_approved(shared_zone_test_context):
|
||||
"""
|
||||
Test that creating a record in a shared zone by a user with no write permissions fails if the record type is not approved
|
||||
"""
|
||||
|
||||
client = shared_zone_test_context.dummy_vinyldns_client
|
||||
zone = shared_zone_test_context.shared_zone
|
||||
group = shared_zone_test_context.dummy_group
|
||||
|
||||
record_json = get_recordset_json(zone, 'test_shared_not_approved_record_type', 'MX', [{'preference': 3, 'exchange': 'mx'}])
|
||||
record_json['ownerGroupId'] = group['id']
|
||||
error = client.create_recordset(record_json, status=403)
|
||||
assert_that(error, is_('User dummy does not have access to create test-shared-not-approved-record-type.shared.'))
|
||||
|
||||
def test_create_with_not_found_owner_group_fails(shared_zone_test_context):
|
||||
"""
|
||||
|
@ -662,53 +662,6 @@ def test_no_delete_access_non_test_zone(shared_zone_test_context):
|
||||
|
||||
client.delete_recordset(zone_id, record_delete['id'], status=403)
|
||||
|
||||
def test_delete_for_user_not_in_record_owner_group_in_shared_zone_fails(shared_zone_test_context):
|
||||
"""
|
||||
Test that a user cannot delete a record in a shared zone if not part of record owner group
|
||||
"""
|
||||
|
||||
dummy_client = shared_zone_test_context.dummy_vinyldns_client
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
shared_zone = shared_zone_test_context.shared_zone
|
||||
result_rs = None
|
||||
|
||||
record_json = get_recordset_json(shared_zone, 'test_shared_del_nonog', 'A', [{'address': '1.1.1.1'}], ownergroup_id = shared_zone_test_context.shared_record_group['id'])
|
||||
|
||||
try:
|
||||
create_rs = shared_client.create_recordset(record_json, status=202)
|
||||
result_rs = shared_client.wait_until_recordset_change_status(create_rs, 'Complete')['recordSet']
|
||||
|
||||
error = dummy_client.delete_recordset(shared_zone['id'], result_rs['id'], status=403)
|
||||
assert_that(error, is_('User dummy does not have access to delete test-shared-del-nonog.shared.'))
|
||||
|
||||
finally:
|
||||
if result_rs:
|
||||
delete_rs = shared_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_rs, 'Complete')
|
||||
|
||||
def test_delete_for_user_in_record_owner_group_in_non_shared_zone_fails(shared_zone_test_context):
|
||||
"""
|
||||
Test that a user in record owner group cannot delete a record in a non-shared zone
|
||||
"""
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
ok_zone = shared_zone_test_context.ok_zone
|
||||
result_rs = None
|
||||
|
||||
record_json = get_recordset_json(ok_zone, 'test_non_shared_del_og', 'A', [{'address': '1.1.1.1'}], ownergroup_id = shared_zone_test_context.shared_record_group['id'])
|
||||
|
||||
try:
|
||||
create_rs = ok_client.create_recordset(record_json, status=202)
|
||||
result_rs = ok_client.wait_until_recordset_change_status(create_rs, 'Complete')['recordSet']
|
||||
|
||||
error = shared_client.delete_recordset(ok_zone['id'], result_rs['id'], status=403)
|
||||
assert_that(error, is_('User sharedZoneUser does not have access to delete test-non-shared-del-og.ok.'))
|
||||
|
||||
finally:
|
||||
if result_rs:
|
||||
delete_rs = ok_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
ok_client.wait_until_recordset_change_status(delete_rs, 'Complete')
|
||||
|
||||
def test_delete_for_user_in_record_owner_group_in_shared_zone_succeeds(shared_zone_test_context):
|
||||
"""
|
||||
Test that a user in record owner group can delete a record in a shared zone
|
||||
@ -740,3 +693,90 @@ def test_delete_for_zone_admin_in_shared_zone_succeeds(shared_zone_test_context)
|
||||
|
||||
delete_rs = shared_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_rs, 'Complete')
|
||||
|
||||
def test_delete_for_unowned_record_with_approved_record_type_in_shared_zone_succeeds(shared_zone_test_context):
|
||||
"""
|
||||
Test that a user not associated with a unowned record can delete it in a shared zone
|
||||
"""
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
shared_zone = shared_zone_test_context.shared_zone
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
|
||||
record_json = get_recordset_json(shared_zone, 'test_shared_approved_record_type', 'A', [{'address': '1.1.1.1'}])
|
||||
|
||||
create_rs = shared_client.create_recordset(record_json, status=202)
|
||||
result_rs = shared_client.wait_until_recordset_change_status(create_rs, 'Complete')['recordSet']
|
||||
|
||||
delete_rs = ok_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
ok_client.wait_until_recordset_change_status(delete_rs, 'Complete')
|
||||
|
||||
def test_delete_for_user_not_in_record_owner_group_in_shared_zone_fails(shared_zone_test_context):
|
||||
"""
|
||||
Test that a user cannot delete a record in a shared zone if not part of record owner group
|
||||
"""
|
||||
|
||||
dummy_client = shared_zone_test_context.dummy_vinyldns_client
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
shared_zone = shared_zone_test_context.shared_zone
|
||||
result_rs = None
|
||||
|
||||
record_json = get_recordset_json(shared_zone, 'test_shared_del_nonog', 'A', [{'address': '1.1.1.1'}], ownergroup_id = shared_zone_test_context.shared_record_group['id'])
|
||||
|
||||
try:
|
||||
create_rs = shared_client.create_recordset(record_json, status=202)
|
||||
result_rs = shared_client.wait_until_recordset_change_status(create_rs, 'Complete')['recordSet']
|
||||
|
||||
error = dummy_client.delete_recordset(shared_zone['id'], result_rs['id'], status=403)
|
||||
assert_that(error, is_('User dummy does not have access to delete test-shared-del-nonog.shared.'))
|
||||
|
||||
finally:
|
||||
if result_rs:
|
||||
delete_rs = shared_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_rs, 'Complete')
|
||||
|
||||
def test_delete_for_user_not_in_unowned_record_in_shared_zone_fails_if_record_type_is_not_approved(shared_zone_test_context):
|
||||
"""
|
||||
Test that a user cannot delete a record in a shared zone if the record is unowned and the record type is not approved
|
||||
"""
|
||||
|
||||
dummy_client = shared_zone_test_context.dummy_vinyldns_client
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
shared_zone = shared_zone_test_context.shared_zone
|
||||
result_rs = None
|
||||
|
||||
record_json = get_recordset_json(shared_zone, 'test_shared_del_not_approved_record_type', 'MX', [{'preference': 3, 'exchange': 'mx'}])
|
||||
|
||||
try:
|
||||
create_rs = shared_client.create_recordset(record_json, status=202)
|
||||
result_rs = shared_client.wait_until_recordset_change_status(create_rs, 'Complete')['recordSet']
|
||||
|
||||
error = dummy_client.delete_recordset(shared_zone['id'], result_rs['id'], status=403)
|
||||
assert_that(error, is_('User dummy does not have access to delete test-shared-del-not-approved-record-type.shared.'))
|
||||
|
||||
finally:
|
||||
if result_rs:
|
||||
delete_rs = shared_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_rs, 'Complete')
|
||||
|
||||
def test_delete_for_user_in_record_owner_group_in_non_shared_zone_fails(shared_zone_test_context):
|
||||
"""
|
||||
Test that a user in record owner group cannot delete a record in a non-shared zone
|
||||
"""
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
ok_zone = shared_zone_test_context.ok_zone
|
||||
result_rs = None
|
||||
|
||||
record_json = get_recordset_json(ok_zone, 'test_non_shared_del_og', 'A', [{'address': '1.1.1.1'}], ownergroup_id = shared_zone_test_context.shared_record_group['id'])
|
||||
|
||||
try:
|
||||
create_rs = ok_client.create_recordset(record_json, status=202)
|
||||
result_rs = ok_client.wait_until_recordset_change_status(create_rs, 'Complete')['recordSet']
|
||||
|
||||
error = shared_client.delete_recordset(ok_zone['id'], result_rs['id'], status=403)
|
||||
assert_that(error, is_('User sharedZoneUser does not have access to delete test-non-shared-del-og.ok.'))
|
||||
|
||||
finally:
|
||||
if result_rs:
|
||||
delete_rs = ok_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
ok_client.wait_until_recordset_change_status(delete_rs, 'Complete')
|
||||
|
@ -158,22 +158,47 @@ def test_get_recordset_from_shared_zone(shared_zone_test_context):
|
||||
delete_result = client.delete_recordset(retrieved_rs['zoneId'], retrieved_rs['id'], status=202)
|
||||
client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
|
||||
def test_get_unowned_recordset_from_shared_zone(shared_zone_test_context):
|
||||
def test_get_unowned_recordset_from_shared_zone_succeeds_if_record_type_approved(shared_zone_test_context):
|
||||
"""
|
||||
Test getting an unowned recordset with no admin rights succeeds
|
||||
Test getting an unowned recordset with no admin rights succeeds if the record type is approved
|
||||
"""
|
||||
client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
result_rs = None
|
||||
try:
|
||||
new_rs = get_recordset_json(shared_zone_test_context.shared_zone,
|
||||
"test_get_unowned_recordset_approved_type", "A", [{"address": "1.2.3.4"}])
|
||||
|
||||
result = client.create_recordset(new_rs, status=202)
|
||||
result_rs = client.wait_until_recordset_change_status(result, 'Complete')['recordSet']
|
||||
|
||||
# Get the recordset we just made and verify
|
||||
retrieved = ok_client.get_recordset(result_rs['zoneId'], result_rs['id'], status=200)
|
||||
retrieved_rs = retrieved['recordSet']
|
||||
verify_recordset(retrieved_rs, new_rs)
|
||||
|
||||
finally:
|
||||
if result_rs:
|
||||
delete_result = ok_client.delete_recordset(result_rs['zoneId'], result_rs['id'], status=202)
|
||||
ok_client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
|
||||
def test_get_unowned_recordset_from_shared_zone_fails_if_record_type_not_approved(shared_zone_test_context):
|
||||
"""
|
||||
Test getting an unowned recordset with no admin rights fails if the record type is not approved
|
||||
"""
|
||||
client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
result_rs = None
|
||||
try:
|
||||
new_rs = get_recordset_json(shared_zone_test_context.shared_zone,
|
||||
"test_get_unowned_recordset", "TXT", [{'text':'should-not-work'}])
|
||||
"test_get_unowned_recordset", "MX", [{'preference': 3, 'exchange': 'mx'}])
|
||||
|
||||
result = client.create_recordset(new_rs, status=202)
|
||||
result_rs = client.wait_until_recordset_change_status(result, 'Complete')['recordSet']
|
||||
|
||||
# Get the recordset we just made and verify
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
ok_client.get_recordset(result_rs['zoneId'], result_rs['id'], status=200)
|
||||
error = ok_client.get_recordset(result_rs['zoneId'], result_rs['id'], status=403)
|
||||
assert_that(error, is_("User ok does not have access to view test-get-unowned-recordset.shared."))
|
||||
|
||||
finally:
|
||||
if result_rs:
|
||||
|
@ -2032,11 +2032,11 @@ def test_update_owner_group_from_user_in_record_owner_group_for_shared_zone_pass
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
shared_record_group = shared_zone_test_context.shared_record_group
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
zone = shared_zone_test_context.shared_zone
|
||||
shared_zone = shared_zone_test_context.shared_zone
|
||||
update_rs = None
|
||||
|
||||
try:
|
||||
record_json = get_recordset_json(zone, 'test_shared_success', 'A', [{'address': '1.1.1.1'}])
|
||||
record_json = get_recordset_json(shared_zone, 'test_shared_success', 'A', [{'address': '1.1.1.1'}])
|
||||
record_json['ownerGroupId'] = shared_record_group['id']
|
||||
create_response = shared_client.create_recordset(record_json, status=202)
|
||||
update = shared_client.wait_until_recordset_change_status(create_response, 'Complete')['recordSet']
|
||||
@ -2051,7 +2051,7 @@ def test_update_owner_group_from_user_in_record_owner_group_for_shared_zone_pass
|
||||
|
||||
finally:
|
||||
if update_rs:
|
||||
delete_result = shared_client.delete_recordset(zone['id'], update_rs['id'], status=202)
|
||||
delete_result = shared_client.delete_recordset(shared_zone['id'], update_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
|
||||
|
||||
@ -2084,10 +2084,35 @@ def test_update_owner_group_from_admin_in_shared_zone_passes(shared_zone_test_co
|
||||
delete_result = shared_client.delete_recordset(zone['id'], update_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
|
||||
|
||||
def test_update_from_unassociated_user_in_shared_zone_succeeds(shared_zone_test_context):
|
||||
def test_update_from_unassociated_user_in_shared_zone_passes_when_record_type_is_approved(shared_zone_test_context):
|
||||
"""
|
||||
Test that an unassociated user updating record without existing owner group ID in shared zone succeeds
|
||||
Test that updating with a user that does not have write access succeeds in a shared zone if the record type is approved
|
||||
"""
|
||||
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
shared_client = shared_zone_test_context.shared_zone_vinyldns_client
|
||||
zone = shared_zone_test_context.shared_zone
|
||||
update_rs = None
|
||||
|
||||
try:
|
||||
record_json = get_recordset_json(zone, 'test_shared_approved_record_type', 'A', [{'address': '1.1.1.1'}])
|
||||
create_response = shared_client.create_recordset(record_json, status=202)
|
||||
create_rs = shared_client.wait_until_recordset_change_status(create_response, 'Complete')['recordSet']
|
||||
assert_that(create_rs, is_not(has_key('ownerGroupId')))
|
||||
|
||||
update = create_rs
|
||||
update['ttl'] = update['ttl'] + 100
|
||||
update_response = ok_client.update_recordset(update, status=202)
|
||||
update_rs = shared_client.wait_until_recordset_change_status(update_response, 'Complete')['recordSet']
|
||||
|
||||
finally:
|
||||
if update_rs:
|
||||
delete_result = shared_client.delete_recordset(zone['id'], update_rs['id'], status=202)
|
||||
shared_client.wait_until_recordset_change_status(delete_result, 'Complete')
|
||||
|
||||
def test_update_from_unassociated_user_in_shared_zone_fails(shared_zone_test_context):
|
||||
"""
|
||||
Test that updating with a user that does not have write access fails in a shared zone
|
||||
"""
|
||||
|
||||
ok_client = shared_zone_test_context.ok_vinyldns_client
|
||||
@ -2096,16 +2121,15 @@ def test_update_from_unassociated_user_in_shared_zone_succeeds(shared_zone_test_
|
||||
create_rs = None
|
||||
|
||||
try:
|
||||
record_json = get_recordset_json(zone, 'test_shared_success', 'A', [{'address': '1.1.1.1'}])
|
||||
record_json = get_recordset_json(zone, 'test_shared_unapproved_record_type', 'MX', [{'preference': 3, 'exchange': 'mx'}])
|
||||
create_response = shared_client.create_recordset(record_json, status=202)
|
||||
create_rs = shared_client.wait_until_recordset_change_status(create_response, 'Complete')['recordSet']
|
||||
assert_that(create_rs, is_not(has_key('ownerGroupId')))
|
||||
|
||||
update = create_rs
|
||||
update['ttl'] = update['ttl'] + 100
|
||||
update_response = ok_client.update_recordset(update, status=202)
|
||||
update_rs = shared_client.wait_until_recordset_change_status(update_response, 'Complete')
|
||||
assert_that(update_rs, is_not(has_key('ownerGroupId')))
|
||||
error = ok_client.update_recordset(update, status=403)
|
||||
assert_that(error, is_('User ok does not have access to update test-shared-unapproved-record-type.shared.'))
|
||||
|
||||
finally:
|
||||
if create_rs:
|
||||
@ -2127,7 +2151,7 @@ def test_update_from_acl_for_shared_zone_passes(shared_zone_test_context):
|
||||
try:
|
||||
add_shared_zone_acl_rules(shared_zone_test_context, [acl_rule])
|
||||
|
||||
record_json = get_recordset_json(zone, 'test_shared_success', 'A', [{'address': '1.1.1.1'}])
|
||||
record_json = get_recordset_json(zone, 'test_shared_acl', 'A', [{'address': '1.1.1.1'}])
|
||||
create_response = shared_client.create_recordset(record_json, status=202)
|
||||
update = shared_client.wait_until_recordset_change_status(create_response, 'Complete')['recordSet']
|
||||
assert_that(update, is_not(has_key('ownerGroupId')))
|
||||
|
@ -53,6 +53,8 @@ vinyldns {
|
||||
]
|
||||
}
|
||||
|
||||
# types of unowned records that users can access in shared zones
|
||||
shared-approved-types = ["A", "AAAA", "CNAME", "PTR"]
|
||||
|
||||
dynamodb.repositories {
|
||||
record-set {
|
||||
|
@ -116,4 +116,7 @@ vinyldns {
|
||||
"fd69:27cc:fe91:0:0:0:ffff:0"
|
||||
]
|
||||
}
|
||||
|
||||
# types of unowned records that users can access in shared zones
|
||||
shared-approved-types = ["A", "AAAA", "CNAME", "PTR"]
|
||||
}
|
||||
|
@ -23,6 +23,9 @@ import com.typesafe.config.{Config, ConfigFactory}
|
||||
import pureconfig.module.catseffect.loadConfigF
|
||||
import vinyldns.api.crypto.Crypto
|
||||
import com.comcast.ip4s._
|
||||
import net.ceedubs.ficus.Ficus._
|
||||
import net.ceedubs.ficus.readers.EnumerationReader._
|
||||
import vinyldns.core.domain.record.RecordType
|
||||
|
||||
import scala.collection.JavaConverters._
|
||||
import scala.util.matching.Regex
|
||||
@ -63,6 +66,9 @@ object VinylDNSConfig {
|
||||
lazy val highValueIpList: List[IpAddress] =
|
||||
getOptionalStringList("high-value-domains.ip-list").flatMap(ip => IpAddress(ip))
|
||||
|
||||
lazy val sharedApprovedTypes: Set[RecordType.Value] =
|
||||
vinyldnsConfig.as[Option[Set[RecordType.Value]]]("shared-approved-types").getOrElse(Set())
|
||||
|
||||
lazy val defaultZoneConnection: ZoneConnection = {
|
||||
val connectionConfig = VinylDNSConfig.vinyldnsConfig.getConfig("defaultZoneConnection")
|
||||
val name = connectionConfig.getString("name")
|
||||
|
@ -17,6 +17,7 @@
|
||||
package vinyldns.api.domain
|
||||
|
||||
import vinyldns.api.Interfaces.ensuring
|
||||
import vinyldns.api.VinylDNSConfig
|
||||
import vinyldns.api.domain.zone._
|
||||
import vinyldns.core.domain.auth.AuthPrincipal
|
||||
import vinyldns.core.domain.record.RecordType
|
||||
@ -184,11 +185,18 @@ object AccessValidations extends AccessValidationAlgebra {
|
||||
case testUser if testUser.isTestUser && !zone.isTest => AccessLevel.NoAccess
|
||||
case admin if admin.canEditAll || admin.isGroupMember(zone.adminGroupId) =>
|
||||
AccessLevel.Delete
|
||||
case recordOwner if zone.shared && recordOwnerGroupId.forall(recordOwner.isGroupMember) =>
|
||||
case recordOwner if zone.shared && sharedRecordAccess(recordOwner, recordType, recordOwnerGroupId) =>
|
||||
AccessLevel.Delete
|
||||
case supportUser if supportUser.canReadAll =>
|
||||
val aclAccess = getAccessFromAcl(auth, recordName, recordType, zone)
|
||||
if (aclAccess == AccessLevel.NoAccess) AccessLevel.Read else aclAccess
|
||||
case _ => getAccessFromAcl(auth, recordName, recordType, zone)
|
||||
}
|
||||
|
||||
def sharedRecordAccess(
|
||||
auth: AuthPrincipal,
|
||||
recordType: RecordType,
|
||||
recordOwnerGroupId: Option[String]): Boolean =
|
||||
recordOwnerGroupId.exists(auth.isGroupMember) ||
|
||||
(recordOwnerGroupId.isEmpty && VinylDNSConfig.sharedApprovedTypes.contains(recordType))
|
||||
}
|
||||
|
@ -37,6 +37,9 @@ vinyldns {
|
||||
]
|
||||
}
|
||||
|
||||
# types of unowned records that users can access in shared zones
|
||||
shared-approved-types = ["A", "AAAA", "CNAME", "PTR"]
|
||||
|
||||
# used for testing only
|
||||
string-list-test = ["test"]
|
||||
|
||||
|
@ -490,18 +490,28 @@ class AccessValidationsSpec
|
||||
result shouldBe AccessLevel.Delete
|
||||
}
|
||||
|
||||
"return AccessLevel.Delete if the record is unowned and the zone is shared" in {
|
||||
val recordOwnerAuth = AuthPrincipal(dummyUser.copy(isSupport = true), Seq())
|
||||
"return AccessLevel.Delete if the zone is shared and the record is unowned and an approved record type" in {
|
||||
val result =
|
||||
accessValidationTest.getAccessLevel(
|
||||
recordOwnerAuth,
|
||||
okAuth,
|
||||
sharedZoneRecordNoOwnerGroup.name,
|
||||
sharedZoneRecordNoOwnerGroup.typ,
|
||||
RecordType.AAAA,
|
||||
sharedZone,
|
||||
sharedZoneRecordNoOwnerGroup.ownerGroupId)
|
||||
None)
|
||||
result shouldBe AccessLevel.Delete
|
||||
}
|
||||
|
||||
"return AccessLevel.NoAccess if the zone is shared and the record is unowned but not an approved record type" in {
|
||||
val result =
|
||||
accessValidationTest.getAccessLevel(
|
||||
okAuth,
|
||||
sharedZoneRecordNotApprovedRecordType.name,
|
||||
RecordType.MX,
|
||||
sharedZone,
|
||||
None)
|
||||
result shouldBe AccessLevel.NoAccess
|
||||
}
|
||||
|
||||
"return the result of getAccessLevel if the user is a record owner but zone is not shared" in {
|
||||
val result =
|
||||
accessValidationTest.getAccessLevel(
|
||||
|
@ -654,17 +654,32 @@ class RecordSetServiceSpec
|
||||
result shouldBe a[NotAuthorizedError]
|
||||
}
|
||||
|
||||
"fail when the account is not authorized for the record" in {
|
||||
doReturn(IO.pure(Some(sharedZoneRecordNotFoundOwnerGroup)))
|
||||
"return the unowned record in a shared zone when the record has an approved record type" in {
|
||||
doReturn(IO.pure(Some(sharedZoneRecordNoOwnerGroup)))
|
||||
.when(mockRecordRepo)
|
||||
.getRecordSet(sharedZone.id, sharedZoneRecordNotFoundOwnerGroup.id)
|
||||
|
||||
doReturn(IO.pure(None)).when(mockGroupRepo).getGroup(any[String])
|
||||
|
||||
val expectedRecordSetInfo = RecordSetInfo(sharedZoneRecordNoOwnerGroup, None)
|
||||
|
||||
val result: RecordSetInfo =
|
||||
rightResultOf(
|
||||
underTest.getRecordSet(sharedZoneRecordNoOwnerGroup.id, sharedZone.id, sharedAuth).value)
|
||||
result shouldBe expectedRecordSetInfo
|
||||
}
|
||||
|
||||
"fail when the unowned record in a shared zone is not an approved record type and user is unassociated with it" in {
|
||||
doReturn(IO.pure(Some(sharedZoneRecordNotApprovedRecordType)))
|
||||
.when(mockRecordRepo)
|
||||
.getRecordSet(sharedZone.id, sharedZoneRecordNotApprovedRecordType.id)
|
||||
|
||||
doReturn(IO.pure(None)).when(mockGroupRepo).getGroup(any[String])
|
||||
|
||||
val result =
|
||||
leftResultOf(
|
||||
underTest
|
||||
.getRecordSet(sharedZoneRecordNotFoundOwnerGroup.id, sharedZone.id, okAuth)
|
||||
.getRecordSet(sharedZoneRecordNotApprovedRecordType.id, sharedZone.id, okAuth)
|
||||
.value)
|
||||
result shouldBe a[NotAuthorizedError]
|
||||
}
|
||||
|
@ -183,6 +183,17 @@ object TestRecordSetData {
|
||||
val sharedZoneRecordNotFoundOwnerGroup: RecordSet =
|
||||
sharedZoneRecord.copy(name = "records", ownerGroupId = Some("not-in-backend"))
|
||||
|
||||
val sharedZoneRecordNotApprovedRecordType: RecordSet =
|
||||
RecordSet(
|
||||
sharedZone.id,
|
||||
"mxsharedrecord",
|
||||
RecordType.MX,
|
||||
200,
|
||||
RecordSetStatus.Pending,
|
||||
DateTime.now,
|
||||
None,
|
||||
List(MXData(3, "mx")))
|
||||
|
||||
/* RECORDSET CHANGES */
|
||||
|
||||
def makeTestAddChange(
|
||||
|
1
modules/portal/.gitignore
vendored
1
modules/portal/.gitignore
vendored
@ -6,6 +6,7 @@ bower_components/
|
||||
node_modules/
|
||||
public/javascripts/
|
||||
public/stylesheets/
|
||||
public/test_frameworks/
|
||||
public/custom/views.vinyl.js
|
||||
package-lock.json
|
||||
release.version
|
||||
|
@ -48,7 +48,8 @@ object Dependencies {
|
||||
"org.typelevel" %% "cats-effect" % catsEffectV,
|
||||
"com.47deg" %% "github4s" % "0.18.6",
|
||||
"com.comcast" %% "ip4s-core" % ip4sV,
|
||||
"com.comcast" %% "ip4s-cats" % ip4sV
|
||||
"com.comcast" %% "ip4s-cats" % ip4sV,
|
||||
"com.iheart" %% "ficus" % "1.4.3"
|
||||
)
|
||||
|
||||
lazy val coreDependencies = Seq(
|
||||
|
Loading…
x
Reference in New Issue
Block a user