def test_authenticate_and_behavior_failure_non_group_member_of_all_required_groups_1(
            self):
        # User is member of two of the required groups (1 and 3) but not all three of them
        # (1, 2, 3)
        required_group_dns = [
            'cn=group1,dc=stackstorm,dc=net',
            'cn=group2,dc=stackstorm,dc=net',
            'cn=group3,dc=stackstorm,dc=net',
        ]
        backend = ldap_backend.LDAPAuthenticationBackend(LDAP_BIND_DN,
                                                         LDAP_BIND_PASSWORD,
                                                         LDAP_BASE_OU,
                                                         required_group_dns,
                                                         LDAP_HOST,
                                                         id_attr=LDAP_ID_ATTR,
                                                         group_dns_check='and')

        authenticated = backend.authenticate(LDAP_USER_UID,
                                             LDAP_USER_BAD_PASSWD)
        self.assertFalse(authenticated)
    def test_client_options(self):
        client_options = {
            ldap.OPT_RESTART: 0,
            ldap.OPT_SIZELIMIT: 2014,
            ldap.OPT_DIAGNOSTIC_MESSAGE: 'test',
            # Not using a constant, 20482 is OPT_TIMEOUT
            '20482': 9
        }

        backend = ldap_backend.LDAPAuthenticationBackend(
            LDAP_BIND_DN,
            LDAP_BIND_PASSWORD,
            LDAP_BASE_OU,
            LDAP_GROUP_DNS,
            LDAP_HOST,
            id_attr=LDAP_ID_ATTR,
            client_options=client_options)

        conn = backend._init_connection()
        for option_name, option_value in client_options.items():
            self.assertEqual(conn.get_option(int(option_name)), option_value)
    def test_authenticate_and_is_default_behavior_non_group_member_of_all_required_groups(
            self):
        # User is member of two of the required groups and two non-required, but not
        # all of the required groups
        # Verify "and" is a default group_dns_check_behavior
        required_group_dns = [
            'cn=group1,dc=stackstorm,dc=net',
            'cn=group2,dc=stackstorm,dc=net',
            'cn=group5,dc=stackstorm,dc=net',
            'cn=group6,dc=stackstorm,dc=net',
        ]
        backend = ldap_backend.LDAPAuthenticationBackend(LDAP_BIND_DN,
                                                         LDAP_BIND_PASSWORD,
                                                         LDAP_BASE_OU,
                                                         required_group_dns,
                                                         LDAP_HOST,
                                                         id_attr=LDAP_ID_ATTR)

        authenticated = backend.authenticate(LDAP_USER_UID,
                                             LDAP_USER_BAD_PASSWD)
        self.assertFalse(authenticated)
    def test_get_groups_caching_no_cross_username_cache_polution(self):
        required_group_dns = [
            'cn=group3,dc=stackstorm,dc=net', 'cn=group4,dc=stackstorm,dc=net'
        ]
        # Test which verifies that cache items are correctly scoped per username
        backend = ldap_backend.LDAPAuthenticationBackend(
            LDAP_BIND_DN,
            LDAP_BIND_PASSWORD,
            LDAP_BASE_OU,
            required_group_dns,
            LDAP_HOST,
            id_attr=LDAP_ID_ATTR,
            group_dns_check='or',
            cache_user_groups_response=True)
        user_groups = backend.get_user_groups(username=LDAP_USER_UID)
        self.assertEqual(user_groups, ['cn=group3,dc=stackstorm,dc=net'])
        self.assertEqual(backend._user_groups_cache[LDAP_USER_UID],
                         ['cn=group3,dc=stackstorm,dc=net'])

        user_groups = backend.get_user_groups(username=LDAP_USER_UID_2)
        self.assertEqual(user_groups, ['cn=group4,dc=stackstorm,dc=net'])
        self.assertEqual(backend._user_groups_cache[LDAP_USER_UID_2],
                         ['cn=group4,dc=stackstorm,dc=net'])
    def test_special_characters_in_username_are_escaped(self):
        # User is not member of any of the required group
        backend = ldap_backend.LDAPAuthenticationBackend(LDAP_BIND_DN,
                                                         LDAP_BIND_PASSWORD,
                                                         LDAP_BASE_OU,
                                                         LDAP_GROUP_DNS,
                                                         LDAP_HOST,
                                                         id_attr=LDAP_ID_ATTR)

        values = [
            ('stanleyA', 'stanleyA'),
            ('stanley!@?.,&', 'stanley!@?.,&'),
            # Special characters () should be escaped
            ('(stanley)', '\\28stanley\\29'),
            # Special characters () should be escaped
            ('(stanley=)', '\\28stanley=\\29'),
        ]

        for actual_username, expected_username in values:
            authenticated = backend.authenticate(actual_username,
                                                 LDAP_USER_BAD_PASSWD)
            call_args_1 = ldap.ldapobject.SimpleLDAPObject.search_s.call_args_list[
                0][0]
            call_args_2 = ldap.ldapobject.SimpleLDAPObject.search_s.call_args_list[
                1][0]

            # First search_s call (find user by uid)
            filter_call_value = call_args_1[2]
            self.assertEqual(filter_call_value, 'uid=%s' % (expected_username))

            # Second search_s call (group membership test)
            filter_call_value = call_args_2[2]
            self.assertTrue('(memberUid=%s)' %
                            (expected_username) in filter_call_value)

            ldap.ldapobject.SimpleLDAPObject.search_s = mock.MagicMock(
                side_effect=[LDAP_USER_SEARCH_RESULT, []])
    def test_get_user_specifying_account_pattern(self):
        expected_username = '******'
        required_group_dns = [
            'cn=group3,dc=stackstorm,dc=net', 'cn=group4,dc=stackstorm,dc=net'
        ]
        scope = 'subtree'
        scope_number = ldap_backend.SEARCH_SCOPES[scope]

        account_pattern = '''
        (&
          (objectClass=person)
          (|
            (accountName={username})
            (mail={username})
          )
        )
        '''.replace('\n', '').replace(' ', '')
        expected_account_pattern = account_pattern.format(
            username=expected_username)

        backend = ldap_backend.LDAPAuthenticationBackend(
            LDAP_BIND_DN,
            LDAP_BIND_PASSWORD,
            LDAP_BASE_OU,
            required_group_dns,
            LDAP_HOST,
            scope=scope,
            account_pattern=account_pattern,
        )
        connection = mock.MagicMock()
        backend._init_connection = mock.MagicMock(return_value=connection)
        backend.get_user(expected_username)

        connection.search_s.assert_called_once_with(LDAP_BASE_OU, scope_number,
                                                    expected_account_pattern,
                                                    [])