示例#1
0
def test_apply_grant_rule_all_schema(mocker):
    gla = mocker.patch('ldap2pg.manager.expand_attributes', autospec=True)

    from ldap2pg.manager import SyncManager

    manager = SyncManager()

    gla.side_effect = [['alice']]
    items = manager.apply_grant_rules(
        grant=[
            dict(
                privilege='connect',
                databases=['postgres'],
                schema='__all__',
                roles=['{cn}'],
            )
        ],
        entries=[None],
    )
    items = list(items)
    assert 1 == len(items)
    assert 'alice' == items[0].role
    assert 'postgres' == items[0].dbname[0]
    # Ensure __all__ schema is mapped to object
    assert items[0].schema != '__all__'
示例#2
0
def test_inspect_ldap_roles(mocker):
    ql = mocker.patch('ldap2pg.manager.SyncManager.query_ldap')

    from ldap2pg.manager import SyncManager
    from ldap2pg.role import Role

    ql.return_value = [('dn', {}, {})]

    manager = SyncManager(
        ldapconn=mocker.Mock(),
        inspector=mocker.Mock(name='inspector'),
    )
    manager.inspector.roles_blacklist = ['blacklisted']

    rule0 = mocker.Mock(name='rule0', all_fields=[])
    rule0.generate.return_value = [Role('alice', options=dict(LOGIN=True))]
    rule1 = mocker.Mock(name='rule1', all_fields=[])
    rule1.generate.return_value = [Role('bob')]
    rule2 = mocker.Mock(name='rule2', all_fields=[])
    rule2.generate.return_value = [Role('blacklisted')]

    # Minimal effective syncmap
    syncmap = [
        dict(roles=[]),
        dict(
            ldap=dict(base='ou=users,dc=tld', filter='*', attributes=['cn']),
            roles=[rule0, rule1, rule2],
        ),
    ]

    ldaproles, _ = manager.inspect_ldap(syncmap=syncmap)

    assert 'alice' in ldaproles
    assert 'bob' in ldaproles
示例#3
0
def test_apply_role_rule_unexpected_dn(mocker):
    gla = mocker.patch('ldap2pg.manager.expand_attributes', autospec=True)

    from ldap2pg.manager import SyncManager, RDNError, UserError

    manager = SyncManager()

    gla.side_effect = RDNError

    list(
        manager.apply_role_rules(
            entries=[('dn0', ), ('dn1', )],
            rules=[dict(names=['{cn}'], on_unexpected_dn='warn')],
        ))

    list(
        manager.apply_role_rules(
            entries=[('dn0', ), ('dn1', )],
            rules=[dict(names=['{cn}'], on_unexpected_dn='ignore')],
        ))

    with pytest.raises(UserError):
        list(
            manager.apply_role_rules(
                entries=[('dn0', ), ('dn1', )],
                rules=[dict(names=['{cn}'])],
            ))
示例#4
0
def test_sync(mocker):
    diff = mocker.patch('ldap2pg.manager.SyncManager.diff')

    from ldap2pg.manager import SyncManager

    psql = mocker.MagicMock()
    cursor = psql.return_value.__enter__.return_value

    manager = SyncManager(psql=psql)

    # Simple diff with one query
    diff.return_value = qry = [mocker.Mock(name='qry', args=(), message='hop')]
    qry[0].expand.return_value = [qry[0]]

    sync_kw = dict(
        databases=['postgres', 'template1'],
        pgroles=set(), pgacls=set(), ldaproles=set(), ldapacls=set(),
    )

    # Dry run
    manager.dry = True
    # No mapping, we're just testing query loop
    manager.sync(**sync_kw)
    assert cursor.called is False

    # Real mode
    manager.dry = False
    manager.sync(**sync_kw)
    assert cursor.called is True

    # Nothing to do
    diff.return_value = []
    manager.dry = False
    manager.sync(**sync_kw)
    assert cursor.called is True
示例#5
0
def test_query_ldap(mocker):
    from ldap2pg.manager import SyncManager, UserError

    manager = SyncManager(ldapconn=mocker.Mock())
    manager.ldapconn.search_s.return_value = [
        ('dn=a', {}),
        ('dn=b', {}),
        (None, {
            'ref': True
        }),
    ]

    entries = manager.query_ldap(
        base='ou=people,dc=global',
        filter='(objectClass=*)',
        scope=2,
        attributes=['cn'],
    )

    assert 2 == len(entries)

    manager.ldapconn.search_s.return_value = [('dn=a', {'a': b'\xbb'})]
    with pytest.raises(UserError):
        manager.query_ldap(
            base='ou=people,dc=global',
            filter='(objectClass=*)',
            scope=2,
            attributes=['cn'],
        )
示例#6
0
def test_diff_acls(mocker):
    from ldap2pg.acl import Acl, AclItem
    from ldap2pg.manager import SyncManager

    acl = Acl(name='connect', revoke='REVOKE {role}', grant='GRANT {role}')
    nogrant = Acl(name='nogrant', revoke='REVOKE')
    norvk = Acl(name='norvk', grant='GRANT')
    m = SyncManager(acl_dict={a.name: a for a in [acl, nogrant, norvk]})

    item0 = AclItem(acl=acl.name, dbname='backend', role='daniel')
    pgacls = set([
        item0,
        AclItem(acl=acl.name, dbname='backend', role='alice'),
        AclItem(acl=norvk.name, role='torevoke'),
    ])
    ldapacls = set([
        item0,
        AclItem(acl=acl.name, dbname='backend', role='david'),
        AclItem(acl=nogrant.name, role='togrant'),
    ])

    queries = [q.args[0] for q in m.diff(pgacls=pgacls, ldapacls=ldapacls)]

    assert not fnfilter(queries, "REVOKE daniel*")
    assert fnfilter(queries, "REVOKE alice*")
    assert fnfilter(queries, "GRANT david*")
示例#7
0
def test_inspect_acls(mocker):
    mod = 'ldap2pg.manager.'
    psql = mocker.MagicMock()
    psql.itersessions.return_value = [('postgres', psql)]

    dbl = mocker.patch(mod + 'SyncManager.fetch_database_list', autospec=True)
    dbl.return_value = ['postgres']
    mocker.patch(mod + 'SyncManager.process_pg_roles', autospec=True)
    pa = mocker.patch(mod + 'SyncManager.process_pg_acl_items', autospec=True)
    la = mocker.patch(mod + 'SyncManager.apply_grant_rules', autospec=True)

    from ldap2pg.manager import SyncManager, AclItem
    from ldap2pg.acl import Acl
    from ldap2pg.utils import make_group_map

    acl_dict = dict(
        noinspect=Acl(name='noinspect'),
        ro=Acl(name='ro', inspect='SQL'),
    )
    pa.return_value = [AclItem('ro', 'postgres', None, 'alice')]
    la.return_value = [AclItem('ro', 'postgres', None, 'alice')]

    manager = SyncManager(
        psql=psql, ldapconn=mocker.Mock(), acl_dict=acl_dict,
        acl_aliases=make_group_map(acl_dict)
    )
    syncmap = dict(db=dict(schema=[dict(roles=[], grant=dict(acl='ro'))]))

    databases, _, pgacls, _, ldapacls = manager.inspect(syncmap=syncmap)

    assert 1 == len(pgacls)
    assert 1 == len(ldapacls)
示例#8
0
def test_inspect_roles(mocker):
    p = mocker.patch('ldap2pg.manager.SyncManager.process_pg_roles')
    ql = mocker.patch('ldap2pg.manager.SyncManager.query_ldap')
    r = mocker.patch('ldap2pg.manager.SyncManager.process_ldap_entry')
    psql = mocker.MagicMock()

    from ldap2pg.manager import SyncManager, Role

    p.return_value = {Role(name='spurious')}
    ql.return_value = [mocker.Mock(name='entry')]
    r.side_effect = [{Role(name='alice')}, {Role(name='bob')}]

    manager = SyncManager(psql=psql, ldapconn=mocker.Mock())
    # Minimal effective syncmap
    syncmap = dict(db=dict(s=[
        dict(roles=[]),
        dict(
            ldap=dict(base='ou=users,dc=tld', filter='*', attributes=['cn']),
            roles=[dict(), dict()],
        ),
    ]))

    manager.inspect(syncmap=syncmap)

    assert 2 is r.call_count, "sync did not iterate over each rules."
示例#9
0
def test_query_ldap_joins_missing(mocker):
    from ldap2pg.manager import SyncManager, UserError

    search_result = [('cn=A,ou=people,dc=global', {
        'cn': ['A'],
    })]

    manager = SyncManager(ldapconn=mocker.Mock())
    manager.ldapconn.search_s.side_effect = [search_result]

    with pytest.raises(UserError) as ei:
        manager.query_ldap(
            base='ou=people,dc=global',
            filter='(objectClass=group)',
            scope=2,
            joins={
                'member':
                dict(
                    filter='(objectClass=people)',
                    attributes=['sAMAccountName'],
                )
            },
            attributes=['cn', 'member'],
        )
    assert "Missing attribute member" in str(ei.value)
示例#10
0
def test_inspect_ldap_roles(mocker):
    ql = mocker.patch('ldap2pg.manager.SyncManager.query_ldap')
    r = mocker.patch('ldap2pg.manager.SyncManager.process_ldap_entry')

    from ldap2pg.manager import SyncManager, Role

    ql.return_value = [mocker.Mock(name='entry')]
    r.side_effect = [
        {Role(name='alice', options=dict(SUPERUSER=True))},
        {Role(name='bob')},
    ]

    manager = SyncManager(
        ldapconn=mocker.Mock(),
    )

    # Minimal effective syncmap
    syncmap = [
        dict(roles=[]),
        dict(
            ldap=dict(base='ou=users,dc=tld', filter='*', attributes=['cn']),
            roles=[dict(), dict()],
        ),
    ]

    ldaproles, _ = manager.inspect_ldap(syncmap=syncmap)

    assert 2 == r.call_count, "sync did not iterate over each rules."

    assert 'alice' in ldaproles
    assert 'bob' in ldaproles
示例#11
0
def test_postprocess_acl_inexistant_privilege():
    from ldap2pg.manager import SyncManager, Acl, Grant, UserError

    manager = SyncManager()

    with pytest.raises(UserError):
        manager.postprocess_acl(
            acl=Acl([Grant('inexistant')]),
            schemas=dict(postgres=dict(public=['postgres'])),
        )
示例#12
0
def test_apply_grant_rule_wrong_attr(mocker):
    gla = mocker.patch('ldap2pg.manager.expand_attributes')

    from ldap2pg.manager import SyncManager, UserError

    gla.side_effect = ValueError('POUET')
    items = SyncManager().apply_grant_rules(
        grant=[dict(roles=['{cn}'])],
        entries=[None, None],
    )
    with pytest.raises(UserError):
        list(items)
示例#13
0
def test_query_ldap_bad_filter(mocker):
    from ldap2pg.manager import SyncManager, LDAPError, UserError

    manager = SyncManager(ldapconn=mocker.Mock())
    manager.ldapconn.search_s.side_effect = LDAPError()

    with pytest.raises(UserError):
        manager.query_ldap(
            base='dc=unit', filter='(broken', scope=2, attributes=[],
        )

    assert manager.ldapconn.search_s.called is True
示例#14
0
def test_query_ldap(mocker):
    from ldap2pg.manager import SyncManager

    manager = SyncManager(ldapconn=mocker.Mock())
    manager.ldapconn.search_s.return_value = [('dn=a', {}), ('dn=b', {})]

    entries = manager.query_ldap(
        base='ou=people,dc=global', filter='(objectClass=*)',
        scope=2, attributes=['cn'],
    )

    assert 2 == len(entries)
示例#15
0
def test_fetch_roles(mocker):
    from ldap2pg.manager import SyncManager

    manager = SyncManager()
    psql = mocker.Mock(name='psql')
    psql.return_value = mocker.MagicMock()
    psql.return_value.__iter__.return_value = r = [mocker.Mock()]

    rows = manager.fetch_pg_roles(psql)
    rows = list(rows)

    assert r == rows

    manager = SyncManager(roles_query=None)
    psql = mocker.Mock(name='psql')
    psql.return_value = cur = mocker.MagicMock()

    rows = manager.fetch_pg_roles(psql)
    rows = list(rows)

    assert cur.called is False
    assert [] == rows
示例#16
0
def test_process_entry_dn():
    from ldap2pg.manager import SyncManager

    manager = SyncManager()

    entry = ('dn', {'member': ['cn=alice,dc=unit', 'cn=bob,dc=unit']})

    roles = manager.process_ldap_entry(entry, name_attribute='member.cn')
    roles = list(roles)
    names = {r.name for r in roles}

    assert 2 == len(roles)
    assert 'alice' in names
    assert 'bob' in names
示例#17
0
def test_process_entry_static():
    from ldap2pg.manager import SyncManager

    manager = SyncManager()

    roles = manager.process_ldap_entry(
        entry=None, names=['ALICE'], parents=['postgres'],
        options=dict(LOGIN=True),
    )
    roles = list(roles)

    assert 1 == len(roles)
    assert 'alice' in roles
    assert 'postgres' in roles[0].parents
示例#18
0
def test_inspect_roles_duplicate_differents_options(mocker):
    from ldap2pg.manager import SyncManager, UserError

    manager = SyncManager()

    syncmap = [dict(roles=[
        dict(names=['group0']),
        dict(names=['group1']),
        dict(names=['bob'], options=dict(LOGIN=True)),
        dict(names=['bob'], options=dict(LOGIN=False)),
    ])]

    with pytest.raises(UserError):
        manager.inspect_ldap(syncmap=syncmap)
示例#19
0
def test_apply_role_rule_ko(mocker):
    gla = mocker.patch('ldap2pg.manager.expand_attributes', autospec=True)

    from ldap2pg.manager import SyncManager, UserError

    manager = SyncManager()

    gla.side_effect = ValueError
    items = manager.apply_role_rules(
        entries=[('dn0',), ('dn1',)],
        rules=[dict(names=['{cn}'])],
    )
    with pytest.raises(UserError):
        list(items)
示例#20
0
def test_empty_sync_map(mocker):
    from ldap2pg.manager import SyncManager, RoleSet

    manager = SyncManager(
        inspector=mocker.Mock(name='inspector'),
        psql=mocker.Mock(name='psql'),
    )
    manager.inspector.fetch_me.return_value = 'me', True
    manager.inspector.fetch_roles_blacklist.return_value = []
    manager.inspector.fetch_roles.return_value = [], RoleSet(), RoleSet()
    manager.inspector.filter_roles.return_value = RoleSet(), RoleSet()
    manager.psql.run_queries.return_value = 0

    manager.sync([])
示例#21
0
def test_query_ldap_joins_filtered_allowed(mocker):
    from ldap2pg.manager import SyncManager, LDAPEntry

    search_result = [
        ('cn=A,ou=people,dc=global', {
            'cn': ['A'],
            'member': ['cn=P,ou=people,dc=global']
        }),
    ]

    sub_search_result = []

    manager = SyncManager(ldapconn=mocker.Mock())
    manager.ldapconn.search_s.side_effect = [search_result, sub_search_result]

    entries = manager.query_ldap(
        base='ou=people,dc=global',
        filter='(objectClass=group)',
        scope=2,
        attributes=['cn', 'member'],
        joins={
            'member':
            dict(
                base='ou=people,dc=global',
                scope=2,
                filter='(objectClass=group)',
                attributes=['cn'],
                allow_missing_attributes=[],
            )
        },
        allow_missing_attributes=['member'],
    )

    assert 2 == manager.ldapconn.search_s.call_count

    expected_entries = [
        LDAPEntry(
            'cn=A,ou=people,dc=global',
            {
                'cn': ['A'],
                'member': ['cn=P,ou=people,dc=global'],
            },
            {
                'member': [],
            },
        ),
    ]

    assert expected_entries == entries
示例#22
0
def test_process_roles_rows():
    from ldap2pg.manager import SyncManager

    manager = SyncManager(blacklist=['pg_*', 'postgres'])
    rows = [
        ('postgres', []),
        ('pg_signal_backend', []),
        ('dba', ['alice']),
        ('alice', []),
    ]
    roles = list(manager.process_pg_roles(rows))

    assert 2 == len(roles)
    assert 'dba' == roles[0].name
    assert 'alice' == roles[1].name
示例#23
0
def test_process_entry_members(mocker):
    from ldap2pg.manager import SyncManager

    manager = SyncManager()

    entry = ('dn', {'member': ['cn=alice,dc=unit', 'cn=bob,dc=unit']})

    roles = manager.process_ldap_entry(
        entry, names=['group'], members_attribute='member.cn',
    )
    roles = list(roles)

    assert 1 == len(roles)
    role = roles[0]
    assert 'alice' in role.members
    assert 'bob' in role.members
示例#24
0
def test_apply_role_rule_ko(mocker):
    gla = mocker.patch('ldap2pg.manager.get_ldap_attribute', autospec=True)

    from ldap2pg.manager import SyncManager, UserError

    manager = SyncManager()

    gla.side_effect = ValueError
    items = manager.apply_role_rules(
        entries=[None, None],
        rules=[dict(
            name_attribute='cn',
        )],
    )
    with pytest.raises(UserError):
        list(items)
示例#25
0
def test_postprocess_acl_bad_database():
    from ldap2pg.manager import SyncManager, Grant, Acl, UserError
    from ldap2pg.privilege import NspAcl
    from ldap2pg.utils import make_group_map

    privileges = dict(ro=NspAcl(name='ro', inspect='SQL'))
    manager = SyncManager(
        privileges=privileges, privilege_aliases=make_group_map(privileges),
    )

    acl = Acl([Grant('ro', ['inexistantdb'], None, 'alice')])
    schemas = dict(postgres=dict(public=['postgres']))

    with pytest.raises(UserError) as ei:
        manager.postprocess_acl(acl, schemas)
    assert 'inexistantdb' in str(ei.value)
示例#26
0
def test_apply_grant_rule_filter(mocker):
    from ldap2pg.manager import SyncManager

    items = SyncManager().apply_grant_rules(
        grant=[dict(
            privilege='connect',
            database='postgres',
            schema='__any__',
            role_match='*_r',
            roles=['alice_r', 'bob_rw'],
        )],
        entries=[None],
    )
    items = list(items)
    assert 1 == len(items)
    assert 'alice_r' == items[0].role
示例#27
0
def test_fetch_schema(mocker):
    from ldap2pg.manager import SyncManager

    manager = SyncManager()
    psql = mocker.Mock(name='psql')
    psql.return_value = mocker.MagicMock()
    psql.return_value.__iter__.return_value = [
        ('information_schema',), ('custom',),
    ]

    rows = manager.fetch_schema_list(psql)
    rows = list(rows)

    assert 2 == len(rows)
    assert 'information_schema' in rows
    assert 'custom' in rows
示例#28
0
def test_fetch_databases(mocker):
    from ldap2pg.manager import SyncManager

    manager = SyncManager()
    psql = mocker.Mock(name='psql')
    psql.return_value = mocker.MagicMock()
    psql.return_value.__iter__.return_value = [
        ('postgres',), ('template1',),
    ]

    rows = manager.fetch_database_list(psql)
    rows = list(rows)

    assert 2 == len(rows)
    assert 'postgres' in rows
    assert 'template1' in rows
示例#29
0
def test_apply_grant_rule_nodb(mocker):
    gla = mocker.patch('ldap2pg.manager.expand_attributes', autospec=True)

    from ldap2pg.manager import Grant, SyncManager

    manager = SyncManager()

    gla.return_value = ['alice']
    items = list(manager.apply_grant_rules(
        grant=[dict(
            privilege='connect',
            database='__all__', schema='__any__',
            roles=['{cn}'],
        )],
        entries=[None],
    ))
    assert items[0].dbname is Grant.ALL_DATABASES
示例#30
0
def test_process_entry_user():
    from ldap2pg.manager import SyncManager

    manager = SyncManager()

    entry = ('dn', {'cn': [('alice', {}), ('bob', {})]})

    roles = manager.process_ldap_entry(
        entry, names=['{cn}'],
        options=dict(LOGIN=True),
    )
    roles = list(roles)

    assert 2 == len(roles)
    assert 'alice' in roles
    assert 'bob' in roles
    assert roles[0].options['LOGIN'] is True