Browse Source

Revert "Command-line utility for importing users and groups from LDAP"

This reverts commit 7f46ab4353169e0ae164eb2e3c88a24d475279e7.
Jon Natkins 13 năm trước cách đây
mục cha
commit
a7b57ff5a4

+ 0 - 159
apps/useradmin/src/useradmin/ldap_access.py

@@ -1,159 +0,0 @@
-#!/usr/bin/env python
-# Licensed to Cloudera, Inc. under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  Cloudera, Inc. licenses this file
-# to you 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.
-"""
-This module provides access to LDAP servers, along with some basic functionality required for Hue and
-User Admin to work seamlessly with LDAP.
-"""
-import desktop.conf
-import ldap
-import ldap.filter
-
-import logging
-LOG = logging.getLogger(__name__)
-
-CACHED_LDAP_CONN = None
-
-def get_connection():
-  global CACHED_LDAP_CONN
-  if CACHED_LDAP_CONN is not None:
-    return CACHED_LDAP_CONN
-
-  ldap_url = desktop.conf.LDAP.LDAP_URL.get()
-  nt_domain = desktop.conf.LDAP.NT_DOMAIN.get()
-  username = desktop.conf.LDAP.BIND_DN.get()
-  password = desktop.conf.LDAP.BIND_PASSWORD.get()
-  ldap_cert = desktop.conf.LDAP.LDAP_CERT.get()
-
-  return LdapConnection(ldap_url, get_ldap_username(username, nt_domain),
-                        password, ldap_cert)
-
-def get_ldap_username(username, nt_domain):
-  if nt_domain:
-    return '%s@%s' % (username, nt_domain)
-  else:
-    return username
-
-class LdapConnection(object):
-  """
-  Constructor creates LDAP connection. Contains methods
-  to easily query an LDAP server.
-  """
-
-  def __init__(self, ldap_url, bind_user=None, bind_password=None, cert_file=None):
-    """
-    Constructor initializes the LDAP connection
-    """
-    if cert_file is not None:
-      ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW)
-      ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, cert_file)
-
-    ldap.set_option(ldap.OPT_REFERRALS, 0)
-
-    self.ldap_handle = ldap.initialize(ldap_url)
-
-    if bind_user is not None:
-      try:
-        self.ldap_handle.simple_bind_s(bind_user, bind_password)
-      except:
-        raise RuntimeError("Failed to bind to LDAP server as user %s" %
-            (bind_user,))
-    else:
-      try:
-        # Do anonymous bind
-        self.ldap_handle.simple_bind_s('','')
-      except:
-        raise RuntimeError("Failed to bind to LDAP server anonymously")
-
-  def find_user(self, username, find_by_dn=False):
-    """
-    LDAP search helper method finding users. This supports searching for users
-    by distinguished name, or the configured username attribute.
-    """
-    base_dn = self._get_root_dn()
-    scope = ldap.SCOPE_SUBTREE
-
-    user_filter = desktop.conf.LDAP.USERS.USER_FILTER.get()
-    if not user_filter.startswith('('):
-      user_filter = '(' + user_filter + ')'
-    user_name_attr = desktop.conf.LDAP.USERS.USER_NAME_ATTR.get()
-
-    if find_by_dn:
-      sanitized_name = ldap.filter.escape_filter_chars(username)
-      user_name_filter = '(distinguishedName=' + sanitized_name + ')'
-    else:
-      sanitized_name = ldap.filter.escape_filter_chars(username)
-      user_name_filter = '(' + user_name_attr + '=' + sanitized_name + ')'
-    ldap_filter = '(&' + user_filter + user_name_filter + ')'
-
-    ldap_result_id = self.ldap_handle.search(base_dn, scope, ldap_filter)
-    result_type, result_data = self.ldap_handle.result(ldap_result_id)
-    if result_type == ldap.RES_SEARCH_RESULT and result_data[0][0] is not None:
-      data = result_data[0][1]
-      user_info = { 'username': data[user_name_attr][0] }
-
-      if 'givenName' in data:
-        user_info['first'] = data['givenName'][0]
-      if 'sn' in data:
-        user_info['last'] = data['sn'][0]
-      if 'email' in data:
-        user_info['email'] = data['email'][0]
-
-      return user_info
-
-    return None
-
-  def find_group(self, groupname, find_by_dn=False):
-    """
-    LDAP search helper method for finding groups
-    """
-    base_dn = self._get_root_dn()
-    scope = ldap.SCOPE_SUBTREE
-
-    group_filter = desktop.conf.LDAP.GROUPS.GROUP_FILTER.get()
-    if not group_filter.startswith('('):
-      group_filter = '(' + group_filter + ')'
-    group_name_attr = desktop.conf.LDAP.GROUPS.GROUP_NAME_ATTR.get()
-
-    if find_by_dn:
-      sanitized_name = ldap.filter.escape_filter_chars(groupname)
-      group_name_filter = '(distinguishedName=' + sanitized_name + ')'
-    else:
-      sanitized_name = ldap.filter.escape_filter_chars(groupname)
-      group_name_filter = '(' + group_name_attr + '=' + sanitized_name + ')'
-    ldap_filter = '(&' + group_filter + group_name_filter + ')'
-
-    ldap_result_id = self.ldap_handle.search(base_dn, scope, ldap_filter)
-    result_type, result_data = self.ldap_handle.result(ldap_result_id)
-    if result_type == ldap.RES_SEARCH_RESULT and result_data[0][0] is not None:
-      data = result_data[0][1]
-      group_info = { 'name': data[group_name_attr][0] }
-
-      member_attr = desktop.conf.LDAP.GROUPS.GROUP_MEMBER_ATTR.get()
-      if member_attr in data:
-        group_info['members'] = data[member_attr]
-      else:
-        group_info['members'] = []
-
-      return group_info
-
-    return None
-
-  def _get_root_dn(self):
-    """
-    Returns the configured base DN (DC=desktop,DC=local).
-    """
-    return desktop.conf.LDAP.BASE_DN.get()

+ 0 - 50
apps/useradmin/src/useradmin/management/commands/import_ldap_group.py

@@ -1,50 +0,0 @@
-#!/usr/bin/env python
-# Licensed to Cloudera, Inc. under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  Cloudera, Inc. licenses this file
-# to you 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 optparse import make_option
-
-from useradmin.views import import_ldap_group
-
-from django.core.management.base import BaseCommand, CommandError
-
-class Command(BaseCommand):
-  """
-  Handler for importing LDAP groups into the Hue database.
-
-  If a group has been previously imported, this will sync membership within the
-  group with the LDAP server. If --import-members is specified, it will import
-  all unimported users.
-  """
-
-  option_list = BaseCommand.option_list + (
-      make_option("--dn", help="Whether or not the user should be imported by "
-                               "distinguished name",
-                          action="store_true",
-                          default=False),
-      make_option("--import-members", help="Import users from the group",
-                                      action="store_true",
-                                      default=False),
-   )
-
-  args = "group-name"
-
-  def handle(self, group=None, **options):
-    if group is None:
-      raise CommandError("A group name must be provided")
-
-    import_members = options['import_members']
-    import_by_dn = options['dn']
-    import_ldap_group(group, import_members, import_by_dn)

+ 0 - 44
apps/useradmin/src/useradmin/management/commands/import_ldap_user.py

@@ -1,44 +0,0 @@
-#!/usr/bin/env python
-# Licensed to Cloudera, Inc. under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  Cloudera, Inc. licenses this file
-# to you 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 optparse import make_option
-
-from useradmin.views import import_ldap_user
-
-from django.core.management.base import BaseCommand, CommandError
-
-class Command(BaseCommand):
-  """
-  Handler for importing LDAP users into the Hue database.
-
-  If a user has been previously imported, this will sync their user information.
-  """
-
-  option_list = BaseCommand.option_list + (
-      make_option("--dn", help="Whether or not the user should be imported by "
-                               "distinguished name",
-                          action="store_true",
-                          default=False),
-  )
-
-  args = "username"
-
-  def handle(self, user=None, **options):
-    if user is None:
-      raise CommandError("A username must be provided")
-
-    import_by_dn = options['dn']
-    import_ldap_user(user, import_by_dn)

+ 0 - 31
apps/useradmin/src/useradmin/management/commands/sync_ldap_users_and_groups.py

@@ -1,31 +0,0 @@
-#!/usr/bin/env python
-# Licensed to Cloudera, Inc. under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  Cloudera, Inc. licenses this file
-# to you 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 useradmin.views import sync_ldap_users_and_groups
-
-from django.core.management.base import NoArgsCommand
-
-class Command(NoArgsCommand):
-  """
-  Handler for syncing the Hue database with LDAP users and groups.
-
-  This will not import any users or groups that don't already exist in Hue. All
-  user information and group memberships will be updated based on the LDAP
-  server's current state.
-  """
-
-  def handle_noargs(self, **options):
-    sync_ldap_users_and_groups()

+ 1 - 85
apps/useradmin/src/useradmin/tests.py

@@ -29,12 +29,9 @@ from desktop.lib.django_test_util import make_logged_in_client
 from django.contrib.auth.models import User, Group
 from django.utils.encoding import smart_unicode
 
-from useradmin.models import HuePermission, GroupPermission, LdapGroup, UserProfile
+from useradmin.models import HuePermission, GroupPermission
 from useradmin.models import get_profile
 
-from views import sync_ldap_users_and_groups
-import ldap_access
-
 def reset_all_users():
   """Reset to a clean state by deleting all users"""
   for user in User.objects.all():
@@ -45,43 +42,6 @@ def reset_all_groups():
   for grp in Group.objects.all():
     grp.delete()
 
-class LdapTestConnection(object):
-  """
-  Test class which mimics the behaviour of LdapConnection (from ldap_access.py).
-  It also includes functionality to fake modifications to an LDAP server.  It is designed
-  as a singleton, to allow for changes to persist across discrete connections.
-  """
-
-  _instance = None
-  def __init__(self):
-    if LdapTestConnection._instance is None:
-      LdapTestConnection._instance = LdapTestConnection._Singleton()
-
-  def add_user_group_for_test(self, user, group):
-    LdapTestConnection._instance.groups[group]['members'].append(user)
-
-  def remove_user_group_for_test(self, user, group):
-    LdapTestConnection._instance.groups[group]['members'].remove(user)
-
-  def find_user(self, user, find_by_dn=False):
-    """ Returns info for a particular user """
-    return LdapTestConnection._instance.users[user]
-
-  def find_group(self, groupname):
-    """ Return all groups in the system with parents and children """
-    return LdapTestConnection._instance.groups[groupname]
-
-  class _Singleton:
-    def __init__(self):
-      self.users = {'moe': {'username':'moe', 'first':'Moe', 'email':'moe@stooges.com'},
-                    'larry': {'username':'larry', 'first':'Larry', 'last':'Stooge', 'email':'larry@stooges.com'},
-                    'curly': {'username':'curly', 'first':'Curly', 'last':'Stooge', 'email':'curly@stooges.com'}}
-
-      self.groups = {'TestUsers': {'name':'TestUsers', 'members':['moe','larry','curly']},
-                     'Test Administrators': {'name':'Test Administrators', 'members':['curly','larry']}}
-
-
-
 def test_invalid_username():
   BAD_NAMES = ('-foo', 'foo:o', 'foo o', ' foo')
 
@@ -308,47 +268,3 @@ def test_user_admin():
   # You shouldn't be able to create a user without a password
   response = c_su.post('/useradmin/users/new', dict(username="test"))
   assert_true("You must specify a password when creating a new user." in response.content)
-
-def test_userman_ldap_integration():
-  reset_all_users()
-  reset_all_groups()
-
-  # Set up LDAP tests to use a LdapTestConnection instead of an actual LDAP connection
-  ldap_access.CACHED_LDAP_CONN = LdapTestConnection()
-
-  # Try importing a user
-  sync_ldap_users_and_groups(user='larry')
-  larry = User.objects.get(username='larry')
-  assert_true(larry.first_name == 'Larry')
-  assert_true(larry.last_name == 'Stooge')
-  assert_true(larry.email == 'larry@stooges.com')
-  assert_true(get_profile(larry).creation_method == str(UserProfile.CreationMethod.EXTERNAL))
-
-  # Should be a noop
-  sync_ldap_users_and_groups()
-  assert_true(len(User.objects.all()) == 1)
-  assert_true(len(Group.objects.all()) == 0)
-
-  # Should import a group, but will only sync already-imported members
-  sync_ldap_users_and_groups(group='Test Administrators')
-  assert_true(len(User.objects.all()) == 1)
-  assert_true(len(Group.objects.all()) == 1)
-  test_admins = Group.objects.get(name='Test Administrators')
-  assert_true(len(test_admins.user_set.all()) == 1)
-  assert_true(test_admins.user_set.all()[0].username == larry.username)
-
-  # Import all members of TestUsers
-  sync_ldap_users_and_groups(group='TestUsers', import_members=True)
-  test_users = Group.objects.get(name='TestUsers')
-  assert_true(LdapGroup.objects.filter(group=test_users).exists())
-  assert_true(len(test_users.user_set.all()) == 3)
-
-  ldap_access.CACHED_LDAP_CONN.remove_user_group_for_test('moe', 'TestUsers')
-  sync_ldap_users_and_groups(group='TestUsers')
-  assert_true(len(test_users.user_set.all()) == 2)
-  assert_true(len(User.objects.get(username='moe').groups.all()) == 0)
-
-  ldap_access.CACHED_LDAP_CONN.add_user_group_for_test('moe', 'TestUsers')
-  sync_ldap_users_and_groups(group='TestUsers')
-  assert_true(len(test_users.user_set.all()) == 3)
-  assert_true(len(User.objects.get(username='moe').groups.all()) == 1)

+ 1 - 95
apps/useradmin/src/useradmin/views.py

@@ -31,9 +31,7 @@ from django.contrib.auth.models import User, Group
 from desktop.lib.django_util import get_username_re_rule, get_groupname_re_rule, render, PopupException, format_preserving_redirect
 from django.core import urlresolvers
 
-from useradmin.models import GroupPermission, HuePermission, UserProfile, LdapGroup
-from useradmin.models import get_profile
-import ldap_access
+from useradmin.models import GroupPermission, HuePermission
 
 LOG = logging.getLogger(__name__)
 
@@ -328,98 +326,6 @@ def sync_unix_users_and_groups(min_uid, max_uid, min_gid, max_gid, check_shell):
   __users_lock.release()
   __groups_lock.release()
 
-def _import_ldap_user(username, import_by_dn=False):
-  """
-  Import a user from LDAP. If import_by_dn is true, this will import the user by
-  the distinguished name, rather than the configured username attribute.
-  """
-  conn = ldap_access.get_connection()
-  user_info = conn.find_user(username, import_by_dn)
-  if user_info is None:
-    LOG.warn("Could not get LDAP details for user %s" % (username,))
-    return None
-
-  user, created = User.objects.get_or_create(username=user_info['username'])
-  profile = get_profile(user)
-  if not created and profile.creation_method == str(UserProfile.CreationMethod.HUE):
-    # This is a Hue user, and shouldn't be overwritten
-    LOG.warn('There was a naming conflict while importing user %s' % (username,))
-    return None
-
-  if 'first' in user_info:
-    user.first_name = user_info['first']
-  if 'last' in user_info:
-    user.last_name = user_info['last']
-  if 'email' in user_info:
-    user.email = user_info['email']
-
-  profile.creation_method = UserProfile.CreationMethod.EXTERNAL
-  profile.save()
-  user.save()
-
-  return user
-
-def _import_ldap_group(groupname, import_members=False, import_by_dn=False):
-  """
-  Import a group from LDAP. If import_members is true, this will also import any
-  LDAP users that exist within the group.
-  """
-  conn = ldap_access.get_connection()
-  group_info = conn.find_group(groupname, import_by_dn)
-  if group_info is None:
-    LOG.warn("Could not get LDAP details for group %s" % (groupname,))
-    return None
-
-  group, created = Group.objects.get_or_create(name=group_info['name'])
-  if not created and not LdapGroup.objects.filter(group=group).exists():
-    # This is a Hue group, and shouldn't be overwritten
-    LOG.warn('There was a naming conflict while importing group %s' % (groupname,))
-    return None
-
-  LdapGroup.objects.get_or_create(group=group)
-
-  group.user_set.clear()
-  for member in group_info['members']:
-    if import_members:
-      LOG.debug("Importing user %s" % (member,))
-      user = _import_ldap_user(member, import_by_dn=True)
-    else:
-      user_info = conn.find_user(member, find_by_dn=True)
-      try:
-        user = User.objects.get(username=user_info['username'])
-      except User.DoesNotExist:
-        continue
-
-    if get_profile(user).creation_method == str(UserProfile.CreationMethod.HUE):
-      continue
-    LOG.debug("Adding user %s to group %s" % (member, group.name))
-    group.user_set.add(user)
-
-  group.save()
-  return group
-
-def import_ldap_user(user, import_by_dn):
-  _import_ldap_user(user, import_by_dn)
-
-def import_ldap_group(group, import_members, import_by_dn):
-  _import_ldap_group(group, import_members, import_by_dn)
-
-def sync_ldap_users_and_groups():
-  """
-  Syncs LDAP user information and group memberships. This will not import new
-  users or groups from LDAP. It is also not possible to import both a user and a
-  group at the same time. Each must be a separate operation. If neither a user,
-  nor a group is provided, all users and groups will be synced.
-  """
-  # Sync everything
-  users = User.objects.filter(userprofile__creation_method=str(UserProfile.CreationMethod.EXTERNAL)).all()
-  for user in users:
-    _import_ldap_user(user.username)
-
-  groups = Group.objects.filter(group__in=LdapGroup.objects.all())
-  for group in groups:
-    _import_ldap_group(group.name)
-
 class GroupEditForm(forms.ModelForm):
   """
   Form to manipulate a group.  This manages the group name and its membership.