mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2024-12-23 07:33:27 -06:00
b6258d08d6
Memberofindirect processing of an entry doesn't work if the user doesn't have rights to any one of these attributes: - member - memberuser - memberhost Add all of these to any read permission that specifies any of them. Add a check to makeaci that will enforce this for any future permissions. Reviewed-By: Martin Kosek <mkosek@redhat.com>
138 lines
4.6 KiB
Python
Executable File
138 lines
4.6 KiB
Python
Executable File
#!/usr/bin/python2
|
|
# Authors:
|
|
# Petr Viktorin <pviktori@redhat.com>
|
|
# John Dennis <jdennis@redhat.com>
|
|
# Martin Kosek <mkosek@redhat.com>
|
|
#
|
|
# Copyright (C) 2011 Red Hat
|
|
# see file 'COPYING' for use and warranty information
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# Test the managed permission ACIs against a known-good ACI list
|
|
# to ensure that changes aren't made lightly.
|
|
# Can either regenerate ACI.txt, or validate against it.
|
|
|
|
import sys
|
|
import difflib
|
|
from argparse import ArgumentParser
|
|
|
|
from ipalib import api
|
|
from ipapython.dn import DN
|
|
from ipapython.ipaldap import LDAPEntry, IPASimpleLDAPObject, LDAPClient
|
|
|
|
|
|
class FakeLDAPClient(LDAPClient):
|
|
"""A LDAP client that can't do any LDAP operations
|
|
|
|
Used to create and manipulate entries without an LDAP connection.
|
|
"""
|
|
def _init_connection(self):
|
|
self.conn = IPASimpleLDAPObject('', False, no_schema=True)
|
|
|
|
|
|
def parse_options():
|
|
parser = ArgumentParser()
|
|
parser.add_argument('--validate', dest='validate', action='store_true',
|
|
default=False, help='Validate the API vs the stored API')
|
|
parser.add_argument('filename', nargs='?', default='ACI.txt',
|
|
help='File to create or validate, default: ACI.txt')
|
|
|
|
options = parser.parse_args()
|
|
return options
|
|
|
|
|
|
def generate_aci_lines(api):
|
|
"""Yields ACI lines as they appear in ACI.txt, with trailing newline"""
|
|
update_plugin = api.Updater['update_managed_permissions']
|
|
perm_plugin = api.Object['permission']
|
|
fake_ldap = FakeLDAPClient('')
|
|
for name, template, obj in update_plugin.get_templates():
|
|
dn = perm_plugin.get_dn(name)
|
|
entry = fake_ldap.make_entry(dn)
|
|
update_plugin.update_entry(
|
|
obj=obj,
|
|
entry=entry,
|
|
template=template,
|
|
anonymous_read_aci=None,
|
|
is_new=True,
|
|
)
|
|
aci = perm_plugin.make_aci(entry)
|
|
yield 'dn: %s\n' % dn
|
|
yield 'aci: %s\n' % aci
|
|
|
|
check_member_attrs(name, template)
|
|
|
|
|
|
def check_member_attrs(name, template):
|
|
"""Check that member* attrs are always present together for read
|
|
|
|
ldap2._process_memberofindirect reads all these attributes together;
|
|
if the user doesn't have rights to one of them, the entire entry is
|
|
left out and memberofindirect processing returns wrong a result.
|
|
So we need all of them be readable.
|
|
"""
|
|
checked_attrs = ['member', 'memberuser', 'memberhost']
|
|
perm_attrs = template.get('ipapermdefaultattr', ())
|
|
flags = [(a in perm_attrs) for a in checked_attrs]
|
|
if 'read' in template['ipapermright'] and any(flags) and not all(flags):
|
|
raise AssertionError("'%s' includes some but not all of %s" %
|
|
(name, checked_attrs))
|
|
|
|
|
|
def main(options):
|
|
api.bootstrap(
|
|
context='cli',
|
|
in_server=False,
|
|
debug=False,
|
|
verbose=0,
|
|
validate_api=True,
|
|
enable_ra=True,
|
|
mode='developer',
|
|
plugins_on_demand=False,
|
|
basedn=DN('dc=ipa,dc=example'),
|
|
realm='IPA.EXAMPLE',
|
|
)
|
|
from ipaserver.install.plugins.update_managed_permissions import (
|
|
update_managed_permissions)
|
|
from ipalib.plugins.permission import permission
|
|
api.finalize()
|
|
|
|
output_lines = list(generate_aci_lines(api))
|
|
|
|
if options.validate:
|
|
with open(options.filename) as file:
|
|
file_lines = file.readlines()
|
|
if file_lines != output_lines:
|
|
diff = list(difflib.unified_diff(
|
|
file_lines,
|
|
output_lines,
|
|
fromfile='existing %s' % options.filename,
|
|
tofile='new result',
|
|
))
|
|
for line in diff:
|
|
print line,
|
|
print>>sys.stderr
|
|
print>>sys.stderr, 'Managed permission ACI validation failed.'
|
|
print>>sys.stderr, 'Re-check permission changes and run `makeaci`.'
|
|
exit('%s validation failed' % options.filename)
|
|
else:
|
|
with open(options.filename, 'w') as file:
|
|
file.writelines(output_lines)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
options = parse_options()
|
|
main(options)
|