<commit_before># Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
import uuid

import ldap.filter
from oslo_log import log
from oslo_log import versionutils
import six

from keystone.common import driver_hints
import keystone.conf
from keystone import exception
from keystone.i18n import _, _LW
from keystone.identity.backends import base
from keystone.identity.backends.ldap import common as common_ldap
from keystone.identity.backends.ldap import models


CONF = keystone.conf.CONF
LOG = log.getLogger(__name__)

_DEPRECATION_MSG = _('%s for the LDAP identity backend has been deprecated in '
                     'the Mitaka release in favor of read-only identity LDAP '
                     'access. It will be removed in the "O" release.')

READ_ONLY_LDAP_ERROR_MESSAGE = _("LDAP does not support write operations")

LDAP_MATCHING_RULE_IN_CHAIN = "1.2.840.113556.1.4.1941"


class Identity(base.IdentityDriverBase):
    def __init__(self, conf=None):
        super(Identity, self).__init__()
        if conf is None:
            self.conf = CONF
        else:
            self.conf = conf
        self.user = UserApi(self.conf)
        self.group = GroupApi(self.conf)

    def is_domain_aware(self):
        return False

    def generates_uuids(self):
        return False

    # Identity interface

    def authenticate(self, user_id, password):
        try:
            user_ref = self._get_user(user_id)
        except exception.UserNotFound:
            raise AssertionError(_('Invalid user / password'))
        if not user_id or not password:
            raise AssertionError(_('Invalid user / password'))
        conn = None
        try:
            conn = self.user.get_connection(user_ref['dn'],
                                            password, end_user_auth=True)
            if not conn:
                raise AssertionError(_('Invalid user / password'))
        except Exception:
            raise AssertionError(_('Invalid user / password'))
        finally:
            if conn:
                conn.unbind_s()
        return self.user.filter_attributes(user_ref)

    def _get_user(self, user_id):
        return self.user.get(user_id)

    def get_user(self, user_id):
        return self.user.get_filtered(user_id)

    def list_users(self, hints):
        return self.user.get_all_filtered(hints)

    def unset_default_project_id(self, project_id):
        # This function is not implemented for the LDAP backend. The LDAP
        # backend is readonly.
        self._disallow_write()

    def get_user_by_name(self, user_name, domain_id):
        # domain_id will already have been handled in the Manager layer,
        # parameter left in so this matches the Driver specification
        return self.user.filter_attributes(self.user.get_by_name(user_name))

    def get_group(self, group_id):
        return self.group.get_filtered(group_id)

    def get_group_by_name(self, group_name, domain_id):
        # domain_id will already have been handled in the Manager layer,
        # parameter left in so this matches the Driver specification
        return self.group.get_filtered_by_name(group_name)

    def list_groups_for_user(self, user_id, hints):
        user_ref = self._get_user(user_id)
        if self.conf.ldap.group_members_are_ids:
            user_dn = user_ref['id']
        else:
            user_dn = user_ref['dn']
        return self.group.list_user_groups_filtered(user_dn, hints)

    def list_groups(self, hints):
        return self.group.get_all_filtered(hints)

    def list_users_in_group(self, group_id, hints):
        users = []
        for user_key in self.group.list_group_users(group_id):
            if self.conf.ldap.group_members_are_ids:
                user_id = user_key
            else:
                user_id = self.user._dn_to_id(user_key)

            try:
                users.append(self.user.get_filtered(user_id))
            except exception.UserNotFound:
                msg = ('Group member `%(user_key)s` not found in'
                       ' `%(group_id)s`. The user should be removed'
                       ' from the group. The user will be ignored.')
                LOG.debug(msg, dict(user_key=user_key, group_id=group_id))
        return users

    def check_user_in_group(self, user_id, group_id):
        user_refs = self.list_users_in_group(group_id, driver_hints.Hints())
        for x in user_refs:
            if x['id'] == user_id:
                break
        else:
            # Try to fetch the user to see if it even exists.  This
            # will raise a more accurate exception.
            self.get_user(user_id)
            raise exception.NotFound(_("User '%(user_id)s' not found in"
                                       " group '%(group_id)s'") %
                                     {'user_id': user_id,
                                      'group_id': group_id})

    # Unsupported methods
    def _disallow_write(self):
        if not common_ldap.WRITABLE:
            raise exception.Forbidden(READ_ONLY_LDAP_ERROR_MESSAGE)

    def create_user(self, user_id, user):
        self._disallow_write()
        return self._create_user(user_id, user)

    def update_user(self, user_id, user):
        self._disallow_write()
        return self._update_user(user_id, user)

    def delete_user(self, user_id):
        self._disallow_write()
        self._delete_user(user_id)

    def change_password(self, user_id, new_password):
        raise exception.Forbidden(READ_ONLY_LDAP_ERROR_MESSAGE)<commit_msg>Speed up check_user_in_group for LDAP users<commit_after># Copyright 2012 OpenStack Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import
import uuid

import ldap.filter
from oslo_log import log
from oslo_log import versionutils
import six

import keystone.conf
from keystone import exception
from keystone.i18n import _, _LW
from keystone.identity.backends import base
from keystone.identity.backends.ldap import common as common_ldap
from keystone.identity.backends.ldap import models


CONF = keystone.conf.CONF
LOG = log.getLogger(__name__)

_DEPRECATION_MSG = _('%s for the LDAP identity backend has been deprecated in '
                     'the Mitaka release in favor of read-only identity LDAP '
                     'access. It will be removed in the "O" release.')

READ_ONLY_LDAP_ERROR_MESSAGE = _("LDAP does not support write operations")

LDAP_MATCHING_RULE_IN_CHAIN = "1.2.840.113556.1.4.1941"


class Identity(base.IdentityDriverBase):
    def __init__(self, conf=None):
        super(Identity, self).__init__()
        if conf is None:
            self.conf = CONF
        else:
            self.conf = conf
        self.user = UserApi(self.conf)
        self.group = GroupApi(self.conf)

    def is_domain_aware(self):
        return False

    def generates_uuids(self):
        return False

    # Identity interface

    def authenticate(self, user_id, password):
        try:
            user_ref = self._get_user(user_id)
        except exception.UserNotFound:
            raise AssertionError(_('Invalid user / password'))
        if not user_id or not password:
            raise AssertionError(_('Invalid user / password'))
        conn = None
        try:
            conn = self.user.get_connection(user_ref['dn'],
                                            password, end_user_auth=True)
            if not conn:
                raise AssertionError(_('Invalid user / password'))
        except Exception:
            raise AssertionError(_('Invalid user / password'))
        finally:
            if conn:
                conn.unbind_s()
        return self.user.filter_attributes(user_ref)

    def _get_user(self, user_id):
        return self.user.get(user_id)

    def get_user(self, user_id):
        return self.user.get_filtered(user_id)

    def list_users(self, hints):
        return self.user.get_all_filtered(hints)

    def unset_default_project_id(self, project_id):
        # This function is not implemented for the LDAP backend. The LDAP
        # backend is readonly.
        self._disallow_write()

    def get_user_by_name(self, user_name, domain_id):
        # domain_id will already have been handled in the Manager layer,
        # parameter left in so this matches the Driver specification
        return self.user.filter_attributes(self.user.get_by_name(user_name))

    def get_group(self, group_id):
        return self.group.get_filtered(group_id)

    def get_group_by_name(self, group_name, domain_id):
        # domain_id will already have been handled in the Manager layer,
        # parameter left in so this matches the Driver specification
        return self.group.get_filtered_by_name(group_name)

    def list_groups_for_user(self, user_id, hints):
        user_ref = self._get_user(user_id)
        if self.conf.ldap.group_members_are_ids:
            user_dn = user_ref['id']
        else:
            user_dn = user_ref['dn']
        return self.group.list_user_groups_filtered(user_dn, hints)

    def list_groups(self, hints):
        return self.group.get_all_filtered(hints)

    def _transform_group_member_ids(self, group_member_list):
        for user_key in group_member_list:
            if self.conf.ldap.group_members_are_ids:
                user_id = user_key
            else:
                user_id = self.user._dn_to_id(user_key)
            yield user_id

    def list_users_in_group(self, group_id, hints):
        users = []
        group_members = self.group.list_group_users(group_id)
        for user_id in self._transform_group_member_ids(group_members):
            try:
                users.append(self.user.get_filtered(user_id))
            except exception.UserNotFound:
                msg = ('Group member `%(user_id)s` for group `%(group_id)s`'
                       ' not found in the directory. The user should be'
                       ' removed from the group. The user will be ignored.')
                LOG.debug(msg, dict(user_id=user_id, group_id=group_id))
        return users

    def check_user_in_group(self, user_id, group_id):
        # Before doing anything, check that the user exists. This will raise
        # a not found error if the user doesn't exist so we avoid doing extra
        # work.
        self.get_user(user_id)
        member_list = self.group.list_group_users(group_id)
        for group_member_id in self._transform_group_member_ids(member_list):
            if group_member_id == user_id:
                break
        else:
            raise exception.NotFound(_("User '%(user_id)s' not found in"
                                       " group '%(group_id)s'") %
                                     {'user_id': user_id,
                                      'group_id': group_id})

    # Unsupported methods
    def _disallow_write(self):
        if not common_ldap.WRITABLE:
            raise exception.Forbidden(READ_ONLY_LDAP_ERROR_MESSAGE)

    def create_user(self, user_id, user):
        self._disallow_write()
        return self._create_user(user_id, user)

    def update_user(self, user_id, user):
        self._disallow_write()
        return self._update_user(user_id, user)

    def delete_user(self, user_id):
        self._disallow_write()
        self._delete_user(user_id)

    def change_password(self, user_id, new_password):
        raise exception.Forbidden(READ_ONLY_LDAP_ERROR_MESSAGE)
{'fraction_non_alphanumeric': 0.07660902977905859, 'fraction_numerical': 0.004322766570605188, 'mean_word_length': 2.4606648199445984, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7543850', 'n_tokens_mistral': 3681, 'n_tokens_neox': 3527, 'n_words': 998}