예제 #1
0
 def remove(config, username, filename, force):
     """Remove user's SSH public key from their LDAP entry."""
     client = Client()
     client.prepare_connection()
     user_api = UserApi(client)
     key_api = API(client)
     key_api.remove(username, user_api, filename, force)
예제 #2
0
 def show(config, username):  # pragma: no cover
     """Show a user's SSH public key from their LDAP entry."""
     client = Client()
     client.prepare_connection()
     key_api = API(client)
     for key, value in key_api.get_keys_from_ldap(username).items():
         print(value)
예제 #3
0
 def create(config, name, group, type):
     """Create an LDAP user."""
     if type not in ('user', 'service'):
         raise click.BadOptionUsage("--type must be 'user' or 'service'")
     client = Client()
     client.prepare_connection()
     user_api = API(client)
     group_api = GroupApi(client)
     user_api.create(name[0], name[1], group, type, group_api)
예제 #4
0
 def list(config):  # pragma: no cover
     """List SSH public key(s) from LDAP."""
     client = Client()
     client.prepare_connection()
     key_api = API(client)
     for key, values in key_api.get_keys_from_ldap().items():
         print("{}: ".format(key))
         for value in [v.decode() for v in values]:
             print("\t - {}".format(value))
예제 #5
0
    def create(config, group, type):
        """Create an LDAP group."""
        if type not in ('user', 'service'):
            raise click.BadOptionUsage(  # pragma: no cover
                "--grouptype must be 'user' or 'service'")

        client = Client()
        client.prepare_connection()
        group_api = API(client)
        group_api.create(group, type)
예제 #6
0
    def delete(config, group, force):
        """Delete an LDAP group."""
        if not force:
            if not click.confirm(
                    'Confirm that you want to delete group {}'.format(group)):
                sys.exit("Deletion of {} aborted".format(group))

        client = Client()
        client.prepare_connection()
        group_api = API(client)
        group_api.delete(group)
예제 #7
0
 def remove_user(config, group, username):
     """Remove specified user from specified group."""
     client = Client()
     client.prepare_connection()
     group_api = API(client)
     try:
         group_api.remove_user(group, username)
     except ldap_tools.exceptions.NoGroupsFound:  # pragma: no cover
         print("Group ({}) not found".format(group))
     except ldap_tools.exceptions.TooManyResults:  # pragma: no cover
         print("Query for group ({}) returned multiple results.".format(
             group))
     except ldap3.NO_SUCH_ATTRIBUTE:  # pragma: no cover
         print("{} does not exist in {}".format(username, group))
예제 #8
0
 def add_user(config, group, username):
     """Add specified user to specified group."""
     client = Client()
     client.prepare_connection()
     group_api = API(client)
     try:
         group_api.add_user(group, username)
     except ldap_tools.exceptions.NoGroupsFound:  # pragma: no cover
         print("Group ({}) not found".format(group))
     except ldap_tools.exceptions.TooManyResults:  # pragma: no cover
         print("Query for group ({}) returned multiple results.".format(
             group))
     except ldap3.TYPE_OR_VALUE_EXISTS:  # pragma: no cover
         print("{} already exists in {}".format(username, group))
예제 #9
0
 def add(config, username, filename):
     """Add user's SSH public key to their LDAP entry."""
     try:
         client = Client()
         client.prepare_connection()
         user_api = UserApi(client)
         key_api = API(client)
         key_api.add(username, user_api, filename)
     except (ldap3.core.exceptions.LDAPNoSuchAttributeResult,
             ldap_tools.exceptions.InvalidResult,
             ldap3.core.exceptions.LDAPAttributeOrValueExistsResult
             ) as err:  # pragma: no cover
         print('{}: {}'.format(type(err), err.args[0]))
     except Exception as err:  # pragma: no cover
         raise err from None
예제 #10
0
 def install(config):  # pragma: no cover
     """Install user's SSH public key to the local system."""
     client = Client()
     client.prepare_connection()
     key_api = API(client)
     key_api.install()
예제 #11
0
 def index(config):
     """Display user info in LDIF format."""
     client = Client()
     client.prepare_connection()
     user_api = API(client)
     CLI.show_user(user_api.index())
예제 #12
0
def describe_client():
    client = Client()
    client.conn = MagicMock()
    client.basedn = 'dc=test,dc=org'
    distinguished_name = 'cn=test.user,ou=People,dc=test,dc=org'
    object_class = ['inetOrgPerson']
    attributes = {'givenName': 'Test', 'sn': 'User'}

    def it_adds_object_to_ldap():
        client.conn.reset_mock()
        client.add(distinguished_name, object_class, attributes)
        client.conn.add.assert_called_once_with(distinguished_name,
                                                object_class, attributes)

    def describe_client_search():
        client.conn.search = MagicMock()

        def it_searches_with_default_filter_and_attributes():
            pytest.xfail(reason='ideopathic unreliable results')
            search_filter = ["(objectclass=*)"]
            filterstr = "(&{})".format(''.join(search_filter))
            attributes = ['*']
            client.conn.reset_mock()
            client.conn.search.reset_mock()

            client.search(None)
            client.conn.search.assert_any_call(search_base=client.basedn,
                                               search_filter=filterstr,
                                               search_scope=ldap3.SUBTREE,
                                               attributes=attributes)

        def it_searches_with_default_attributes_and_custom_filter():
            pytest.xfail(reason='ideopathic unreliable results')
            search_filter = ["(objectclass=top)"]
            filterstr = "(&{})".format(''.join(search_filter))
            attributes = ['*']
            client.conn.reset_mock()
            client.conn.search.reset_mock()

            client.search(search_filter)
            client.conn.search.assert_any_call(search_base=client.basedn,
                                               search_filter=filterstr,
                                               search_scope=ldap3.SUBTREE,
                                               attributes=attributes)

        def it_searches_with_default_filter_and_custom_attributes():
            pytest.xfail(reason='ideopathic unreliable results')
            search_filter = ["(objectclass=*)"]
            filterstr = "(&{})".format(''.join(search_filter))
            attributes = ['uid', 'gid']
            client.conn.reset_mock()
            client.conn.search.reset_mock()

            client.search(None, attributes)
            client.conn.search.assert_any_call(search_base=client.basedn,
                                               search_filter=filterstr,
                                               search_scope=ldap3.SUBTREE,
                                               attributes=attributes)

    def describe_get_max_id():
        def it_gets_id_of_service_user():
            client.search = MagicMock(return_value=[])
            assert client.get_max_id('user', 'service') == 20000

        def it_gets_id_of_normal_user():
            client.search = MagicMock(return_value=[])
            assert client.get_max_id('user', 'user') == 10000

        def it_raises_error_on_bad_user_type():
            client.search = MagicMock(return_value=[])
            with pytest.raises(ldap_tools.exceptions.InvalidResult,
                               message=("Unknown object type")):
                client.get_max_id('user', 'foo')
예제 #13
0
    def describe_api_calls():
        client = Client()
        client.prepare_connection = MagicMock()

        def describe_key_addition():
            client.modify = MagicMock()
            user_api = UserApi(client)
            user_api.find = MagicMock(return_value=ldap_entry)
            key_api = KeyApi(client)

            def it_calls_the_client():
                pytest.xfail(reason='Need to learn how to mock user.entry_dn')
                client.modify.reset_mock()
                filename = path.join(fixture_path, 'single_key_user')
                key_api.add(username, user_api, filename)
                client.modify.assert_called_once_with(distinguished_name,
                                                      mock.ANY)

            def it_raises_error_on_bad_key():
                pytest.xfail(reason='Need to learn how to mock user.entry_dn')
                filename = path.join(fixture_path, 'invalid_user_key')

                with pytest.raises(sshpubkeys.exceptions.MalformedDataError):
                    key_api.add(username, user_api, filename)

            def it_raises_error_on_bad_object():
                pytest.xfail(reason='Need to learn how to mock user.entry_dn')
                filename = path.join(fixture_path, 'single_key_user')
                ldap_entry = [[
                    distinguished_name, {
                        'objectClass': [
                            b'top', b'posixAccount', b'shadowAccount',
                            b'inetOrgPerson', b'organizationalPerson',
                            b'person'
                        ]
                    }
                ]]
                user_api.find = MagicMock(return_value=ldap_entry)

                with pytest.raises(
                        ldap3.core.exceptions.LDAPNoSuchAttributeResult):
                    key_api.add(username, user_api, filename)

        def it_removes_key_from_user(mocker):  # noqa: F811
            pytest.xfail(reason='Need to learn how to mock user.entry_dn')
            client.modify = MagicMock()
            client.search = MagicMock()
            user_api = UserApi(client)
            user_api.find = MagicMock(return_value=ldap_entry)
            key_api = KeyApi(client)

            with open(path.join(fixture_path, 'two_key_user'),
                      'r') as FILE:  # get current keys
                mocker.patch.object(key_api,
                                    '_API__current_keys',
                                    return_value=FILE.read().splitlines())

            filename = path.join(fixture_path, 'delete_user_key')

            key_api.remove(username, user_api, filename, True)
            client.modify.assert_called_once_with(distinguished_name, mock.ANY)

        def describe_get_keys_from_ldap():
            client.search = MagicMock()
            key_api = KeyApi(client)

            def it_filters_with_username():
                client.search.reset_mock()
                filter = ['(sshPublicKey=*)', '(uid={})'.format(username)]
                key_api.get_keys_from_ldap(username)

                client.search.assert_any_call(filter, ['uid', 'sshPublicKey'])

            def it_filters_without_username():
                client.search.reset_mock()
                filter = ['(sshPublicKey=*)']
                key_api.get_keys_from_ldap()

                client.search.assert_called_once_with(filter,
                                                      ['uid', 'sshPublicKey'])
예제 #14
0
 def raw(config):  # pragma: no cover
     """Dump the contents of LDAP to console in raw format."""
     client = Client()
     client.prepare_connection()
     audit_api = API(client)
     print(audit_api.raw())
예제 #15
0
def describe_group():  # TODO: change this to use test_key.py format
    group_name = 'testGroup'
    group_type = 'user'
    username = '******'
    ldap_attributes = {'cn': b'testGroup', 'gidnumber': 99999}
    group_objectclass = ["(objectclass=posixGroup)"]
    runner = CliRunner()
    client = Client()
    client.prepare_connection = MagicMock()
    client.load_ldap_config = MagicMock()
    client.prepare_connection()
    client.basedn = 'dc=test,dc=org'
    client.server = ldap3.Server('my_fake_server')
    client.conn = ldap3.Connection(client.server,
                                   user='******'.format(
                                       client.basedn),
                                   password='******',
                                   client_strategy=ldap3.MOCK_SYNC)

    def describe_creates_group():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.group.API.create', return_value=None)
                mocker.patch('ldap_tools.client.Client.prepare_connection',
                             return_value=None)

                runner.invoke(
                    GroupCli.group,
                    ['create', '--group', group_name, '--type', group_type])

                ldap_tools.group.API.create.assert_called_once_with(
                    group_name, group_type)

            def it_raises_exception_on_bad_type(mocker):  # noqa: F811
                mocker.patch('ldap_tools.group.API.create', return_value=None)
                mocker.patch('ldap_tools.client.Client.prepare_connection',
                             return_value=None)

                runner.invoke(
                    GroupCli.group,
                    ['create', '--group', group_name, '--type', group_type])

                assert pytest.raises(click.BadOptionUsage)

        def describe_api():
            def it_calls_the_client():
                client.add = MagicMock()
                client.get_max_id = MagicMock(return_value=99999)
                group_objectclass = ['top', 'posixGroup']

                group_api = GroupApi(client)
                # mocker.patch.object(
                #     group_api, '_API__ldap_attr', return_value=ldap_attributes)

                group_api.create(group_name, group_type)
                client.add.assert_called_once_with(
                    'cn={},ou=Group,{}'.format(group_name, client.basedn),
                    group_objectclass, ldap_attributes)

    def describe_deletes_group():
        def describe_commandline():
            group_api = GroupApi(client)
            group_api.delete = MagicMock()

            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.group.API.delete', return_value=None)
                mocker.patch('ldap_tools.client.Client.prepare_connection',
                             return_value=None)

                # We have to force here, otherwise, we get stuck
                # on an interactive prompt
                runner.invoke(GroupCli.group,
                              ['delete', '--group', group_name, '--force'])

                ldap_tools.group.API.delete.assert_called_once_with(group_name)

            def it_exits_on_no_force_no_confirm(mocker):  # noqa: F811
                mocker.patch('ldap_tools.group.API.delete', return_value=None)
                mocker.patch('ldap_tools.client.Client.prepare_connection',
                             return_value=None)
                mocker.patch('click.confirm', return_value=False)

                # We have to force here, otherwise, we get stuck
                # on an interactive prompt
                result = runner.invoke(GroupCli.group,
                                       ['delete', '--group', group_name])
                assert result.output == "Deletion of {} aborted\n".format(
                    group_name)

        def describe_api():
            def it_calls_the_client():
                client.delete = MagicMock()

                group_api = GroupApi(client)

                group_api.delete(group_name)
                client.delete.assert_called_once_with(
                    'cn={},ou=Group,{}'.format(group_name, client.basedn))

    def describe_adds_user():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.group.API.add_user',
                             return_value=None)
                mocker.patch('ldap_tools.client.Client.prepare_connection',
                             return_value=None)
                group_api = GroupApi(client)
                group_api.add_user = MagicMock()

                runner.invoke(GroupCli.group, [
                    'add_user', '--group', group_name, '--username', username
                ])

                ldap_tools.group.API.add_user.assert_called_once_with(
                    group_name, username)

        def describe_api():
            def it_calls_the_client(mocker):  # noqa: F811
                client.modify = MagicMock()

                group_api = GroupApi(client)
                group_api.lookup_id = MagicMock(return_value=99999)

                group_api.add_user(group_name, username)
                client.modify.assert_called_once_with(
                    'cn={},ou=Group,{}'.format(group_name, client.basedn),
                    {'memberUid': [(ldap3.MODIFY_ADD, [username])]})

    def describe_removes_user():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.group.API.remove_user',
                             return_value=None)
                mocker.patch('ldap_tools.client.Client.prepare_connection',
                             return_value=None)
                group_api = GroupApi(client)
                group_api.remove_user = MagicMock()

                runner.invoke(GroupCli.group, [
                    'remove_user', '--group', group_name, '--username',
                    username
                ])

                ldap_tools.group.API.remove_user.assert_called_once_with(
                    group_name, username)

        def describe_api():
            def it_calls_the_client():
                client.modify = MagicMock()

                group_api = GroupApi(client)
                group_api.lookup_id = MagicMock(return_value=99999)

                group_api.remove_user(group_name, username)
                client.modify.assert_called_once_with(
                    'cn={},ou=Group,{}'.format(group_name, client.basedn),
                    {'memberUid': [(ldap3.MODIFY_DELETE, [username])]})

    def describe_indexes_groups():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.group.API.index', return_value=None)
                mocker.patch('ldap_tools.client.Client.prepare_connection',
                             return_value=None)
                group_api = GroupApi(client)
                group_api.index = MagicMock()

                runner.invoke(GroupCli.group, ['index'])

                ldap_tools.group.API.index.assert_called_once_with()

        def describe_api():
            def it_calls_the_client():
                client.search = MagicMock()
                # client.prepare_connection = MagicMock()
                # client.load_ldap_config = MagicMock()

                group_api = GroupApi(client)

                group_api.index()
                client.search.assert_called_once_with(group_objectclass)

    def describe_lookup_id():
        def describe_commandline():
            pass  # not implemented

        def describe_api():
            def it_searches_with_correct_filter():
                pytest.xfail(
                    reason='Need to learn how to mock list.gidNumber.value')
                client.search = MagicMock(return_value=['foo'])

                group_api = GroupApi(client)
                group_api.lookup_id(group_name)
                search_filter = [
                    "(cn={})".format(group_name), "(objectclass=posixGroup)"
                ]
                client.search.assert_called_once_with(search_filter,
                                                      ['gidNumber'])

            def it_raises_exception_on_no_groups_found():
                client.search = MagicMock()
                group_api = GroupApi(client)

                with pytest.raises(ldap_tools.exceptions.NoGroupsFound,
                                   message=("No Groups Returned by LDAP.")):
                    group_api.lookup_id(group_name)

            def it_raises_exception_on_multiple_results():
                client.search = MagicMock(return_value=['foo', 'bar'])
                group_api = GroupApi(client)

                with pytest.raises(
                        ldap_tools.exceptions.TooManyResults,
                        message=(
                            "Multiple groups found. Please narrow your search."
                        )):
                    group_api.lookup_id(group_name)
예제 #16
0
 def by_user(config):
     """Display LDAP group membership sorted by user."""
     client = Client()
     client.prepare_connection()
     audit_api = API(client)
     CLI.parse_membership('Groups by User', audit_api.by_user())
예제 #17
0
 def delete(config, username, type):
     """Delete an LDAP user."""
     client = Client()
     client.prepare_connection()
     user_api = API(client)
     user_api.delete(username, type)
예제 #18
0
def describe_user():  # TODO: change this to use test_key.py format
    first_name = 'Test'
    last_name = 'User'
    username = '******'
    user_type = 'user'
    group_name = 'testGroup'
    ldap_attributes = {'attribute': 'value'}
    runner = CliRunner()  # initialize commandline runner
    client = Client()
    group_api = GroupApi(client)

    def describe_creates_user():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.user.API.create', return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                runner.invoke(UserCli.user, [
                    'create', '--name', first_name, last_name, '--type',
                    user_type, '--group', group_name
                ])

                ldap_tools.user.API.create.assert_called_once_with(
                    first_name, last_name, group_name, user_type, mock.ANY)

            def it_raises_exception_on_bad_type(mocker):  # noqa: F811
                mocker.patch('ldap_tools.user.API.create', return_value=None)

                runner.invoke(ldap_tools.user.CLI.user, [
                    'create', '--name', first_name, last_name, '--type',
                    'badType', '--group', group_name
                ])

                assert pytest.raises(click.BadOptionUsage)

        def describe_api():
            def it_assembles_the_current_username(mocker):  # noqa: F811
                client.add = MagicMock()

                user_api = UserApi(client)
                # mock private method __ldap_attr, so we don't have to manage
                # a giant dict that requires mocking many private methods
                client.basedn = 'dc=test,dc=org'
                mocker.patch.object(
                    user_api, '_API__ldap_attr', return_value=ldap_attributes)

                user_api.create(first_name, last_name, group_name, user_type,
                                group_api)
                user_api.ldap_attr = ldap_attributes

                assert user_api.username == 'test.user'

            def it_calls_the_client(mocker):  # noqa: F811
                client.add = MagicMock()

                user_api = UserApi(client)
                # mock private method __ldap_attr, so we don't have to manage
                # a giant dict that requires mocking many private methods
                client.basedn = 'dc=test,dc=org'
                mocker.patch.object(
                    user_api, '_API__ldap_attr', return_value=ldap_attributes)
                mocker.patch.object(
                    UserApi,
                    '_API__object_class',
                    return_value='inetOrgPerson')

                user_api.create(first_name, last_name, group_name, user_type,
                                group_api)
                user_api.ldap_attr = ldap_attributes

                client.add.assert_called_once_with(
                    'uid=test.user,ou=People,dc=test,dc=org', 'inetOrgPerson',
                    ldap_attributes)

    def describe_deletes_user():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.user.API.delete', return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                runner.invoke(
                    ldap_tools.user.CLI.user,
                    ['delete', '--username', username, '--type', user_type])

                ldap_tools.user.API.delete.assert_called_once_with(
                    username, user_type)

        def describe_api():
            def it_uses_the_correct_distinguished_name(mocker):  # noqa: F811
                mocker.patch(
                    'ldap_tools.client.Client.delete', return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.load_ldap_config',
                    return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                ldap_tools.client.Client.basedn = 'dc=test,dc=org'

                user_api = UserApi(client)
                user_api.delete(username, user_type)

                ldap_tools.client.Client.delete.assert_called_once_with(
                    'uid=test.user,ou=People,dc=test,dc=org')

    def describe_indexes_user():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.user.API.index', return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                runner.invoke(ldap_tools.user.CLI.user, ['index'])

                ldap_tools.user.API.index.assert_called_once_with()

        def describe_api():
            def it_passes_the_correct_filter(mocker):  # noqa: F811
                mocker.patch(
                    'ldap_tools.client.Client.search', return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                user_api = UserApi(client)
                user_api.index()

                ldap_tools.client.Client.search.assert_called_once_with(
                    ["(objectclass=posixAccount)"])

    def describe_shows_user():
        def describe_commandline():
            def it_calls_the_api(mocker):  # noqa: F811
                mocker.patch('ldap_tools.user.API.show', return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                runner.invoke(ldap_tools.user.CLI.user,
                              ['show', '--username', username])

                ldap_tools.user.API.show.assert_called_once_with(username)

        def describe_api():
            def it_passes_the_correct_filter(mocker):  # noqa: F811
                mocker.patch(
                    'ldap_tools.client.Client.search', return_value=None)
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                user_api = UserApi(client)
                user_api.show(username)

                filter = [
                    '(objectclass=posixAccount)', "(uid={})".format(username)
                ]

                ldap_tools.client.Client.search.assert_called_once_with(filter)

    def describe_finds_user():
        def describe_commandline():
            pass  # no methods implemented

        def describe_api():
            def it_finds_a_user(mocker):  # noqa: F811
                mocker.patch(
                    'ldap_tools.client.Client.search', return_value=['foo'])
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                user_api = UserApi(client)
                user_api.find(username)

                ldap_tools.client.Client.search.assert_called_once_with(
                    ['(uid={})'.format(username)])

            def it_finds_two_users(mocker):  # noqa: F811
                mocker.patch(
                    'ldap_tools.client.Client.search',
                    return_value=['foo', 'bar'])
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                user_api = UserApi(client)

                with pytest.raises(
                        ldap_tools.exceptions.TooManyResults,
                        message=(
                            "Multiple users found. Please narrow your search."
                        )):
                    user_api.find(username)

            def it_finds_no_users(mocker):  # noqa: F811
                mocker.patch(
                    'ldap_tools.client.Client.search', return_value=[])
                mocker.patch(
                    'ldap_tools.client.Client.prepare_connection',
                    return_value=None)

                user_api = UserApi(client)

                with pytest.raises(
                        ldap_tools.exceptions.NoUserFound,
                        message="User ({}) not found"):
                    user_api.find(username)
예제 #19
0
 def by_group(config):
     """Display LDAP group membership sorted by group."""
     client = Client()
     client.prepare_connection()
     audit_api = API(client)
     CLI.parse_membership('Users by Group', audit_api.by_group())
예제 #20
0
 def index(config):  # pragma: no cover
     """Display group info in raw format."""
     client = Client()
     client.prepare_connection()
     group_api = API(client)
     print(group_api.index())
예제 #21
0
 def show(config, username):
     """Display a specific user."""
     client = Client()
     client.prepare_connection()
     user_api = API(client)
     CLI.show_user(user_api.show(username))