#1063 allow acls to match custom_fields
This commit is contained in:
@@ -207,17 +207,15 @@ sub check_acl {
|
|||||||
my $found = false;
|
my $found = false;
|
||||||
|
|
||||||
ITEM: foreach my $item (@$things) {
|
ITEM: foreach my $item (@$things) {
|
||||||
if (blessed $item) {
|
if (blessed $item and $item->can('tags')) {
|
||||||
if ($neg xor ($item->can('tags') and ref [] eq ref $item->tags
|
if ($neg xor scalar grep {$_ eq $tag} @{ $item->tags || [] }) {
|
||||||
and scalar grep {$_ eq $tag} @{ $item->tags })) {
|
|
||||||
return true if not $all;
|
return true if not $all;
|
||||||
$found = true;
|
$found = true;
|
||||||
last ITEM;
|
last ITEM;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
elsif (ref {} eq ref $item) {
|
elsif (ref {} eq ref $item and exists $item->{'tags'}) {
|
||||||
if ($neg xor (exists $item->{'tags'} and ref [] eq ref $item->{'tags'}
|
if ($neg xor scalar grep {$_ eq $tag} @{ $item->{'tags'} || [] }) {
|
||||||
and scalar grep {$_ eq $tag} @{ $item->{'tags'} })) {
|
|
||||||
return true if not $all;
|
return true if not $all;
|
||||||
$found = true;
|
$found = true;
|
||||||
last ITEM;
|
last ITEM;
|
||||||
@@ -229,6 +227,58 @@ sub check_acl {
|
|||||||
next RULE;
|
next RULE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# cf:customfield:val
|
||||||
|
if ($rule =~ m/^cf:([^:]+):(.*)$/) {
|
||||||
|
my $prop = $1;
|
||||||
|
my $match = $2 || '';
|
||||||
|
my $found = false;
|
||||||
|
|
||||||
|
# custom field exists, undef is allowed to match empty string
|
||||||
|
ITEM: foreach my $item (@$things) {
|
||||||
|
my $cf = {};
|
||||||
|
if (blessed $item and $item->can('custom_fields')) {
|
||||||
|
$cf = from_json ($item->custom_fields || '{}');
|
||||||
|
}
|
||||||
|
elsif (ref {} eq ref $item and exists $item->{'custom_fields'}) {
|
||||||
|
$cf = from_json ($item->{'custom_fields'} || '{}');
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($neg xor (ref {} eq ref $cf and exists $cf->{$prop} and
|
||||||
|
((!defined $cf->{$prop} and $match eq q{})
|
||||||
|
or
|
||||||
|
(defined $cf->{$prop} and ref $cf->{$prop} eq q{} and $cf->{$prop} =~ m/^$match$/)) )) {
|
||||||
|
return true if not $all;
|
||||||
|
$found = true;
|
||||||
|
last ITEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# missing custom field matches empty string
|
||||||
|
# (which is done in a second pass to allow all @$things to be
|
||||||
|
# inspected for existing custom fields)
|
||||||
|
ITEM: foreach my $item (@$things) {
|
||||||
|
last ITEM if $found;
|
||||||
|
|
||||||
|
my $cf = {};
|
||||||
|
if (blessed $item and $item->can('custom_fields')) {
|
||||||
|
$cf = from_json ($item->custom_fields || '{}');
|
||||||
|
}
|
||||||
|
elsif (ref {} eq ref $item and exists $item->{'custom_fields'}) {
|
||||||
|
$cf = from_json ($item->{'custom_fields'} || '{}');
|
||||||
|
}
|
||||||
|
|
||||||
|
# empty or missing property
|
||||||
|
if ($neg xor ($match eq q{} and ! exists $cf->{$prop})) {
|
||||||
|
return true if not $all;
|
||||||
|
$found = true;
|
||||||
|
last ITEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false if $all and not $found;
|
||||||
|
next RULE;
|
||||||
|
}
|
||||||
|
|
||||||
# prop:val
|
# prop:val
|
||||||
# with a check that prop isn't just the first part of a v6 addr
|
# with a check that prop isn't just the first part of a v6 addr
|
||||||
if ($rule =~ m/^([^:]+):(.*)$/ and $1 !~ m/^[a-f0-9]+$/i) {
|
if ($rule =~ m/^([^:]+):(.*)$/ and $1 !~ m/^[a-f0-9]+$/i) {
|
||||||
|
|||||||
@@ -151,11 +151,13 @@ my $dp = App::Netdisco::DB->resultset('DevicePort')->new_result({
|
|||||||
port => 'TenGigabitEthernet1/10',
|
port => 'TenGigabitEthernet1/10',
|
||||||
type => 'l3ipvlan',
|
type => 'l3ipvlan',
|
||||||
tags => [qw/ foo bar baz /],
|
tags => [qw/ foo bar baz /],
|
||||||
|
custom_fields => '{"baz": "quux"}',
|
||||||
});
|
});
|
||||||
|
|
||||||
my $d = App::Netdisco::DB->resultset('Device')->new_result({
|
my $d = App::Netdisco::DB->resultset('Device')->new_result({
|
||||||
ip => '127.0.0.1',
|
ip => '127.0.0.1',
|
||||||
tags => [qw/ quux /],
|
tags => [qw/ quux /],
|
||||||
|
custom_fields => '{"foo": "bar"}',
|
||||||
});
|
});
|
||||||
|
|
||||||
# device properties
|
# device properties
|
||||||
@@ -221,4 +223,17 @@ ok(acl_matches([$dip2c, $dpc], ['tag:foo']), 'hh tag exists');
|
|||||||
ok(acl_matches([$dip2c, $dpc], ['!tag:quux']), 'hh tag not existing');
|
ok(acl_matches([$dip2c, $dpc], ['!tag:quux']), 'hh tag not existing');
|
||||||
is(acl_matches([$dpc], ['tag:quux']), 0, 'hh tag does not exist');
|
is(acl_matches([$dpc], ['tag:quux']), 0, 'hh tag does not exist');
|
||||||
|
|
||||||
|
# custom fields
|
||||||
|
|
||||||
|
ok(acl_matches([$dip2, $dp], ['cf:baz:quux']), '2obj cf matches');
|
||||||
|
ok(acl_matches([$dip2, $dp], ['!cf:baa:qd']), '2obj cf does not match');
|
||||||
|
is(acl_matches([$dp], ['cf:baa:quux']), 0, '1obh cf does not exist');
|
||||||
|
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['cf:baz:quux']), 'hh cf matches');
|
||||||
|
ok(acl_matches([$dip2c, $dpc], ['!cf:baa:qd']), 'hh cf does not match');
|
||||||
|
is(acl_matches([$dpc], ['cf:baa:quux']), 0, 'hh cf does not exist');
|
||||||
|
|
||||||
|
ok(acl_matches([$d, $dp], ['op:and','cf:foo:bar','cf:baz:quux']), '2obj cf two rules match');
|
||||||
|
is(acl_matches([$d, $dp], ['op:and','cf:foo:bar','cf:baa:qd']), 0, '2obj cf two rules do not match');
|
||||||
|
|
||||||
done_testing;
|
done_testing;
|
||||||
|
|||||||
Reference in New Issue
Block a user