Exemplo n.º 1
0
def test_postprocess_grants():
    from ldap2pg.manager import SyncManager
    from ldap2pg.privilege import DefAcl, Grant, Acl

    manager = SyncManager(
        privileges=dict(ro=DefAcl(name='ro')),
        privilege_aliases=dict(ro=['ro']),
    )

    # No owners
    acl = manager.postprocess_acl(Acl(), schemas=dict())
    assert 0 == len(acl)

    acl = Acl([Grant(privilege='ro', dbname=['db'], schema=None)])
    acl = manager.postprocess_acl(
        acl,
        schemas=dict(db=dict(
            public=['postgres', 'owner'],
            ns=['owner'],
        )),
    )

    # One grant per schema, per owner
    assert 3 == len(acl)
Exemplo n.º 2
0
def test_inspect_ldap_unexpected_dn(mocker):
    ql = mocker.patch('ldap2pg.manager.SyncManager.query_ldap')

    from ldap2pg.manager import SyncManager, UserError, LDAPEntry
    from ldap2pg.role import RoleRule

    manager = SyncManager()

    ql.return_value = [
        LDAPEntry('dn0', {
            'member': ['cn=member0', 'baddn=o0', 'cn=member1'],
        })
    ]

    list(
        manager.inspect_ldap([
            dict(
                description="Test query desc",
                ldap=dict(on_unexpected_dn='warn'),
                roles=[RoleRule(names=['{member.cn}'])],
            )
        ]))

    list(
        manager.inspect_ldap([
            dict(ldap=dict(on_unexpected_dn='ignore'),
                 roles=[RoleRule(names=['{member.cn}'])])
        ]))

    with pytest.raises(UserError):
        list(
            manager.inspect_ldap(
                [dict(
                    ldap=dict(),
                    roles=[RoleRule(names=['{member.cn}'])],
                )]))
Exemplo n.º 3
0
def test_inspect_ldap_grants(mocker):
    from ldap2pg.manager import SyncManager
    from ldap2pg.privilege import Grant, NspAcl
    from ldap2pg.utils import make_group_map

    privileges = dict(ro=NspAcl(name='ro'))
    manager = SyncManager(
        psql=mocker.Mock(),
        ldapconn=mocker.Mock(),
        privileges=privileges,
        privilege_aliases=make_group_map(privileges),
        inspector=mocker.Mock(name='inspector'),
    )
    manager.inspector.roles_blacklist = ['blacklisted']
    rule = mocker.Mock(name='grant', attributes_map={})
    rule.generate.return_value = [
        Grant('ro', 'postgres', None, 'alice'),
        Grant('ro', 'postgres', None, 'blacklisted'),
    ]
    syncmap = [dict(roles=[], grant=[rule])]

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

    assert 1 == len(grants)
Exemplo n.º 4
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', {
            'member': ['m']
        }),
        (None, {
            'ref': True
        }),
        (None, ['ldap://list_ref']),
    ]

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

    assert 2 == len(entries)
    assert [] == entries[0][1]['member']

    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,
            joins={},
            attributes=['cn'],
        )
Exemplo n.º 5
0
def test_sync_sql_error(mocker):
    diff = mocker.patch('ldap2pg.manager.SyncManager.diff')

    from ldap2pg.manager import SyncManager

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

    manager = SyncManager(psql=psql)

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

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

    manager.dry = False
    with pytest.raises(Exception):
        manager.sync(**sync_kw)
    assert cursor.called is True
Exemplo n.º 6
0
def test_apply_grant_rule_ok(mocker):
    gla = mocker.patch('ldap2pg.manager.get_ldap_attribute', autospec=True)

    from ldap2pg.manager import SyncManager

    manager = SyncManager()

    gla.side_effect = [['alice'], ['bob']]
    items = manager.apply_grant_rules(
        grant=[dict(
            acl='connect',
            database='postgres',
            schema='__any__',
            role_attribute='cn',
        )],
        entries=[None, None],
    )
    items = list(items)
    assert 2 == len(items)
    assert 'alice' == items[0].role
    assert 'postgres' == items[0].dbname
    # Ensure __any__ schema is mapped to None
    assert items[0].schema is None
    assert 'bob' == items[1].role
Exemplo n.º 7
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
Exemplo n.º 8
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
Exemplo n.º 9
0
def test_sync(mocker):
    from ldap2pg.manager import RoleOptions

    mod = 'ldap2pg.manager'
    mocker.patch(
        mod + '.RoleOptions.SUPPORTED_COLUMNS',
        RoleOptions.SUPPORTED_COLUMNS[:],
    )

    cls = mod + '.SyncManager'
    il = mocker.patch(cls + '.inspect_ldap', autospec=True)
    mocker.patch(cls + '.postprocess_acl', autospec=True)

    from ldap2pg.manager import SyncManager, UserError

    psql = mocker.Mock(name='psql')
    inspector = mocker.Mock(name='inspector')
    manager = SyncManager(psql=psql, inspector=inspector)

    inspector.fetch_me.return_value = ('postgres', False)
    inspector.roles_blacklist = ['pg_*']
    inspector.fetch_roles.return_value = (['postgres'], set(), set())
    pgroles = mocker.Mock(name='pgroles')
    # Simple diff with one query
    pgroles.diff.return_value = qry = [
        mocker.Mock(name='qry', args=(), message='hop')]
    inspector.filter_roles.return_value = set(), pgroles
    il.return_value = (mocker.Mock(name='ldaproles'), set())
    qry[0].expand.return_value = [qry[0]]
    inspector.fetch_schemas.return_value = dict(postgres=dict(ns=['owner']))
    inspector.fetch_grants.return_value = pgacl = mocker.Mock(name='pgacl')
    pgacl.diff.return_value = []

    # No privileges to sync, one query
    psql.dry = False
    psql.run_queries.return_value = 1
    count = manager.sync(syncmap=[])
    assert pgroles.diff.called is True
    assert pgacl.diff.called is False
    assert 1 == count

    # With privileges
    manager.privileges = dict(ro=mocker.Mock(name='ro'))
    count = manager.sync(syncmap=[])
    assert pgroles.diff.called is True
    assert pgacl.diff.called is True
    assert 2 == count

    # Dry run with roles and ACL
    manager.psql.dry = True
    manager.sync(syncmap=[])

    # Nothing to do
    psql.run_queries.return_value = 0
    count = manager.sync(syncmap=[])
    assert 0 == count

    # resolve_membership failure
    il.return_value[0].resolve_membership.side_effect = ValueError()
    with pytest.raises(UserError):
        manager.sync(syncmap=[])
Exemplo n.º 10
0
def test_query_ldap_joins(mocker):
    from ldap2pg.manager import SyncManager, LDAPError

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

    sub_search_result = [
        ('cn=P,ou=people,dc=global', {'sAMAccountName': ['P']}),
    ]

    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, joins={'member': dict(
            base='ou=people,dc=global',
            scope=2,
            filter='(objectClass=people)',
            attributes=['sAMAccountName'],
        )},
        attributes=['cn', 'member'],
    )

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

    assert expected_entries == entries

    manager.ldapconn.search_s.side_effect = [search_result]

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

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

    assert expected_entries == entries

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

    sub_search_result = LDAPError()

    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, joins={'member': dict(
            base='ou=people,dc=global',
            scope=2,
            filter='(objectClass=people)',
            attributes=['sAMAccountName'],
        )},
        attributes=['cn', 'member'],
    )

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

    assert expected_entries == entries
Exemplo n.º 11
0
def test_entry_build_vars():
    from ldap2pg.ldap import LDAPEntry
    from ldap2pg.manager import SyncManager

    entry = LDAPEntry(
        dn='cn=my0,uo=gr0,dc=acme,dc=tld',
        attributes=dict(
            cn=['my0'],
            member=[
                'cn=m0,uo=gr0',
                'cn=m1,uo=gr0',
            ],
            simple=[
                'cn=s0,uo=gr1',
                'cn=s1,uo=gr1',
                'cn=s2,uo=gr1',
            ],
        ),
        children=dict(member=[
            LDAPEntry(
                'cn=m0,uo=gr0',
                dict(mail=['*****@*****.**', '*****@*****.**']),
            ),
            LDAPEntry(
                'cn=m1,uo=gr0',
                dict(mail=['*****@*****.**']),
            ),
        ]),
    )

    map_ = dict(
        __self__=['dn', 'cn', 'dn.cn'],
        member=['cn', 'dn', 'mail', 'dn.cn'],
        simple=['cn'],
    )

    manager = SyncManager()
    vars_ = manager.build_format_vars(entry, map_, on_unexpected_dn='fail')
    wanted = dict(
        __self__=[
            dict(
                dn=[dict(
                    dn="cn=my0,uo=gr0,dc=acme,dc=tld",
                    cn="my0",
                )],
                cn=["my0"],
            )
        ],
        member=[
            dict(
                dn=[dict(dn="cn=m0,uo=gr0", cn="m0")],
                cn=["m0"],
                mail=["*****@*****.**", "*****@*****.**"],
            ),
            dict(
                dn=[dict(dn="cn=m1,uo=gr0", cn="m1")],
                cn=["m1"],
                mail=["*****@*****.**"],
            ),
        ],
        simple=[
            dict(
                dn=["cn=s0,uo=gr1"],
                cn=["s0"],
            ),
            dict(
                dn=["cn=s1,uo=gr1"],
                cn=["s1"],
            ),
            dict(
                dn=["cn=s2,uo=gr1"],
                cn=["s2"],
            ),
        ],
    )

    assert wanted == vars_
Exemplo n.º 12
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