summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRob Crittenden <rcritten@redhat.com>2010-06-25 16:14:46 -0400
committerRob Crittenden <rcritten@redhat.com>2010-07-06 15:39:34 -0400
commitba59d9d648d7ee9f3e5b03ede9aeccab97f13a13 (patch)
treef333b0335b3ebdd0d198f3afcd0f274daae5950a
parent83fd9ef7cc7823619692a0286cbcec5297245153 (diff)
downloadfreeipa-ba59d9d648d7ee9f3e5b03ede9aeccab97f13a13.tar.gz
freeipa-ba59d9d648d7ee9f3e5b03ede9aeccab97f13a13.tar.xz
freeipa-ba59d9d648d7ee9f3e5b03ede9aeccab97f13a13.zip
Add support for User-Private Groups
This uses a new 389-ds plugin, Managed Entries, to automatically create a group entry when a user is created. The DNA plugin ensures that the group has a gidNumber that matches the users uidNumber. When the user is removed the group is automatically removed as well. If the managed entries plugin is not available or if a specific, separate range for gidNumber is passed in at install time then User-Private Groups will not be configured. The code checking for the Managed Entries plugin may be removed at some point. This is there because this plugin is only available in a 389-ds alpha release currently (1.2.6-a4).
-rw-r--r--install/share/Makefile.am2
-rw-r--r--install/share/dna-upg.ldif16
-rw-r--r--install/share/user_private_groups.ldif19
-rw-r--r--ipalib/plugins/group.py4
-rw-r--r--ipalib/plugins/user.py26
-rw-r--r--ipaserver/install/dsinstance.py34
-rw-r--r--ipaserver/plugins/ldap2.py37
7 files changed, 119 insertions, 19 deletions
diff --git a/install/share/Makefile.am b/install/share/Makefile.am
index cb7d98367..5ff62baf6 100644
--- a/install/share/Makefile.am
+++ b/install/share/Makefile.am
@@ -31,6 +31,7 @@ app_DATA = \
preferences.html.template \
referint-conf.ldif \
dna-posix.ldif \
+ dna-upg.ldif \
master-entry.ldif \
memberof-task.ldif \
memberof-conf.ldif \
@@ -39,6 +40,7 @@ app_DATA = \
schema_compat.uldif \
ldapi.ldif \
wsgi.py \
+ user_private_groups.ldif \
$(NULL)
EXTRA_DIST = \
diff --git a/install/share/dna-upg.ldif b/install/share/dna-upg.ldif
new file mode 100644
index 000000000..c4edcfaa4
--- /dev/null
+++ b/install/share/dna-upg.ldif
@@ -0,0 +1,16 @@
+# add plugin configuration for user private groups
+
+dn: cn=User Private Groups,cn=Distributed Numeric Assignment Plugin,cn=plugins,cn=config
+changetype: add
+objectclass: top
+objectclass: extensibleObject
+cn: Posix Accounts
+dnaType: uidNumber
+dnaType: gidNumber
+dnaNextValue: eval($UIDSTART+1)
+dnaInterval: 1
+dnaMaxValue: eval($UIDSTART+100000)
+dnaMagicRegen: 999
+dnaFilter: (|(objectclass=posixAccount)(objectClass=posixGroup))
+dnaScope: $SUFFIX
+
diff --git a/install/share/user_private_groups.ldif b/install/share/user_private_groups.ldif
new file mode 100644
index 000000000..070d6e020
--- /dev/null
+++ b/install/share/user_private_groups.ldif
@@ -0,0 +1,19 @@
+dn: cn=UPG Template,$SUFFIX
+changetype: add
+objectclass: mepTemplateEntry
+cn: UPG Template
+mepRDNAttr: cn
+mepStaticAttr: objectclass: posixGroup
+mepMappedAttr: cn: $$uid
+mepMappedAttr: gidNumber: $$uidNumber
+mepMappedAttr: description: User private group for $$uid
+
+dn: cn=UPG Definition,cn=Managed Entries,cn=plugins,cn=config
+changetype: add
+objectclass: extensibleObject
+cn: UPG Definition
+originScope: cn=users,cn=accounts,$SUFFIX
+originFilter: objectclass=posixAccount
+managedBase: cn=groups,cn=accounts,$SUFFIX
+managedTemplate: cn=UPG Template,$SUFFIX
+
diff --git a/ipalib/plugins/group.py b/ipalib/plugins/group.py
index 0f3743784..9da4fe569 100644
--- a/ipalib/plugins/group.py
+++ b/ipalib/plugins/group.py
@@ -145,6 +145,8 @@ class group_add(LDAPCreate):
def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options):
if options['posix'] or 'gidnumber' in options:
entry_attrs['objectclass'].append('posixgroup')
+ if not 'gidnumber' in options:
+ entry_attrs['gidnumber'] = 999
return dn
@@ -200,6 +202,8 @@ class group_mod(LDAPUpdate):
else:
old_entry_attrs['objectclass'].append('posixgroup')
entry_attrs['objectclass'] = old_entry_attrs['objectclass']
+ if not 'gidnumber' in options:
+ entry_attrs['gidnumber'] = 999
return dn
api.register(group_mod)
diff --git a/ipalib/plugins/user.py b/ipalib/plugins/user.py
index d72b3bb1b..610d85a95 100644
--- a/ipalib/plugins/user.py
+++ b/ipalib/plugins/user.py
@@ -122,6 +122,8 @@ class user(LDAPObject):
cli_name='uid',
label=_('UID'),
doc=_('User ID Number (system will assign one if not provided)'),
+ autofill=True,
+ default=999,
),
Str('street?',
cli_name='street',
@@ -169,16 +171,20 @@ class user_add(LDAPCreate):
home_dir = home_dir.replace('//', '/').rstrip('/')
entry_attrs['homedirectory'] = home_dir
- # we're adding new users to a default group, get its gidNumber
- # get default group name from config
- def_primary_group = config.get('ipadefaultprimarygroup')
- group_dn = self.api.Object['group'].get_dn(def_primary_group)
- try:
- (group_dn, group_attrs) = ldap.get_entry(group_dn, ['gidnumber'])
- except errors.NotFound:
- error_msg = 'Default group for new users not found.'
- raise errors.NotFound(reason=error_msg)
- entry_attrs['gidnumber'] = group_attrs['gidnumber']
+ if ldap.has_upg():
+ # User Private Groups - uidNumber == gidNumber
+ entry_attrs['gidnumber'] = entry_attrs['uidnumber']
+ else:
+ # we're adding new users to a default group, get its gidNumber
+ # get default group name from config
+ def_primary_group = config.get('ipadefaultprimarygroup')
+ group_dn = self.api.Object['group'].get_dn(def_primary_group)
+ try:
+ (group_dn, group_attrs) = ldap.get_entry(group_dn, ['gidnumber'])
+ except errors.NotFound:
+ error_msg = 'Default group for new users not found.'
+ raise errors.NotFound(reason=error_msg)
+ entry_attrs['gidnumber'] = group_attrs['gidnumber']
return dn
diff --git a/ipaserver/install/dsinstance.py b/ipaserver/install/dsinstance.py
index 92a8cf003..e1ddef394 100644
--- a/ipaserver/install/dsinstance.py
+++ b/ipaserver/install/dsinstance.py
@@ -38,7 +38,8 @@ from ldap.dn import escape_dn_chars
from ipaserver import ipaldap
from ipaserver.install import ldapupdate
from ipaserver.install import httpinstance
-from ipalib import util, uuid
+from ipalib import util, uuid, errors
+from ipaserver.plugins.ldap2 import ldap2
SERVER_ROOT_64 = "/usr/lib64/dirsrv"
SERVER_ROOT_32 = "/usr/lib/dirsrv"
@@ -114,6 +115,25 @@ def is_ds_running():
ret = False
return ret
+def has_managed_entries(host_name, dm_password):
+ """Check to see if the Managed Entries plugin is available"""
+ ldapuri = 'ldap://%s' % host_name
+ conn = None
+ try:
+ conn = ldap2(shared_instance=False, ldap_uri=ldapuri, base_dn='cn=config')
+ conn.connect(bind_dn='cn=Directory Manager', bind_pw=dm_password)
+ (dn, attrs) = conn.get_entry('cn=Managed Entries,cn=plugins',
+ ['*'])
+ return True
+ except errors.NotFound:
+ return False
+ except errors.ExecutionError, e:
+ logging.critical("Could not connect to the Directory Server on %s" % host_name)
+ raise e
+ finally:
+ if conn:
+ conn.disconnect()
+
INF_TEMPLATE = """
[General]
@@ -179,6 +199,8 @@ class DsInstance(service.Service):
self.step("enabling memberof plugin", self.__add_memberof_module)
self.step("enabling referential integrity plugin", self.__add_referint_module)
self.step("enabling winsync plugin", self.__add_winsync_module)
+ if self.uidstart == self.gidstart:
+ self.step("configuring user private groups", self.__user_private_groups)
self.step("configuring replication version plugin", self.__config_version_module)
self.step("enabling IPA enrollment plugin", self.__add_enrollment_module)
self.step("enabling ldapi", self.__enable_ldapi)
@@ -331,7 +353,11 @@ class DsInstance(service.Service):
self._ldap_mod("unique-attributes.ldif", self.sub_dict)
def __config_uidgid_gen_first_master(self):
- self._ldap_mod("dna-posix.ldif", self.sub_dict)
+ if (self.uidstart == self.gidstart and
+ has_managed_entries(self.host_name, self.dm_password)):
+ self._ldap_mod("dna-upg.ldif", self.sub_dict)
+ else:
+ self._ldap_mod("dna-posix.ldif", self.sub_dict)
def __add_master_entry_first_master(self):
self._ldap_mod("master-entry.ldif", self.sub_dict)
@@ -342,6 +368,10 @@ class DsInstance(service.Service):
def __config_version_module(self):
self._ldap_mod("ipa-version-conf.ldif")
+ def __user_private_groups(self):
+ if has_managed_entries(self.host_name, self.dm_password):
+ self._ldap_mod("user_private_groups.ldif", self.sub_dict)
+
def __add_enrollment_module(self):
self._ldap_mod("enrollment-conf.ldif", self.sub_dict)
diff --git a/ipaserver/plugins/ldap2.py b/ipaserver/plugins/ldap2.py
index d1c083f20..987203caa 100644
--- a/ipaserver/plugins/ldap2.py
+++ b/ipaserver/plugins/ldap2.py
@@ -103,9 +103,12 @@ def _handle_errors(e, **kw):
raise errors.DatabaseError(desc=desc, info=info)
-def load_schema(url):
+def global_init(url):
"""
- Retrieve the LDAP schema from the provided url.
+ Perform global initialization when the module is loaded.
+
+ Retrieve the LDAP schema from the provided url and determine if
+ User-Private Groups (upg) are configured.
Bind using kerberos credentials. If in the context of the
in-tree "lite" server then use the current ccache. If in the context of
@@ -113,10 +116,11 @@ def load_schema(url):
principal.
"""
tmpdir = None
+ upg = False
if not api.env.in_server or api.env.context not in ['lite', 'server']:
# The schema is only needed on the server side
- return
+ return (None, None)
try:
if api.env.context == 'server':
@@ -139,9 +143,17 @@ def load_schema(url):
'cn=schema', _ldap.SCOPE_BASE,
attrlist=['attributetypes', 'objectclasses']
)[0]
+ try:
+ upg_entry = conn.search_s(
+ 'cn=UPG Template, %s' % api.env.basedn, _ldap.SCOPE_BASE,
+ attrlist=['*']
+ )[0]
+ upg = True
+ except _ldap.NO_SUCH_OBJECT, e:
+ upg = False
conn.unbind_s()
except _ldap.SERVER_DOWN:
- return None
+ return (None, upg)
except _ldap.LDAPError, e:
# TODO: raise a more appropriate exception
_handle_errors(e, **{})
@@ -154,13 +166,14 @@ def load_schema(url):
if tmpdir:
shutil.rmtree(tmpdir)
- return _ldap.schema.SubSchema(schema_entry[1])
+ return (_ldap.schema.SubSchema(schema_entry[1]), upg)
-# cache schema when importing module
+# cache schema and User-Private Groups when importing module
try:
- _schema = load_schema(api.env.ldap_uri)
+ (_schema, _upg) = global_init(api.env.ldap_uri)
except AttributeError:
_schema = None
+ _upg = None
def get_syntax(attr, value):
@@ -524,6 +537,16 @@ class ldap2(CrudBackend, Encoder):
"""Returns a copy of the current LDAP schema."""
return copy.deepcopy(self.schema)
+ def has_upg(self):
+ """Returns True/False whether User-Private Groups are enabled.
+ This is determined based on whether the UPG Template exists.
+ We determine this at module load so we don't have to test for
+ it every time.
+ """
+ global _upg
+
+ return _upg
+
@encode_args(1, 2)
def get_effective_rights(self, dn, entry_attrs):
"""Returns the rights the currently bound user has for the given DN.