def convert_nsaccountlock(entry_attrs): if 'nsaccountlock' not in entry_attrs: entry_attrs['nsaccountlock'] = False else: nsaccountlock = Bool('temp') entry_attrs['nsaccountlock'] = nsaccountlock.convert( entry_attrs['nsaccountlock'][0])
class userstatus(LDAPObject): parent_object = 'user' takes_params = ( Bool( 'preserved?', label=_('Preserved user'), flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ), Str( 'server', label=_('Server'), flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ), Str( 'krbloginfailedcount', label=_('Failed logins'), flags={'no_create', 'no_update', 'no_search'}, ), Str( 'krblastsuccessfulauth', label=_('Last successful authentication'), flags={'no_create', 'no_update', 'no_search'}, ), Str( 'krblastfailedauth', label=_('Last failed authentication'), flags={'no_create', 'no_update', 'no_search'}, ), Str( 'now', label=_('Time now'), flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ), )
class user(LDAPObject): """ User object. """ container_dn = api.env.container_user object_name = _('user') object_name_plural = _('users') object_class = ['posixaccount'] object_class_config = 'ipauserobjectclasses' possible_objectclasses = ['meporiginentry'] disallow_object_classes = ['krbticketpolicyaux'] search_attributes_config = 'ipausersearchfields' default_attributes = [ 'uid', 'givenname', 'sn', 'homedirectory', 'loginshell', 'uidnumber', 'gidnumber', 'mail', 'ou', 'telephonenumber', 'title', 'memberof', 'nsaccountlock', 'memberofindirect', ] search_display_attributes = [ 'uid', 'givenname', 'sn', 'homedirectory', 'loginshell', 'mail', 'telephonenumber', 'title', 'nsaccountlock', 'uidnumber', 'gidnumber', 'sshpubkeyfp', ] uuid_attribute = 'ipauniqueid' attribute_members = { 'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], 'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'], } rdn_is_primary_key = True bindable = True password_attributes = [('userpassword', 'has_password'), ('krbprincipalkey', 'has_keytab')] label = _('Users') label_singular = _('User') takes_params = ( Str('uid', pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$', pattern_errmsg='may only include letters, numbers, _, -, . and $', maxlength=255, cli_name='login', label=_('User login'), primary_key=True, default_from=lambda givenname, sn: givenname[0] + sn, normalizer=lambda value: value.lower(), ), Str('givenname', cli_name='first', label=_('First name'), ), Str('sn', cli_name='last', label=_('Last name'), ), Str('cn', label=_('Full name'), default_from=lambda givenname, sn: '%s %s' % (givenname, sn), autofill=True, ), Str('displayname?', label=_('Display name'), default_from=lambda givenname, sn: '%s %s' % (givenname, sn), autofill=True, ), Str('initials?', label=_('Initials'), default_from=lambda givenname, sn: '%c%c' % (givenname[0], sn[0]), autofill=True, ), Str('homedirectory?', cli_name='homedir', label=_('Home directory'), ), Str('gecos?', label=_('GECOS field'), default_from=lambda givenname, sn: '%s %s' % (givenname, sn), autofill=True, ), Str('loginshell?', cli_name='shell', label=_('Login shell'), ), Str('krbprincipalname?', validate_principal, cli_name='principal', label=_('Kerberos principal'), default_from=lambda uid: '%s@%s' % (uid.lower(), api.env.realm), autofill=True, flags=['no_update'], normalizer=lambda value: normalize_principal(value), ), Str('mail*', cli_name='email', label=_('Email address'), ), Password('userpassword?', cli_name='password', label=_('Password'), doc=_('Prompt to set the user password'), # FIXME: This is temporary till bug is fixed causing updates to # bomb out via the webUI. exclude='webui', ), Flag('random?', doc=_('Generate a random user password'), flags=('no_search', 'virtual_attribute'), default=False, ), Str('randompassword?', label=_('Random password'), flags=('no_create', 'no_update', 'no_search', 'virtual_attribute'), ), Int('uidnumber', cli_name='uid', label=_('UID'), doc=_('User ID Number (system will assign one if not provided)'), autofill=True, default=DNA_MAGIC, minvalue=1, ), Int('gidnumber', label=_('GID'), doc=_('Group ID Number'), minvalue=1, default=DNA_MAGIC, autofill=True, ), Str('street?', cli_name='street', label=_('Street address'), ), Str('l?', cli_name='city', label=_('City'), ), Str('st?', cli_name='state', label=_('State/Province'), ), Str('postalcode?', label=_('ZIP'), ), Str('telephonenumber*', cli_name='phone', label=_('Telephone Number') ), Str('mobile*', label=_('Mobile Telephone Number') ), Str('pager*', label=_('Pager Number') ), Str('facsimiletelephonenumber*', cli_name='fax', label=_('Fax Number'), ), Str('ou?', cli_name='orgunit', label=_('Org. Unit'), ), Str('title?', label=_('Job Title'), ), Str('manager?', label=_('Manager'), ), Str('carlicense?', label=_('Car License'), ), Bool('nsaccountlock?', label=_('Account disabled'), flags=['no_option'], ), Str('ipasshpubkey*', validate_sshpubkey, cli_name='sshpubkey', label=_('SSH public key'), normalizer=normalize_sshpubkey, csv=True, flags=['no_search'], ), ) def _normalize_and_validate_email(self, email, config=None): if not config: config = self.backend.get_ipa_config()[1] # check if default email domain should be added defaultdomain = config.get('ipadefaultemaildomain', [None])[0] if email: norm_email = [] if not isinstance(email, (list, tuple)): email = [email] for m in email: if isinstance(m, basestring): if '@' not in m and defaultdomain: m = m + u'@' + defaultdomain if not Email(m): raise errors.ValidationError(name='email', error=_('invalid e-mail format: %(email)s') % dict(email=m)) norm_email.append(m) else: if not Email(m): raise errors.ValidationError(name='email', error=_('invalid e-mail format: %(email)s') % dict(email=m)) norm_email.append(m) return norm_email return email def _normalize_manager(self, manager): """ Given a userid verify the user's existence and return the dn. """ if not manager: return None if not isinstance(manager, list): manager = [manager] try: container_dn = DN(self.container_dn, api.env.basedn) for m in xrange(len(manager)): if isinstance(manager[m], DN) and manager[m].endswith(container_dn): continue (dn, entry_attrs) = self.backend.find_entry_by_attr( self.primary_key.name, manager[m], self.object_class, [''], self.container_dn ) manager[m] = dn except errors.NotFound: raise errors.NotFound(reason=_('manager %(manager)s not found') % dict(manager=manager[m])) return manager def _convert_manager(self, entry_attrs, **options): """ Convert a manager dn into a userid """ if options.get('raw', False): return if 'manager' in entry_attrs: for m in xrange(len(entry_attrs['manager'])): entry_attrs['manager'][m] = self.get_primary_key_from_dn(entry_attrs['manager'][m])
class deskprofilerule(LDAPObject): """ Desktop profile object. """ container_dn = None object_name = _('FleetCommander Desktop Profile Rule Map') object_name_plural = _('FleetCommander Desktop Profile Rule Maps') object_class = ['ipaassociation', 'ipadeskprofilerule'] permission_filter_objectclasses = ['ipadeskprofilerule'] default_attributes = [ 'cn', 'ipaenabledflag', 'ipadeskprofiletarget' 'description', 'usercategory', 'hostcategory', 'memberuser', 'memberhost', 'ipadeskprofilepriority', 'seealso', ] uuid_attribute = 'ipauniqueid' rdn_is_primary_key = True attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], } managed_permissions = { 'System: Read FleetCommander Desktop Profile Rule Map': { 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'cn', 'description', 'hostcategory', 'ipaenabledflag', 'ipauniqueid', 'memberhost', 'memberuser', 'seealso', 'usercategory', 'objectclass', 'member', 'ipadeskprofilepriority', 'ipadeskprofiletarget', }, }, 'System: Add FleetCommander Desktop Profile Rule Map': { 'ipapermbindruletype': 'permission', 'ipapermright': {'add'}, 'default_privileges': {'FleetCommander Desktop Profile Administrators'}, }, 'System: Modify FleetCommander Desktop Profile Rule Map': { 'ipapermbindruletype': 'permission', 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'cn', 'ipaenabledflag', 'memberhost', 'memberuser', 'seealso', 'ipadeskprofilepriority', 'ipadeskprofiletarget', }, 'default_privileges': {'FleetCommander Desktop Profile Administrators'}, }, 'System: Remove FleetCommander Desktop Profile Rule Map': { 'ipapermbindruletype': 'permission', 'ipapermright': {'delete'}, 'default_privileges': {'FleetCommander Desktop Profile Administrators'}, }, } label = _('FleetCommander Desktop Profile Rule Map') label_singular = _('FleetCommander Desktop Profile Rule Map') takes_params = ( Str( 'cn', cli_name='name', label=_('Rule name'), primary_key=True, ), Str( 'ipadeskprofiletarget', cli_name='profile', label=_('Desktop profile'), doc=_('Desktop profile associated with the rule'), ), Int( 'ipadeskprofilepriority', cli_name='prio', label=_('Desktop profile priority'), minvalue=1, maxvalue=100000, doc=_('Priority for desktop profile associated with the rule'), ), Str( 'seealso?', cli_name='hbacrule', label=_('HBAC Rule'), doc=_('HBAC Rule that defines the users, groups and hostgroups'), ), StrEnum( 'usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum( 'hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), Str( 'description?', cli_name='desc', label=_('Description'), ), Bool( 'ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), Str( 'memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), ) # Inject constants into the api.env before it is locked down def _on_finalize(self): self.env._merge(**dict(PLUGIN_CONFIG)) self.container_dn = self.env.container_deskprofilerule super(deskprofilerule, self)._on_finalize() def _normalize_seealso(self, seealso): """ Given a HBAC rule name verify its existence and return the dn. """ if not seealso: return None try: dn = DN(seealso) return str(dn) except ValueError: try: entry_attrs = self.backend.find_entry_by_attr( self.api.Object['hbacrule'].primary_key.name, seealso, self.api.Object['hbacrule'].object_class, [''], DN(self.api.Object['hbacrule'].container_dn, api.env.basedn)) seealso = entry_attrs.dn except errors.NotFound: raise errors.NotFound( reason=_('HBAC rule %(rule)s not found') % dict(rule=seealso)) return seealso def _convert_seealso(self, ldap, entry_attrs, **options): """ Convert an HBAC rule dn into a name """ if options.get('raw', False): return if 'seealso' in entry_attrs: hbac_attrs = ldap.get_entry(entry_attrs['seealso'][0], ['cn']) entry_attrs['seealso'] = hbac_attrs['cn'][0] def _normalize_profile(self, profile): """ Given a Desktop Profile name verify its existence and return the dn. """ if not profile: return None try: dn = DN(profile) return str(dn) except ValueError: try: entry_attrs = self.backend.find_entry_by_attr( self.api.Object['deskprofile'].primary_key.name, profile, self.api.Object['deskprofile'].object_class, [''], DN(self.api.Object['deskprofile'].container_dn, api.env.basedn)) return entry_attrs.dn except errors.NotFound: raise errors.NotFound( reason=_('Desktop profile %(rule)s not found') % dict(rule=profile)) def _convert_profile(self, ldap, entry_attrs, **options): """ Convert an Desktop Profile dn into a name """ if options.get('raw', False): return if 'ipadeskprofiletarget' in entry_attrs: profile_attrs = ldap.get_entry( entry_attrs['ipadeskprofiletarget'][0], ['cn']) entry_attrs['ipadeskprofiletarget'] = profile_attrs['cn'][0]
class hbacrule(LDAPObject): """ HBAC object. """ container_dn = api.env.container_hbac object_name = _('HBAC rule') object_name_plural = _('HBAC rules') object_class = ['ipaassociation', 'ipahbacrule'] permission_filter_objectclasses = ['ipahbacrule'] default_attributes = [ 'cn', 'ipaenabledflag', 'description', 'usercategory', 'hostcategory', 'servicecategory', 'ipaenabledflag', 'memberuser', 'sourcehost', 'memberhost', 'memberservice', 'externalhost', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' allow_rename = True attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], 'sourcehost': ['host', 'hostgroup'], 'memberservice': ['hbacsvc', 'hbacsvcgroup'], } managed_permissions = { 'System: Read HBAC Rules': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'accessruletype', 'accesstime', 'cn', 'description', 'externalhost', 'hostcategory', 'ipaenabledflag', 'ipauniqueid', 'memberhost', 'memberservice', 'memberuser', 'servicecategory', 'sourcehost', 'sourcehostcategory', 'usercategory', 'objectclass', 'member', }, }, 'System: Add HBAC Rule': { 'ipapermright': {'add'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Add HBAC rule";allow (add) groupdn = "ldap:///cn=Add HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'HBAC Administrator'}, }, 'System: Delete HBAC Rule': { 'ipapermright': {'delete'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Delete HBAC rule";allow (delete) groupdn = "ldap:///cn=Delete HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'HBAC Administrator'}, }, 'System: Manage HBAC Rule Membership': { 'ipapermright': {'write'}, 'ipapermdefaultattr': {'externalhost', 'memberhost', 'memberservice', 'memberuser'}, 'replaces': [ '(targetattr = "memberuser || externalhost || memberservice || memberhost")(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Manage HBAC rule membership";allow (write) groupdn = "ldap:///cn=Manage HBAC rule membership,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'HBAC Administrator'}, }, 'System: Modify HBAC Rule': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'accessruletype', 'accesstime', 'cn', 'description', 'hostcategory', 'ipaenabledflag', 'servicecategory', 'sourcehost', 'sourcehostcategory', 'usercategory' }, 'replaces': [ '(targetattr = "servicecategory || sourcehostcategory || cn || description || ipaenabledflag || accesstime || usercategory || hostcategory || accessruletype || sourcehost")(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Modify HBAC rule";allow (write) groupdn = "ldap:///cn=Modify HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'HBAC Administrator'}, }, } label = _('HBAC Rules') label_singular = _('HBAC Rule') takes_params = ( Str( 'cn', cli_name='name', label=_('Rule name'), primary_key=True, ), StrEnum( 'accessruletype', validate_type, cli_name='type', doc=_('Rule type (allow)'), label=_('Rule type'), values=(u'allow', u'deny'), default=u'allow', autofill=True, exclude='webui', flags=['no_option', 'no_output'], ), # FIXME: {user,host,service}categories should expand in the future StrEnum( 'usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum( 'hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), StrEnum( 'sourcehostcategory?', deprecated=True, cli_name='srchostcat', label=_('Source host category'), doc=_('Source host category the rule applies to'), values=(u'all', ), flags={'no_option'}, ), StrEnum( 'servicecategory?', cli_name='servicecat', label=_('Service category'), doc=_('Service category the rule applies to'), values=(u'all', ), ), # AccessTime('accesstime?', # cli_name='time', # label=_('Access time'), # ), Str( 'description?', cli_name='desc', label=_('Description'), ), Bool( 'ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), Str( 'memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'sourcehost_host?', deprecated=True, label=_('Source Hosts'), flags=['no_create', 'no_update', 'no_search', 'no_option'], ), Str( 'sourcehost_hostgroup?', deprecated=True, label=_('Source Host Groups'), flags=['no_create', 'no_update', 'no_search', 'no_option'], ), Str( 'memberservice_hbacsvc?', label=_('Services'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberservice_hbacsvcgroup?', label=_('Service Groups'), flags=['no_create', 'no_update', 'no_search'], ), external_host_param, )
class fasagreement(LDAPObject): """User Agreement object for FAS""" container_dn = DN(("cn", "fasagreements")) object_name = _("Agreement") object_name_plural = _("Agreements") object_class = ["ipaassociation", "fasagreement"] permission_filter_objectclasses = ["fasagreement"] default_attributes = [ "cn", "description", "ipaenabledflag", "member", "memberuser", ] uuid_attribute = "ipauniqueid" attribute_members = { "memberuser": ["user"], "member": ["group"], } allow_rename = True managed_permissions = { "System: Read FAS Agreements": { "replaces_global_anonymous_aci": True, "ipapermbindruletype": "all", "ipapermright": {"read", "search", "compare"}, "ipapermdefaultattr": { "objectclass", "cn", "description", "ipauniqueid", "ipaenabledflag", "member", "memberuser", }, }, "System: Add FAS Agreement": { "ipapermright": {"add"}, "default_privileges": {"FAS Agreement Administrators"}, }, "System: Delete FAS Agreement": { "ipapermright": {"delete"}, "default_privileges": {"FAS Agreement Administrators"}, }, "System: Manage FAS Agreement user membership": { "ipapermright": {"write"}, "ipapermdefaultattr": {"memberUser"}, "default_privileges": {"FAS Agreement Administrators"}, }, "System: Modify FAS Agreement": { "ipapermright": {"write"}, "ipapermdefaultattr": { "cn", "description", "ipaenabledflag", "member", }, "default_privileges": {"FAS Agreement Administrators"}, }, } label = _("User Agreements") label_singular = _("User Agreement") takes_params = ( Str( "cn", cli_name="name", label=_("Agreement name"), primary_key=True, ), Str( "description?", cli_name="desc", label=_("Agreement Description"), ), Bool( "ipaenabledflag?", label=_("Enabled"), flags=["no_option"], ), )
class config(LDAPObject): """ IPA configuration object """ object_name = _('configuration options') default_attributes = [ 'ipamaxusernamelength', 'ipahomesrootdir', 'ipadefaultloginshell', 'ipadefaultprimarygroup', 'ipadefaultemaildomain', 'ipasearchtimelimit', 'ipasearchrecordslimit', 'ipausersearchfields', 'ipagroupsearchfields', 'ipamigrationenabled', 'ipacertificatesubjectbase', 'ipapwdexpadvnotify', 'ipaselinuxusermaporder', 'ipaselinuxusermapdefault', 'ipaconfigstring', 'ipakrbauthzdata', 'ipauserauthtype', 'ipadomainresolutionorder' ] container_dn = DN(('cn', 'ipaconfig'), ('cn', 'etc')) permission_filter_objectclasses = ['ipaguiconfig'] managed_permissions = { 'System: Read Global Configuration': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'cn', 'objectclass', 'ipacertificatesubjectbase', 'ipaconfigstring', 'ipadefaultemaildomain', 'ipadefaultloginshell', 'ipadefaultprimarygroup', 'ipadomainresolutionorder', 'ipagroupobjectclasses', 'ipagroupsearchfields', 'ipahomesrootdir', 'ipakrbauthzdata', 'ipamaxusernamelength', 'ipamigrationenabled', 'ipapwdexpadvnotify', 'ipaselinuxusermapdefault', 'ipaselinuxusermaporder', 'ipasearchrecordslimit', 'ipasearchtimelimit', 'ipauserauthtype', 'ipauserobjectclasses', 'ipausersearchfields', 'ipacustomfields', }, }, } label = _('Configuration') label_singular = _('Configuration') takes_params = ( Int('ipamaxusernamelength', cli_name='maxusername', label=_('Maximum username length'), minvalue=1, maxvalue=255, ), IA5Str('ipahomesrootdir', cli_name='homedirectory', label=_('Home directory base'), doc=_('Default location of home directories'), ), Str('ipadefaultloginshell', cli_name='defaultshell', label=_('Default shell'), doc=_('Default shell for new users'), ), Str('ipadefaultprimarygroup', cli_name='defaultgroup', label=_('Default users group'), doc=_('Default group for new users'), ), Str('ipadefaultemaildomain?', cli_name='emaildomain', label=_('Default e-mail domain'), doc=_('Default e-mail domain'), ), Int('ipasearchtimelimit', cli_name='searchtimelimit', label=_('Search time limit'), doc=_('Maximum amount of time (seconds) for a search (-1 or 0 is unlimited)'), minvalue=-1, ), Int('ipasearchrecordslimit', cli_name='searchrecordslimit', label=_('Search size limit'), doc=_('Maximum number of records to search (-1 or 0 is unlimited)'), minvalue=-1, ), IA5Str('ipausersearchfields', cli_name='usersearch', label=_('User search fields'), doc=_('A comma-separated list of fields to search in when searching for users'), ), IA5Str('ipagroupsearchfields', cli_name='groupsearch', label=_('Group search fields'), doc=_('A comma-separated list of fields to search in when searching for groups'), ), Bool('ipamigrationenabled', cli_name='enable_migration', label=_('Enable migration mode'), doc=_('Enable migration mode'), ), DNParam('ipacertificatesubjectbase', cli_name='subject', label=_('Certificate Subject base'), doc=_('Base for certificate subjects (OU=Test,O=Example)'), flags=['no_update'], ), Str('ipagroupobjectclasses+', cli_name='groupobjectclasses', label=_('Default group objectclasses'), doc=_('Default group objectclasses (comma-separated list)'), ), Str('ipauserobjectclasses+', cli_name='userobjectclasses', label=_('Default user objectclasses'), doc=_('Default user objectclasses (comma-separated list)'), ), Int('ipapwdexpadvnotify', cli_name='pwdexpnotify', label=_('Password Expiration Notification (days)'), doc=_('Number of days\'s notice of impending password expiration'), minvalue=0, ), StrEnum('ipaconfigstring*', cli_name='ipaconfigstring', label=_('Password plugin features'), doc=_('Extra hashes to generate in password plug-in'), values=(u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout', u'KDC:Disable Default Preauth for SPNs'), ), Str('ipaselinuxusermaporder', label=_('SELinux user map order'), doc=_('Order in increasing priority of SELinux users, delimited by $'), ), Str('ipaselinuxusermapdefault?', label=_('Default SELinux user'), doc=_('Default SELinux user when no match is found in SELinux map rule'), ), StrEnum('ipakrbauthzdata*', cli_name='pac_type', label=_('Default PAC types'), doc=_('Default types of PAC supported for services'), values=(u'MS-PAC', u'PAD', u'nfs:NONE'), ), StrEnum('ipauserauthtype*', cli_name='user_auth_type', label=_('Default user authentication types'), doc=_('Default types of supported user authentication'), values=(u'password', u'radius', u'otp', u'disabled'), ), Str( 'ipa_master_server*', label=_('IPA masters'), doc=_('List of all IPA masters'), flags={'virtual_attribute', 'no_create', 'no_update'} ), Str( 'ca_server_server*', label=_('IPA CA servers'), doc=_('IPA servers configured as certificate authority'), flags={'virtual_attribute', 'no_create', 'no_update'} ), Str( 'ntp_server_server*', label=_('IPA NTP servers'), doc=_('IPA servers with enabled NTP'), flags={'virtual_attribute', 'no_create', 'no_update'} ), Str( 'ca_renewal_master_server?', label=_('IPA CA renewal master'), doc=_('Renewal master for IPA certificate authority'), flags={'virtual_attribute', 'no_create'} ), Str( 'pkinit_server_server*', label=_('IPA master capable of PKINIT'), doc=_('IPA master which can process PKINIT requests'), flags={'virtual_attribute', 'no_create', 'no_update'} ), Str( 'ipadomainresolutionorder?', cli_name='domain_resolution_order', label=_('Domain resolution order'), doc=_('colon-separated list of domains used for short name' ' qualification') ) ) def get_dn(self, *keys, **kwargs): return DN(('cn', 'ipaconfig'), ('cn', 'etc'), api.env.basedn) def update_entry_with_role_config(self, role_name, entry_attrs): backend = self.api.Backend.serverroles try: role_config = backend.config_retrieve(role_name) except errors.EmptyResult: # No role config means current user identity # has no rights to see it, return with no action return for key, value in role_config.items(): try: entry_attrs.update({key: value}) except errors.EmptyResult: # An update that doesn't change an entry is fine here # Just ignore and move to the next key pair pass def show_servroles_attributes(self, entry_attrs, *roles, **options): if options.get('raw', False): return for role in roles: self.update_entry_with_role_config(role, entry_attrs) def gather_trusted_domains(self): """ Aggregate all trusted domains into a dict keyed by domain names with values corresponding to domain status (enabled/disabled) """ command = self.api.Command try: ad_forests = command.trust_find(sizelimit=0)['result'] except errors.NotFound: return {} trusted_domains = {} for forest_name in [a['cn'][0] for a in ad_forests]: forest_domains = command.trustdomain_find( forest_name, sizelimit=0)['result'] trusted_domains.update( { dom['cn'][0]: dom['domain_enabled'][0] for dom in forest_domains if 'domain_enabled' in dom } ) return trusted_domains def _validate_single_domain(self, attr_name, domain, known_domains): """ Validate a single domain from domain resolution order :param attr_name: name of attribute that holds domain resolution order :param domain: domain name :param known_domains: dict of domains known to IPA keyed by domain name and valued by boolean value corresponding to domain status (enabled/disabled) :raises: ValidationError if the domain name is empty, syntactically invalid or corresponds to a disable domain NotFound if a syntactically correct domain name unknown to IPA is supplied (not IPA domain and not any of trusted domains) """ if not domain: raise errors.ValidationError( name=attr_name, error=_("Empty domain is not allowed") ) try: validate_domain_name(domain) except ValueError as e: raise errors.ValidationError( name=attr_name, error=_("Invalid domain name '%(domain)s': %(e)s") % dict(domain=domain, e=e)) if domain not in known_domains: raise errors.NotFound( reason=_("Server has no information about domain '%(domain)s'") % dict(domain=domain) ) if not known_domains[domain]: raise errors.ValidationError( name=attr_name, error=_("Disabled domain '%(domain)s' is not allowed") % dict(domain=domain) ) def validate_domain_resolution_order(self, entry_attrs): """ Validate domain resolution order, e.g. split by the delimiter (colon) and check each domain name for non-emptiness, syntactic correctness, and status (enabled/disabled). supplying empty order (':') bypasses validations and allows to specify empty attribute value. """ attr_name = 'ipadomainresolutionorder' if attr_name not in entry_attrs: return domain_resolution_order = entry_attrs[attr_name] # setting up an empty string means that the previous configuration has # to be cleaned up/removed. So, do nothing and let it pass if not domain_resolution_order: return # empty resolution order is signalized by single separator, do nothing # and let it pass if domain_resolution_order == DOMAIN_RESOLUTION_ORDER_SEPARATOR: return submitted_domains = domain_resolution_order.split( DOMAIN_RESOLUTION_ORDER_SEPARATOR) known_domains = self.gather_trusted_domains() # add FreeIPA domain to the list of domains. This one is always enabled known_domains.update({self.api.env.domain: True}) for domain in submitted_domains: self._validate_single_domain(attr_name, domain, known_domains)
class stageuser_add(baseuser_add): __doc__ = _('Add a new stage user.') msg_summary = _('Added stage user "%(value)s"') has_output_params = baseuser_add.has_output_params + stageuser_output_params takes_options = LDAPCreate.takes_options + (Bool( 'from_delete?', deprecated=True, doc=_('Create Stage user in from a delete user'), cli_name='from_delete', flags={'no_option'}, ), ) def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys, **options): assert isinstance(dn, DN) # then givenname and sn are required attributes if 'givenname' not in entry_attrs: raise errors.RequirementError(name='givenname', error=_('givenname is required')) if 'sn' not in entry_attrs: raise errors.RequirementError(name='sn', error=_('sn is required')) # we don't want an user private group to be created for this user # add NO_UPG_MAGIC description attribute to let the DS plugin know entry_attrs.setdefault('description', []) entry_attrs['description'].append(NO_UPG_MAGIC) # uidNumber/gidNumber entry_attrs.setdefault('uidnumber', baseldap.DNA_MAGIC) entry_attrs.setdefault('gidnumber', baseldap.DNA_MAGIC) if not client_has_capability(options['version'], 'optional_uid_params'): # https://fedorahosted.org/freeipa/ticket/2886 # Old clients say 999 (OLD_DNA_MAGIC) when they really mean # "assign a value dynamically". OLD_DNA_MAGIC = 999 if entry_attrs.get('uidnumber') == OLD_DNA_MAGIC: entry_attrs['uidnumber'] = baseldap.DNA_MAGIC if entry_attrs.get('gidnumber') == OLD_DNA_MAGIC: entry_attrs['gidnumber'] = baseldap.DNA_MAGIC # Check the lenght of the RDN (uid) value config = ldap.get_ipa_config() if 'ipamaxusernamelength' in config: if len(keys[-1]) > int(config.get('ipamaxusernamelength')[0]): raise errors.ValidationError( name=self.obj.primary_key.cli_name, error=_('can be at most %(len)d characters') % dict(len=int(config.get('ipamaxusernamelength')[0]))) default_shell = config.get('ipadefaultloginshell', [platformconstants.DEFAULT_SHELL])[0] entry_attrs.setdefault('loginshell', default_shell) # hack so we can request separate first and last name in CLI full_name = '%s %s' % (entry_attrs['givenname'], entry_attrs['sn']) entry_attrs.setdefault('cn', full_name) # Homedirectory # (order is : option, placeholder (TBD), CLI default value (here in config)) if 'homedirectory' not in entry_attrs: # get home's root directory from config homes_root = config.get('ipahomesrootdir', [paths.HOME_DIR])[0] # build user's home directory based on his uid entry_attrs['homedirectory'] = posixpath.join(homes_root, keys[-1]) # Kerberos principal entry_attrs.setdefault('krbprincipalname', '%s@%s' % (entry_attrs['uid'], api.env.realm)) # If requested, generate a userpassword if 'userpassword' not in entry_attrs and options.get('random'): entry_attrs['userpassword'] = ipa_generate_password( entropy_bits=TMP_PWD_ENTROPY_BITS) # save the password so it can be displayed in post_callback setattr(context, 'randompassword', entry_attrs['userpassword']) # Check the email or create it if 'mail' in entry_attrs: entry_attrs['mail'] = self.obj.normalize_and_validate_email( entry_attrs['mail'], config) else: # No e-mail passed in. If we have a default e-mail domain set # then we'll add it automatically. defaultdomain = config.get('ipadefaultemaildomain', [None])[0] if defaultdomain: entry_attrs['mail'] = self.obj.normalize_and_validate_email( keys[-1], config) # If the manager is defined, check it is a ACTIVE user to validate it if 'manager' in entry_attrs: entry_attrs['manager'] = self.obj.normalize_manager( entry_attrs['manager'], self.obj.active_container_dn) if ('objectclass' in entry_attrs and 'userclass' in entry_attrs and 'ipauser' not in entry_attrs['objectclass']): entry_attrs['objectclass'].append('ipauser') if 'ipatokenradiusconfiglink' in entry_attrs: cl = entry_attrs['ipatokenradiusconfiglink'] if cl: if 'objectclass' not in entry_attrs: _entry = ldap.get_entry(dn, ['objectclass']) entry_attrs['objectclass'] = _entry['objectclass'] if 'ipatokenradiusproxyuser' not in entry_attrs['objectclass']: entry_attrs['objectclass'].append( 'ipatokenradiusproxyuser') answer = self.api.Object['radiusproxy'].get_dn_if_exists(cl) entry_attrs['ipatokenradiusconfiglink'] = answer self.pre_common_callback(ldap, dn, entry_attrs, attrs_list, *keys, **options) return dn def post_callback(self, ldap, dn, entry_attrs, *keys, **options): assert isinstance(dn, DN) # Fetch the entry again to update memberof, mep data, etc updated # at the end of the transaction. newentry = ldap.get_entry(dn, ['*']) entry_attrs.update(newentry) if options.get('random', False): try: entry_attrs['randompassword'] = unicode( getattr(context, 'randompassword')) except AttributeError: # if both randompassword and userpassword options were used pass self.post_common_callback(ldap, dn, entry_attrs, *keys, **options) return dn
), Str('ipaallowedtoperform_write_keys_hostgroup', label=_('Host Groups allowed to create keytab'), ), Str('ipaallowedtoperform_read_keys', label=_('Failed allowed to retrieve keytab'), ), Str('ipaallowedtoperform_write_keys', label=_('Failed allowed to create keytab'), ), ) ticket_flags_params = ( Bool('ipakrbrequirespreauth?', cli_name='requires_pre_auth', label=_('Requires pre-authentication'), doc=_('Pre-authentication is required for the service'), flags=['virtual_attribute', 'no_search'], ), Bool('ipakrbokasdelegate?', cli_name='ok_as_delegate', label=_('Trusted for delegation'), doc=_('Client credentials may be delegated to the service'), flags=['virtual_attribute', 'no_search'], ), Bool('ipakrboktoauthasdelegate?', cli_name='ok_to_auth_as_delegate', label=_('Trusted to authenticate as user'), doc=_('The service is allowed to authenticate on behalf of a client'), flags=['virtual_attribute', 'no_search'], ), )
class aii_find(Command): # class name has to be lowercase """aii_find command""" takes_options = ( Bool( 'detail', default=False, required=False, autofill=True, doc='Show details', ), Bool( 'all', default=False, required=False, autofill=True, doc='Use --all option (implies detail)', ), Bool( 'raw', default=False, required=False, autofill=True, doc='Use --all --raw option (implies detail)', ), Str( 'hostname', default=None, required=False, autofill=True, doc='Check this host (ignores hostregex)', ), Str( 'hostregex', default=None, required=False, autofill=True, doc='Show host(s) matching this regex (might be slow)', ), ) def run(self, **options): """ Show all hosts with no keytab, filtered with hostregex Implemented as frontend command (ie no forward/execute) """ opts = {} opts['raw'] = options.get('raw', False) opts['all'] = options.get('all', False) or opts['raw'] self.log.debug('Options all %s raw %s' % (opts['all'], opts['raw'])) reg = None if 'hostname' in options: opts['fqdn'] = options['hostname'] self.log.debug('Set hostname %s' % opts['fqdn']) elif 'hostregex' in options: reg = re.compile(r'' + options.get('hostregex')) self.log.debug('Using regexp pattern %s' % reg.pattern) found = self.Command.host_find(**opts) res = {'fqdns': [], 'details': {}} detail = options.get('detail', False) or opts['all'] # already deals with raw if 'result' in found and len(found['result']): for host in found['result']: fqdns = host.pop('fqdn') # this is a tuple! self.log.debug('host fqdns found %s ' % (fqdns)) for fqdn in fqdns: if (reg is not None) and (not reg.search(fqdn)): continue res['fqdns'].append(fqdn) if detail: res['details'][fqdn] = host else: self.log.debug('No results from host_find') # sort the hostnames before returning them res['fqdns'].sort() return dict(result=res) def output_for_cli(self, textui, result, **options): detail = options.get('detail', False) or options.get( 'all', False) or options.get('raw', False) fqdns = result['result']['fqdns'] if detail: # print per host details for fqdn in fqdns: textui.print_plain("Hostname %s" % (fqdn)) details = result['result']['details'][fqdn].items() details.sort(key=lambda x: x[0]) textui.print_keyval(details) else: # print list of hostnames textui.print_plain(" ".join(fqdns))
class aii(Command): # class name has to be lowercase """aii command""" takes_args = ('shorthostname', 'domain') takes_options = ( Bool( 'install', default=False, required=False, autofill=True, doc='Prepare for installation, returns random OTP', ), Bool( 'disable', default=False, required=False, autofill=True, doc='Disable the host in IPA', ), Str('ip', default=None, required=False, autofill=True, doc= 'Set the IP (implies DNS configuration; don\'t use it if DNS is not enabled/wanted)' ), ) def __init__(self, *args, **kwargs): """Customise the __init__ a bit""" super(aii, self).__init__(*args, **kwargs) self.fqdns = None def find_fqdns(self): """Update list of hosts""" res = self.Command.host_find() self.fqdns = {} for host in res['result']: for fqdn in host['fqdn']: self.fqdns[fqdn] = host self.log.debug('Found fqdns %s' % self.fqdns) self.log.debug('Found fqdns %s' % ', '.join(self.fqdns.keys())) return self.fqdns def host_in_ipa(self, hostname, force_fqdn=False): """Check if hostname is known in IPA""" if self.fqdns is None or force_fqdn: self.find_fqdns() res = hostname in self.fqdns if res: host = self.fqdns[hostname] self.log.debug( 'host %s found in IPA (has_password %s; has_keytab %s)' % (hostname, host['has_password'], host['has_keytab'])) else: self.log.debug('host %s NOT found in IPA' % (hostname)) return res def disable_host(self, hostname): """Disable the host (removes keytab)""" res = {} if self.host_in_ipa(hostname): try: disable = api.Command.host_disable(hostname) res['disable'] = disable['result'] self.log.debug('host_disable on %s OK.' % hostname) except AlreadyInactive: self.log.debug('Host %s already inactive.' % hostname) else: self.log.debug('No need to disable unknown host %s.' % s) self.log.info('Host %s disabled.' % hostname) return res def aii_install(self, hostname): """Take action to allow proper installation""" res = {} do_add = True if self.host_in_ipa(hostname): host = self.fqdns[hostname] if host['has_keytab']: self.log.error( 'Can\'t install host %s, already in IPA (disable first?)' % hostname) raise AlreadyActive else: self.log.debug('Host %s in IPA, but no keytab' % hostname) do_add = False if do_add: self.log.debug('host_add %s' % hostname) added = api.Command.host_add(hostname) res['add'] = added['result'] # modify to set random password self.log.debug('host_mod %s random password' % hostname) # do not print/log res, it contains a password modified = api.Command.host_mod(hostname, random=True) res['modify'] = modified['result'] return res def run(self, shorthostname, domain, **options): """ Implemented as frontend command (ie no forward/execute) """ hostname = unicode("%s.%s" % (shorthostname, domain)) self.log.debug('AII called with hostname %s (options %s)' % (hostname, options)) ip = options.get('ip', None) res = {} # first try to disable (e.g. in case --install=1 --disable=1 is passed) if options.get('disable', False): self.log.debug('Going to disable') res.update(self.disable_host(hostname)) # check for install if options.get('install', False): self.log.debug('Going to install') if ip is not None: self.log.debug('Adding ip %s for hostname %s' % (ip, hostname)) add_records_for_host(shorthostname, domain, [ip]) # do not print/log res, it contains a password res.update(self.aii_install(hostname)) # always return like this return dict(result=res) def output_for_cli(self, textui, result, shorthostname, domain, **options): if options.get('install', False) and 'modify' in result[ 'result'] and 'randompassword' in result['result']['modify']: # use pop to remove it (eg in case we use it for logging) textui.print_plain( 'randompassword = %s' % (result['result']['modify'].pop('randompassword'))) textui.print_plain('%s.%s = %r (options %s)' % (shorthostname, domain, result, options))
class pwpolicy(LDAPObject): """ Password Policy object """ container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos')) object_name = _('password policy') object_name_plural = _('password policies') object_class = ['top', 'nscontainer', 'krbpwdpolicy', 'ipapwdpolicy'] permission_filter_objectclasses = ['krbpwdpolicy', 'ipapwdpolicy'] default_attributes = [ 'cn', 'cospriority', 'krbmaxpwdlife', 'krbminpwdlife', 'krbpwdhistorylength', 'krbpwdmindiffchars', 'krbpwdminlength', 'krbpwdmaxfailure', 'krbpwdfailurecountinterval', 'krbpwdlockoutduration', 'ipapwdmaxrepeat', 'ipapwdmaxsequence', 'ipapwddictcheck', 'ipapwdusercheck', ] managed_permissions = { 'System: Read Group Password Policy': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'permission', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'cn', 'cospriority', 'krbmaxpwdlife', 'krbminpwdlife', 'krbpwdfailurecountinterval', 'krbpwdhistorylength', 'krbpwdlockoutduration', 'krbpwdmaxfailure', 'krbpwdmindiffchars', 'krbpwdminlength', 'objectclass', 'ipapwdmaxrepeat', 'ipapwdmaxsequence', 'ipapwddictcheck', 'ipapwdusercheck', }, 'default_privileges': { 'Password Policy Readers', 'Password Policy Administrator', }, }, 'System: Add Group Password Policy': { 'ipapermright': {'add'}, 'replaces': [ '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Add Group Password Policy";allow (add) groupdn = "ldap:///cn=Add Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'Password Policy Administrator'}, }, 'System: Delete Group Password Policy': { 'ipapermright': {'delete'}, 'replaces': [ '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Delete Group Password Policy";allow (delete) groupdn = "ldap:///cn=Delete Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'Password Policy Administrator'}, }, 'System: Modify Group Password Policy': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'krbmaxpwdlife', 'krbminpwdlife', 'krbpwdfailurecountinterval', 'krbpwdhistorylength', 'krbpwdlockoutduration', 'krbpwdmaxfailure', 'krbpwdmindiffchars', 'krbpwdminlength', 'ipapwdmaxrepeat', 'ipapwdmaxsequence', 'ipapwddictcheck', 'ipapwdusercheck', }, 'replaces': [ '(targetattr = "krbmaxpwdlife || krbminpwdlife || krbpwdhistorylength || krbpwdmindiffchars || krbpwdminlength || krbpwdmaxfailure || krbpwdfailurecountinterval || krbpwdlockoutduration")(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=Modify Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'Password Policy Administrator'}, }, } label = _('Password Policies') label_singular = _('Password Policy') takes_params = ( Str( 'cn?', cli_name='group', label=_('Group'), doc=_('Manage password policy for specific group'), primary_key=True, ), Int( 'krbmaxpwdlife?', cli_name='maxlife', label=_('Max lifetime (days)'), doc=_('Maximum password lifetime (in days)'), minvalue=0, maxvalue=20000, # a little over 54 years ), Int( 'krbminpwdlife?', cli_name='minlife', label=_('Min lifetime (hours)'), doc=_('Minimum password lifetime (in hours)'), minvalue=0, ), Int( 'krbpwdhistorylength?', cli_name='history', label=_('History size'), doc=_('Password history size'), minvalue=0, ), Int( 'krbpwdmindiffchars?', cli_name='minclasses', label=_('Character classes'), doc=_('Minimum number of character classes'), minvalue=0, maxvalue=5, ), Int( 'krbpwdminlength?', cli_name='minlength', label=_('Min length'), doc=_('Minimum length of password'), minvalue=0, ), Int( 'cospriority', cli_name='priority', label=_('Priority'), doc=_( 'Priority of the policy (higher number means lower priority'), minvalue=0, flags=('virtual_attribute', ), ), Int( 'krbpwdmaxfailure?', cli_name='maxfail', label=_('Max failures'), doc=_('Consecutive failures before lockout'), minvalue=0, ), Int( 'krbpwdfailurecountinterval?', cli_name='failinterval', label=_('Failure reset interval'), doc=_('Period after which failure count will be reset (seconds)'), minvalue=0, ), Int( 'krbpwdlockoutduration?', cli_name='lockouttime', label=_('Lockout duration'), doc=_('Period for which lockout is enforced (seconds)'), minvalue=0, ), Int( 'ipapwdmaxrepeat?', cli_name='maxrepeat', label=_('Max repeat'), doc=_('Maximum number of same consecutive characters'), minvalue=0, maxvalue=256, default=0, ), Int( 'ipapwdmaxsequence?', cli_name='maxsequence', label=_('Max sequence'), doc=_('The max. length of monotonic character sequences (abcd)'), minvalue=0, maxvalue=256, default=0, ), Bool( 'ipapwddictcheck?', cli_name='dictcheck', label=_('Dictionary check'), doc=_('Check if the password is a dictionary word'), default=False, ), Bool( 'ipapwdusercheck?', cli_name='usercheck', label=_('User check'), doc=_('Check if the password contains the username'), default=False, ), ) def get_dn(self, *keys, **options): if keys[-1] is not None: return self.backend.make_dn_from_attr( self.primary_key.name, keys[-1], DN(self.container_dn, api.env.basedn)) return global_policy_dn def convert_time_for_output(self, entry_attrs, **options): # Convert seconds to hours and days for displaying to user if not options.get('raw', False): if 'krbmaxpwdlife' in entry_attrs: entry_attrs['krbmaxpwdlife'][0] = unicode( int(entry_attrs['krbmaxpwdlife'][0]) // 86400) if 'krbminpwdlife' in entry_attrs: entry_attrs['krbminpwdlife'][0] = unicode( int(entry_attrs['krbminpwdlife'][0]) // 3600) def convert_time_on_input(self, entry_attrs): # Convert hours and days to seconds for writing to LDAP if 'krbmaxpwdlife' in entry_attrs and entry_attrs['krbmaxpwdlife']: entry_attrs['krbmaxpwdlife'] = entry_attrs['krbmaxpwdlife'] * 86400 if 'krbminpwdlife' in entry_attrs and entry_attrs['krbminpwdlife']: entry_attrs['krbminpwdlife'] = entry_attrs['krbminpwdlife'] * 3600 def validate_minlength(self, ldap, entry_attrs, add=False, *keys): """ If any of the libpwquality options are used then the minimum length must be >= 6 which is the built-in default of libpwquality. Allowing a lower value to be set will result in a failed policy check and a generic error message. """ def get_val(entry, attr): """Get a single value from a list or a string""" val = entry.get(attr, 0) if isinstance(val, list): val = val[0] return val def has_pwquality_set(entry): for attr in [ 'ipapwdmaxrepeat', 'ipapwdmaxsequence', 'ipapwddictcheck', 'ipapwdusercheck' ]: val = get_val(entry, attr) if val not in ('FALSE', '0', 0, None): return True return False has_pwquality_value = False if not add: if len(keys) > 0: existing_entry = self.api.Command.pwpolicy_show( keys[-1], all=True, )['result'] else: existing_entry = self.api.Command.pwpolicy_show( all=True, )['result'] existing_entry.update(entry_attrs) min_length = int(get_val(existing_entry, 'krbpwdminlength')) has_pwquality_value = has_pwquality_set(existing_entry) else: min_length = int(get_val(entry_attrs, 'krbpwdminlength')) has_pwquality_value = has_pwquality_set(entry_attrs) if min_length and min_length < 6 and has_pwquality_value: raise errors.ValidationError( name='minlength', error=_('Minimum length must be >= 6 if maxrepeat, ' 'maxsequence, dictcheck or usercheck are defined')) def validate_lifetime(self, entry_attrs, add=False, *keys): """ Ensure that the maximum lifetime is greater than the minimum. If there is no minimum lifetime set then don't return an error. """ maxlife = entry_attrs.get('krbmaxpwdlife', None) minlife = entry_attrs.get('krbminpwdlife', None) existing_entry = {} if not add: # then read existing entry existing_entry = self.api.Command.pwpolicy_show( keys[-1], all=True, )['result'] if minlife is None and 'krbminpwdlife' in existing_entry: minlife = int(existing_entry['krbminpwdlife'][0]) * 3600 if maxlife is None and 'krbmaxpwdlife' in existing_entry: maxlife = int(existing_entry['krbmaxpwdlife'][0]) * 86400 if maxlife not in (None, 0) and minlife is not None: if minlife > maxlife: raise errors.ValidationError( name='maxlife', error=_("Maximum password life must be equal to " "or greater than the minimum."), ) def add_cospriority(self, entry, pwpolicy_name, rights=True): if pwpolicy_name and pwpolicy_name != global_policy_name: cos_entry = self.api.Command.cosentry_show(pwpolicy_name, rights=rights, all=rights)['result'] if cos_entry.get('cospriority') is not None: entry['cospriority'] = cos_entry['cospriority'] if rights: entry['attributelevelrights']['cospriority'] = \ cos_entry['attributelevelrights']['cospriority']
class hbacrule(LDAPObject): """ HBAC object. """ container_dn = api.env.container_hbac object_name = _('HBAC rule') object_name_plural = _('HBAC rules') object_class = ['ipaassociation', 'ipahbacrule'] default_attributes = [ 'cn', 'ipaenabledflag', 'description', 'usercategory', 'hostcategory', 'sourcehostcategory', 'servicecategory', 'ipaenabledflag', 'memberuser', 'sourcehost', 'memberhost', 'memberservice', 'memberhostgroup', 'externalhost', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], 'sourcehost': ['host', 'hostgroup'], 'memberservice': ['hbacsvc', 'hbacsvcgroup'], } label = _('HBAC Rules') label_singular = _('HBAC Rule') takes_params = ( Str( 'cn', cli_name='name', label=_('Rule name'), primary_key=True, ), StrEnum( 'accessruletype', validate_type, cli_name='type', doc=_('Rule type (allow)'), label=_('Rule type'), values=(u'allow', u'deny'), default=u'allow', autofill=True, exclude='webui', flags=['no_option', 'no_output'], ), # FIXME: {user,host,service}categories should expand in the future StrEnum( 'usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum( 'hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), DeprecatedParam('sourcehostcategory?'), StrEnum( 'servicecategory?', cli_name='servicecat', label=_('Service category'), doc=_('Service category the rule applies to'), values=(u'all', ), ), # AccessTime('accesstime?', # cli_name='time', # label=_('Access time'), # ), Str( 'description?', cli_name='desc', label=_('Description'), ), Bool( 'ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), Str( 'memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), DeprecatedParam('sourcehost_host?'), DeprecatedParam('sourcehost_hostgroup?'), Str( 'memberservice_hbacsvc?', label=_('Services'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberservice_hbacsvcgroup?', label=_('Service Groups'), flags=['no_create', 'no_update', 'no_search'], ), external_host_param, )
class certprofile(LDAPObject): """ Certificate Profile object. """ container_dn = api.env.container_certprofile object_name = _('Certificate Profile') object_name_plural = _('Certificate Profiles') object_class = ['ipacertprofile'] default_attributes = ['cn', 'description', 'ipacertprofilestoreissued'] search_attributes = ['cn', 'description', 'ipacertprofilestoreissued'] label = _('Certificate Profiles') label_singular = _('Certificate Profile') takes_params = ( Str( 'cn', validate_profile_id, primary_key=True, cli_name='id', label=_('Profile ID'), doc=_('Profile ID for referring to this profile'), ), Str( 'config', label=_('Profile configuration'), flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ), Str( 'description', required=True, cli_name='desc', label=_('Profile description'), doc=_('Brief description of this profile'), ), Bool( 'ipacertprofilestoreissued', default=True, cli_name='store', label=_('Store issued certificates'), doc=_('Whether to store certs issued using this profile'), ), ) permission_filter_objectclasses = ['ipacertprofile'] managed_permissions = { 'System: Read Certificate Profiles': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'cn', 'description', 'ipacertprofilestoreissued', 'objectclass', }, }, 'System: Import Certificate Profile': { 'ipapermright': {'add'}, 'replaces': [ '(target = "ldap:///cn=*,cn=certprofiles,cn=ca,$SUFFIX")(version 3.0;acl "permission:Import Certificate Profile";allow (add) groupdn = "ldap:///cn=Import Certificate Profile,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'CA Administrator'}, }, 'System: Delete Certificate Profile': { 'ipapermright': {'delete'}, 'replaces': [ '(target = "ldap:///cn=*,cn=certprofiles,cn=ca,$SUFFIX")(version 3.0;acl "permission:Delete Certificate Profile";allow (delete) groupdn = "ldap:///cn=Delete Certificate Profile,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'CA Administrator'}, }, 'System: Modify Certificate Profile': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'cn', 'description', 'ipacertprofilestoreissued', }, 'replaces': [ '(targetattr = "cn || description || ipacertprofilestoreissued")(target = "ldap:///cn=*,cn=certprofiles,cn=ca,$SUFFIX")(version 3.0;acl "permission:Modify Certificate Profile";allow (write) groupdn = "ldap:///cn=Modify Certificate Profile,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'CA Administrator'}, }, }
class sudorule(LDAPObject): """ Sudo Rule object. """ container_dn = api.env.container_sudorule object_name = _('sudo rule') object_name_plural = _('sudo rules') object_class = ['ipaassociation', 'ipasudorule'] permission_filter_objectclasses = ['ipasudorule'] default_attributes = [ 'cn', 'ipaenabledflag', 'externaluser', 'description', 'usercategory', 'hostcategory', 'cmdcategory', 'memberuser', 'memberhost', 'memberallowcmd', 'memberdenycmd', 'ipasudoopt', 'ipasudorunas', 'ipasudorunasgroup', 'ipasudorunasusercategory', 'ipasudorunasgroupcategory', 'sudoorder', 'hostmask', 'externalhost', 'ipasudorunasextusergroup', 'ipasudorunasextgroup', 'ipasudorunasextuser' ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' allow_rename = True attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], 'memberallowcmd': ['sudocmd', 'sudocmdgroup'], 'memberdenycmd': ['sudocmd', 'sudocmdgroup'], 'ipasudorunas': ['user', 'group'], 'ipasudorunasgroup': ['group'], } managed_permissions = { 'System: Read Sudo Rules': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'cmdcategory', 'cn', 'description', 'externalhost', 'externaluser', 'hostcategory', 'hostmask', 'ipaenabledflag', 'ipasudoopt', 'ipasudorunas', 'ipasudorunasextgroup', 'ipasudorunasextuser', 'ipasudorunasextusergroup', 'ipasudorunasgroup', 'ipasudorunasgroupcategory', 'ipasudorunasusercategory', 'ipauniqueid', 'memberallowcmd', 'memberdenycmd', 'memberhost', 'memberuser', 'sudonotafter', 'sudonotbefore', 'sudoorder', 'usercategory', 'objectclass', 'member', }, }, 'System: Read Sudoers compat tree': { 'non_object': True, 'ipapermlocation': api.env.basedn, 'ipapermtarget': DN('ou=sudoers', api.env.basedn), 'ipapermbindruletype': 'anonymous', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'objectclass', 'cn', 'ou', 'sudouser', 'sudohost', 'sudocommand', 'sudorunas', 'sudorunasuser', 'sudorunasgroup', 'sudooption', 'sudonotbefore', 'sudonotafter', 'sudoorder', 'description', }, }, 'System: Add Sudo rule': { 'ipapermright': {'add'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=sudorules,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Add Sudo rule";allow (add) groupdn = "ldap:///cn=Add Sudo rule,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'Sudo Administrator'}, }, 'System: Delete Sudo rule': { 'ipapermright': {'delete'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=sudorules,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Delete Sudo rule";allow (delete) groupdn = "ldap:///cn=Delete Sudo rule,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'Sudo Administrator'}, }, 'System: Modify Sudo rule': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'description', 'ipaenabledflag', 'usercategory', 'hostcategory', 'cmdcategory', 'ipasudorunasusercategory', 'ipasudorunasgroupcategory', 'externaluser', 'ipasudorunasextusergroup', 'ipasudorunasextuser', 'ipasudorunasextgroup', 'memberdenycmd', 'memberallowcmd', 'memberuser', 'memberhost', 'externalhost', 'sudonotafter', 'hostmask', 'sudoorder', 'sudonotbefore', 'ipasudorunas', 'externalhost', 'ipasudorunasgroup', 'ipasudoopt', 'memberhost', }, 'replaces': [ '(targetattr = "description || ipaenabledflag || usercategory || hostcategory || cmdcategory || ipasudorunasusercategory || ipasudorunasgroupcategory || externaluser || ipasudorunasextuser || ipasudorunasextgroup || memberdenycmd || memberallowcmd || memberuser")(target = "ldap:///ipauniqueid=*,cn=sudorules,cn=sudo,$SUFFIX")(version 3.0;acl "permission:Modify Sudo rule";allow (write) groupdn = "ldap:///cn=Modify Sudo rule,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'Sudo Administrator'}, }, } label = _('Sudo Rules') label_singular = _('Sudo Rule') takes_params = ( Str( 'cn', cli_name='sudorule_name', label=_('Rule name'), primary_key=True, ), Str( 'description?', cli_name='desc', label=_('Description'), ), Bool( 'ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), StrEnum( 'usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum( 'hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), StrEnum( 'cmdcategory?', cli_name='cmdcat', label=_('Command category'), doc=_('Command category the rule applies to'), values=(u'all', ), ), StrEnum( 'ipasudorunasusercategory?', cli_name='runasusercat', label=_('RunAs User category'), doc=_('RunAs User category the rule applies to'), values=(u'all', ), ), StrEnum( 'ipasudorunasgroupcategory?', cli_name='runasgroupcat', label=_('RunAs Group category'), doc=_('RunAs Group category the rule applies to'), values=(u'all', ), ), Int( 'sudoorder?', cli_name='order', label=_('Sudo order'), doc=_('integer to order the Sudo rules'), default=0, minvalue=0, ), Str( 'memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'externaluser?', validate_externaluser, cli_name='externaluser', label=_('External User'), doc=_('External User the rule applies to (sudorule-find only)'), ), Str( 'memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'hostmask', validate_hostmask, normalizer=lambda x: unicode(netaddr.IPNetwork(x).cidr), label=_('Host Masks'), flags=['no_create', 'no_update', 'no_search'], multivalue=True, ), external_host_param, Str( 'memberallowcmd_sudocmd?', label=_('Sudo Allow Commands'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberdenycmd_sudocmd?', label=_('Sudo Deny Commands'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberallowcmd_sudocmdgroup?', label=_('Sudo Allow Command Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberdenycmd_sudocmdgroup?', label=_('Sudo Deny Command Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunas_user?', label=_('RunAs Users'), doc=_('Run as a user'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunas_group?', label=_('Groups of RunAs Users'), doc=_('Run as any user within a specified group'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunasextuser?', validate_runasextuser, cli_name='runasexternaluser', label=_('RunAs External User'), doc=_( 'External User the commands can run as (sudorule-find only)'), ), Str( 'ipasudorunasextusergroup?', cli_name='runasexternalusergroup', label=_('External Groups of RunAs Users'), doc=_('External Groups of users that the command can run as'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunasgroup_group?', label=_('RunAs Groups'), doc=_('Run with the gid of a specified POSIX group'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunasextgroup?', validate_runasextgroup, cli_name='runasexternalgroup', label=_('RunAs External Group'), doc=_( 'External Group the commands can run as (sudorule-find only)'), ), Str( 'ipasudoopt*', label=_('Sudo Option'), flags=['no_create', 'no_update', 'no_search'], ), ) order_not_unique_msg = _( 'order must be a unique value (%(order)d already used by %(rule)s)') def check_order_uniqueness(self, *keys, **options): if options.get('sudoorder') is not None: entries = self.methods.find( sudoorder=options['sudoorder'])['result'] if len(entries) > 0: rule_name = entries[0]['cn'][0] raise errors.ValidationError(name='order', error=self.order_not_unique_msg % { 'order': options['sudoorder'], 'rule': rule_name, })
else: entry_attrs['primarymail'] = entry_attrs['mail'][0] if 'primarymail' in entry_attrs: entry_attrs['mail'] = [entry_attrs['primarymail']] user.takes_params += (Str('primarymail?', cli_name='primary_mail', label=_('Primary mail address')), Str('alias*', cli_name='alias', label=_('Mail aliases')), Str('sendalias*', cli_name='send_alias', label=_('Allowed sender aliases')), Bool('canreceiveexternally?', cli_name='can_receive_externally', label='Can receive external mails'), Bool('cansendexternally?', cli_name='can_send_externally', label='Can send mails to external locations'), Int('mailboxquota?', cli_name='mailbox_quota', label='Mailbox quota [MB]'), Str('mailboxtransport?', cli_name='mailbox_transport', label=_('Mailbox transport string'))) user.default_attributes = user.default_attributes + [ 'alias', 'sendalias', 'mailboxquota', 'mailboxtransport' ]
class caacl(LDAPObject): """ CA ACL object. """ container_dn = api.env.container_caacl object_name = _('CA ACL') object_name_plural = _('CA ACLs') object_class = ['ipaassociation', 'ipacaacl'] permission_filter_objectclasses = ['ipacaacl'] default_attributes = [ 'cn', 'description', 'ipaenabledflag', 'ipacacategory', 'ipamemberca', 'ipacertprofilecategory', 'ipamembercertprofile', 'usercategory', 'memberuser', 'hostcategory', 'memberhost', 'servicecategory', 'memberservice', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], 'memberservice': ['service'], 'ipamemberca': ['ca'], 'ipamembercertprofile': ['certprofile'], } managed_permissions = { 'System: Read CA ACLs': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'cn', 'description', 'ipaenabledflag', 'ipacacategory', 'ipamemberca', 'ipacertprofilecategory', 'ipamembercertprofile', 'usercategory', 'memberuser', 'hostcategory', 'memberhost', 'servicecategory', 'memberservice', 'ipauniqueid', 'objectclass', 'member', }, }, 'System: Add CA ACL': { 'ipapermright': {'add'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Add CA ACL";allow (add) groupdn = "ldap:///cn=Add CA ACL,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'CA Administrator'}, }, 'System: Delete CA ACL': { 'ipapermright': {'delete'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Delete CA ACL";allow (delete) groupdn = "ldap:///cn=Delete CA ACL,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'CA Administrator'}, }, 'System: Manage CA ACL Membership': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'ipacacategory', 'ipamemberca', 'ipacertprofilecategory', 'ipamembercertprofile', 'usercategory', 'memberuser', 'hostcategory', 'memberhost', 'servicecategory', 'memberservice' }, 'replaces': [ '(targetattr = "ipamemberca || ipamembercertprofile || memberuser || memberservice || memberhost || ipacacategory || ipacertprofilecategory || usercategory || hostcategory || servicecategory")(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Manage CA ACL membership";allow (write) groupdn = "ldap:///cn=Manage CA ACL membership,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'CA Administrator'}, }, 'System: Modify CA ACL': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'cn', 'description', 'ipaenabledflag', }, 'replaces': [ '(targetattr = "cn || description || ipaenabledflag")(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Modify CA ACL";allow (write) groupdn = "ldap:///cn=Modify CA ACL,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'CA Administrator'}, }, } label = _('CA ACLs') label_singular = _('CA ACL') takes_params = ( Str('cn', cli_name='name', label=_('ACL name'), primary_key=True, ), Str('description?', cli_name='desc', label=_('Description'), ), Bool('ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), StrEnum('ipacacategory?', cli_name='cacat', label=_('CA category'), doc=_('CA category the ACL applies to'), values=(u'all', ), ), StrEnum('ipacertprofilecategory?', cli_name='profilecat', label=_('Profile category'), doc=_('Profile category the ACL applies to'), values=(u'all', ), ), StrEnum('usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the ACL applies to'), values=(u'all', ), ), StrEnum('hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the ACL applies to'), values=(u'all', ), ), StrEnum('servicecategory?', cli_name='servicecat', label=_('Service category'), doc=_('Service category the ACL applies to'), values=(u'all', ), ), Str('ipamemberca_ca?', label=_('CAs'), flags=['no_create', 'no_update', 'no_search'], ), Str('ipamembercertprofile_certprofile?', label=_('Profiles'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str('memberservice_service?', label=_('Services'), flags=['no_create', 'no_update', 'no_search'], ), )
class migrate_ds(Command): __doc__ = _('Migrate users and groups from DS to IPA.') migrate_objects = { # OBJECT_NAME: (search_filter, pre_callback, post_callback) # # OBJECT_NAME - is the name of an LDAPObject subclass # search_filter - is the filter to retrieve objects from DS # pre_callback - is called for each object just after it was # retrieved from DS and before being added to IPA # post_callback - is called for each object after it was added to IPA # exc_callback - is called when adding entry to IPA raises an exception # # {pre, post}_callback parameters: # ldap - ldap2 instance connected to IPA # pkey - primary key value of the object (uid for users, etc.) # dn - dn of the object as it (will be/is) stored in IPA # entry_attrs - attributes of the object # failed - a list of so-far failed objects # config - IPA config entry attributes # ctx - object context, used to pass data between callbacks # # If pre_callback return value evaluates to False, migration # of the current object is aborted. 'user': { 'filter_template': '(&(|%s)(uid=*))', 'oc_option': 'userobjectclass', 'oc_blocklist_option': 'userignoreobjectclass', 'attr_blocklist_option': 'userignoreattribute', 'pre_callback': _pre_migrate_user, 'post_callback': _post_migrate_user, 'exc_callback': None }, 'group': { 'filter_template': '(&(|%s)(cn=*))', 'oc_option': 'groupobjectclass', 'oc_blocklist_option': 'groupignoreobjectclass', 'attr_blocklist_option': 'groupignoreattribute', 'pre_callback': _pre_migrate_group, 'post_callback': None, 'exc_callback': _group_exc_callback, }, } migrate_order = ('user', 'group') takes_args = ( Str( 'ldapuri', validate_ldapuri, cli_name='ldap_uri', label=_('LDAP URI'), doc=_('LDAP URI of DS server to migrate from'), ), Password( 'bindpw', cli_name='password', label=_('Password'), confirm=False, doc=_('bind password'), ), ) takes_options = ( DNParam('binddn?', cli_name='bind_dn', label=_('Bind DN'), default=DN(('cn', 'directory manager')), autofill=True, ), DNParam('usercontainer', cli_name='user_container', label=_('User container'), doc=_('DN of container for users in DS relative to base DN'), default=DN(('ou', 'people')), autofill=True, ), DNParam('groupcontainer', cli_name='group_container', label=_('Group container'), doc=_('DN of container for groups in DS relative to base DN'), default=DN(('ou', 'groups')), autofill=True, ), Str('userobjectclass+', cli_name='user_objectclass', label=_('User object class'), doc=_('Objectclasses used to search for user entries in DS'), default=(u'person',), autofill=True, ), Str('groupobjectclass+', cli_name='group_objectclass', label=_('Group object class'), doc=_('Objectclasses used to search for group entries in DS'), default=(u'groupOfUniqueNames', u'groupOfNames'), autofill=True, ), Str('userignoreobjectclass*', cli_name='user_ignore_objectclass', label=_('Ignore user object class'), doc=_('Objectclasses to be ignored for user entries in DS'), default=tuple(), autofill=True, ), Str('userignoreattribute*', cli_name='user_ignore_attribute', label=_('Ignore user attribute'), doc=_('Attributes to be ignored for user entries in DS'), default=tuple(), autofill=True, ), Str('groupignoreobjectclass*', cli_name='group_ignore_objectclass', label=_('Ignore group object class'), doc=_('Objectclasses to be ignored for group entries in DS'), default=tuple(), autofill=True, ), Str('groupignoreattribute*', cli_name='group_ignore_attribute', label=_('Ignore group attribute'), doc=_('Attributes to be ignored for group entries in DS'), default=tuple(), autofill=True, ), Flag('groupoverwritegid', cli_name='group_overwrite_gid', label=_('Overwrite GID'), doc=_('When migrating a group already existing in IPA domain overwrite the '\ 'group GID and report as success'), ), StrEnum('schema?', cli_name='schema', label=_('LDAP schema'), doc=_('The schema used on the LDAP server. Supported values are RFC2307 and RFC2307bis. The default is RFC2307bis'), values=_supported_schemas, default=_supported_schemas[0], autofill=True, ), Flag('continue?', label=_('Continue'), doc=_('Continuous operation mode. Errors are reported but the process continues'), default=False, ), DNParam('basedn?', cli_name='base_dn', label=_('Base DN'), doc=_('Base DN on remote LDAP server'), ), Flag('compat?', cli_name='with_compat', label=_('Ignore compat plugin'), doc=_('Allows migration despite the usage of compat plugin'), default=False, ), Str('cacertfile?', cli_name='ca_cert_file', label=_('CA certificate'), doc=_('Load CA certificate of LDAP server from FILE'), default=None, noextrawhitespace=False, ), Bool('use_def_group?', cli_name='use_default_group', label=_('Add to default group'), doc=_('Add migrated users without a group to a default group ' '(default: true)'), default=True, autofill=True, ), StrEnum('scope', cli_name='scope', label=_('Search scope'), doc=_('LDAP search scope for users and groups: base, ' 'onelevel, or subtree. Defaults to onelevel'), values=sorted(_supported_scopes), default=_default_scope, autofill=True, ), ) has_output = ( output.Output( 'result', type=dict, doc=_('Lists of objects migrated; categorized by type.'), ), output.Output( 'failed', type=dict, doc= _('Lists of objects that could not be migrated; categorized by type.' ), ), output.Output( 'enabled', type=bool, doc=_('False if migration mode was disabled.'), ), output.Output( 'compat', type=bool, doc= _('False if migration fails because the compatibility plug-in is enabled.' ), ), ) exclude_doc = _('%s to exclude from migration') truncated_err_msg = _('''\ search results for objects to be migrated have been truncated by the server; migration process might be incomplete\n''') def get_options(self): """ Call get_options of the baseclass and add "exclude" options for each type of object being migrated. """ for option in super(migrate_ds, self).get_options(): yield option for ldap_obj_name in self.migrate_objects: ldap_obj = self.api.Object[ldap_obj_name] name = 'exclude_%ss' % to_cli(ldap_obj_name) doc = self.exclude_doc % ldap_obj.object_name_plural yield Str('%s*' % name, cli_name=name, doc=doc, default=tuple(), autofill=True) def normalize_options(self, options): """ Convert all "exclude" option values to lower-case. Also, empty List parameters are converted to None, but the migration plugin doesn't like that - convert back to empty lists. """ names = [ 'userobjectclass', 'groupobjectclass', 'userignoreobjectclass', 'userignoreattribute', 'groupignoreobjectclass', 'groupignoreattribute' ] names.extend('exclude_%ss' % to_cli(n) for n in self.migrate_objects) for name in names: if options[name]: options[name] = tuple(v.lower() for v in options[name]) else: options[name] = tuple() def _get_search_bases(self, options, ds_base_dn, migrate_order): search_bases = dict() for ldap_obj_name in migrate_order: container = options.get('%scontainer' % to_cli(ldap_obj_name)) if container: # Don't append base dn if user already appended it in the container dn if container.endswith(ds_base_dn): search_base = container else: search_base = DN(container, ds_base_dn) else: search_base = ds_base_dn search_bases[ldap_obj_name] = search_base return search_bases def migrate(self, ldap, config, ds_ldap, ds_base_dn, options): """ Migrate objects from DS to LDAP. """ assert isinstance(ds_base_dn, DN) migrated = {} # {'OBJ': ['PKEY1', 'PKEY2', ...], ...} failed = {} # {'OBJ': {'PKEY1': 'Failed 'cos blabla', ...}, ...} search_bases = self._get_search_bases(options, ds_base_dn, self.migrate_order) migration_start = datetime.datetime.now() scope = _supported_scopes[options.get('scope')] for ldap_obj_name in self.migrate_order: ldap_obj = self.api.Object[ldap_obj_name] template = self.migrate_objects[ldap_obj_name]['filter_template'] oc_list = options[to_cli( self.migrate_objects[ldap_obj_name]['oc_option'])] search_filter = construct_filter(template, oc_list) exclude = options['exclude_%ss' % to_cli(ldap_obj_name)] context = dict(ds_ldap=ds_ldap) migrated[ldap_obj_name] = [] failed[ldap_obj_name] = {} try: entries, truncated = ds_ldap.find_entries( search_filter, ['*'], search_bases[ldap_obj_name], scope, time_limit=0, size_limit=-1) except errors.NotFound: if not options.get('continue', False): raise errors.NotFound( reason= _('%(container)s LDAP search did not return any result ' '(search base: %(search_base)s, ' 'objectclass: %(objectclass)s)') % { 'container': ldap_obj_name, 'search_base': search_bases[ldap_obj_name], 'objectclass': ', '.join(oc_list) }) else: truncated = False entries = [] if truncated: logger.error('%s: %s', ldap_obj.name, self.truncated_err_msg) blocklists = {} for blocklist in ('oc_blocklist', 'attr_blocklist'): blocklist_option = ( self.migrate_objects[ldap_obj_name][blocklist + '_option']) if blocklist_option is not None: blocklists[blocklist] = options.get( blocklist_option, tuple()) else: blocklists[blocklist] = tuple() # get default primary group for new users if 'def_group_dn' not in context and options.get('use_def_group'): def_group = config.get('ipadefaultprimarygroup') context['def_group_dn'] = api.Object.group.get_dn(def_group) try: ldap.get_entry(context['def_group_dn'], ['gidnumber', 'cn']) except errors.NotFound: error_msg = _('Default group for new users not found') raise errors.NotFound(reason=error_msg) context['has_upg'] = ldap.has_upg() valid_gids = set() invalid_gids = set() migrate_cnt = 0 context['migrate_cnt'] = 0 for entry_attrs in entries: context['migrate_cnt'] = migrate_cnt s = datetime.datetime.now() ava = entry_attrs.dn[0][0] if ava.attr == ldap_obj.primary_key.name: # In case if pkey attribute is in the migrated object DN # and the original LDAP is multivalued, make sure that # we pick the correct value (the unique one stored in DN) pkey = ava.value.lower() else: pkey = entry_attrs[ldap_obj.primary_key.name][0].lower() if pkey in exclude: continue entry_attrs.dn = ldap_obj.get_dn(pkey) entry_attrs['objectclass'] = list( set( config.get(ldap_obj.object_class_config, ldap_obj.object_class) + [o.lower() for o in entry_attrs['objectclass']])) entry_attrs[ldap_obj.primary_key.name][0] = entry_attrs[ ldap_obj.primary_key.name][0].lower() callback = self.migrate_objects[ldap_obj_name]['pre_callback'] if callable(callback): try: entry_attrs.dn = callback(ldap, pkey, entry_attrs.dn, entry_attrs, failed[ldap_obj_name], config, context, schema=options['schema'], search_bases=search_bases, valid_gids=valid_gids, invalid_gids=invalid_gids, **blocklists) if not entry_attrs.dn: continue except errors.NotFound as e: failed[ldap_obj_name][pkey] = unicode(e.reason) continue try: ldap.add_entry(entry_attrs) except errors.ExecutionError as e: callback = self.migrate_objects[ldap_obj_name][ 'exc_callback'] if callable(callback): try: callback(ldap, entry_attrs.dn, entry_attrs, e, options) except errors.ExecutionError as e2: failed[ldap_obj_name][pkey] = unicode(e2) continue else: failed[ldap_obj_name][pkey] = unicode(e) continue migrated[ldap_obj_name].append(pkey) callback = self.migrate_objects[ldap_obj_name]['post_callback'] if callable(callback): callback(ldap, pkey, entry_attrs.dn, entry_attrs, failed[ldap_obj_name], config, context) e = datetime.datetime.now() d = e - s total_dur = e - migration_start migrate_cnt += 1 if migrate_cnt > 0 and migrate_cnt % 100 == 0: logger.info("%d %ss migrated. %s elapsed.", migrate_cnt, ldap_obj_name, total_dur) logger.debug("%d %ss migrated, duration: %s (total %s)", migrate_cnt, ldap_obj_name, d, total_dur) if 'def_group_dn' in context: _update_default_group(ldap, context, True) return (migrated, failed) def execute(self, ldapuri, bindpw, **options): ldap = self.api.Backend.ldap2 self.normalize_options(options) config = ldap.get_ipa_config() ds_base_dn = options.get('basedn') if ds_base_dn is not None: assert isinstance(ds_base_dn, DN) # check if migration mode is enabled if config.get('ipamigrationenabled', ('FALSE', ))[0] == 'FALSE': return dict(result={}, failed={}, enabled=False, compat=True) # connect to DS if options.get('cacertfile') is not None: # store CA cert into file tmp_ca_cert_f = write_tmp_file(options['cacertfile']) cacert = tmp_ca_cert_f.name # start TLS connection or STARTTLS ds_ldap = LDAPClient(ldapuri, cacert=cacert, start_tls=True) ds_ldap.simple_bind(options['binddn'], bindpw) tmp_ca_cert_f.close() else: ds_ldap = LDAPClient(ldapuri) ds_ldap.simple_bind(options['binddn'], bindpw, insecure_bind=True) # check whether the compat plugin is enabled if not options.get('compat'): try: ldap.get_entry( DN(('cn', 'users'), ('cn', 'compat'), (api.env.basedn))) return dict(result={}, failed={}, enabled=True, compat=False) except errors.NotFound: pass if not ds_base_dn: # retrieve base DN from remote LDAP server entries, _truncated = ds_ldap.find_entries( '', ['namingcontexts', 'defaultnamingcontext'], DN(''), ds_ldap.SCOPE_BASE, size_limit=-1, time_limit=0, ) if 'defaultnamingcontext' in entries[0]: ds_base_dn = DN(entries[0]['defaultnamingcontext'][0]) assert isinstance(ds_base_dn, DN) else: try: ds_base_dn = DN(entries[0]['namingcontexts'][0]) assert isinstance(ds_base_dn, DN) except (IndexError, KeyError) as e: raise Exception(str(e)) # migrate! (migrated, failed) = self.migrate(ldap, config, ds_ldap, ds_base_dn, options) return dict(result=migrated, failed=failed, enabled=True, compat=True)
class config(LDAPObject): """ IPA configuration object """ object_name = _('configuration options') default_attributes = [ 'ipamaxusernamelength', 'ipahomesrootdir', 'ipadefaultloginshell', 'ipadefaultprimarygroup', 'ipadefaultemaildomain', 'ipasearchtimelimit', 'ipasearchrecordslimit', 'ipausersearchfields', 'ipagroupsearchfields', 'ipamigrationenabled', 'ipacertificatesubjectbase', 'ipapwdexpadvnotify', 'ipaselinuxusermaporder', 'ipaselinuxusermapdefault', 'ipaconfigstring', 'ipakrbauthzdata', ] label = _('Configuration') label_singular = _('Configuration') takes_params = ( Int( 'ipamaxusernamelength', cli_name='maxusername', label=_('Maximum username length'), minvalue=1, ), IA5Str( 'ipahomesrootdir', cli_name='homedirectory', label=_('Home directory base'), doc=_('Default location of home directories'), ), Str( 'ipadefaultloginshell', cli_name='defaultshell', label=_('Default shell'), doc=_('Default shell for new users'), ), Str( 'ipadefaultprimarygroup', cli_name='defaultgroup', label=_('Default users group'), doc=_('Default group for new users'), ), Str( 'ipadefaultemaildomain?', cli_name='emaildomain', label=_('Default e-mail domain'), doc=_('Default e-mail domain'), ), Int( 'ipasearchtimelimit', validate_searchtimelimit, cli_name='searchtimelimit', label=_('Search time limit'), doc= _('Maximum amount of time (seconds) for a search (> 0, or -1 for unlimited)' ), minvalue=-1, ), Int( 'ipasearchrecordslimit', cli_name='searchrecordslimit', label=_('Search size limit'), doc=_('Maximum number of records to search (-1 is unlimited)'), minvalue=-1, ), IA5Str( 'ipausersearchfields', cli_name='usersearch', label=_('User search fields'), doc= _('A comma-separated list of fields to search in when searching for users' ), ), IA5Str( 'ipagroupsearchfields', cli_name='groupsearch', label='Group search fields', doc= _('A comma-separated list of fields to search in when searching for groups' ), ), Bool( 'ipamigrationenabled', cli_name='enable_migration', label=_('Enable migration mode'), doc=_('Enable migration mode'), ), DNParam( 'ipacertificatesubjectbase', cli_name='subject', label=_('Certificate Subject base'), doc=_('Base for certificate subjects (OU=Test,O=Example)'), flags=['no_update'], ), Str( 'ipagroupobjectclasses+', cli_name='groupobjectclasses', label=_('Default group objectclasses'), doc=_('Default group objectclasses (comma-separated list)'), csv=True, ), Str( 'ipauserobjectclasses+', cli_name='userobjectclasses', label=_('Default user objectclasses'), doc=_('Default user objectclasses (comma-separated list)'), csv=True, ), Int( 'ipapwdexpadvnotify', cli_name='pwdexpnotify', label=_('Password Expiration Notification (days)'), doc=_('Number of days\'s notice of impending password expiration'), minvalue=0, ), StrEnum( 'ipaconfigstring*', cli_name='ipaconfigstring', label=_('Password plugin features'), doc=_('Extra hashes to generate in password plug-in'), values=(u'AllowLMhash', u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout'), csv=True, ), Str( 'ipaselinuxusermaporder', label=_('SELinux user map order'), doc=_( 'Order in increasing priority of SELinux users, delimited by $' ), ), Str( 'ipaselinuxusermapdefault?', label=_('Default SELinux user'), doc= _('Default SELinux user when no match is found in SELinux map rule' ), ), StrEnum( 'ipakrbauthzdata*', cli_name='pac_type', label=_('Default PAC types'), doc=_('Default types of PAC supported for services'), values=(u'MS-PAC', u'PAD'), csv=True, ), ) def get_dn(self, *keys, **kwargs): return DN(('cn', 'ipaconfig'), ('cn', 'etc'))
class otptoken(LDAPObject): """ OTP Token object. """ container_dn = api.env.container_otp object_name = _('OTP token') object_name_plural = _('OTP tokens') object_class = ['ipatoken'] possible_objectclasses = ['ipatokentotp', 'ipatokenhotp'] default_attributes = [ 'ipatokenuniqueid', 'description', 'ipatokenowner', 'ipatokendisabled', 'ipatokennotbefore', 'ipatokennotafter', 'ipatokenvendor', 'ipatokenmodel', 'ipatokenserial', 'managedby' ] attribute_members = { 'managedby': ['user'], } relationships = { 'managedby': ('Managed by', 'man_by_', 'not_man_by_'), } allow_rename = True label = _('OTP Tokens') label_singular = _('OTP Token') takes_params = ( Str( 'ipatokenuniqueid', cli_name='id', label=_('Unique ID'), primary_key=True, flags=('optional_create'), ), StrEnum( 'type?', label=_('Type'), doc=_('Type of the token'), default=u'totp', autofill=True, values=tuple(list(TOKEN_TYPES) + [x.upper() for x in TOKEN_TYPES]), flags=('virtual_attribute', 'no_update'), ), Str( 'description?', cli_name='desc', label=_('Description'), doc=_('Token description (informational only)'), ), Str( 'ipatokenowner?', cli_name='owner', label=_('Owner'), doc=_('Assigned user of the token (default: self)'), ), Str( 'managedby_user?', label=_('Manager'), doc=_('Assigned manager of the token (default: self)'), flags=['no_create', 'no_update', 'no_search'], ), Bool('ipatokendisabled?', cli_name='disabled', label=_('Disabled'), doc=_('Mark the token as disabled (default: false)')), DateTime( 'ipatokennotbefore?', cli_name='not_before', label=_('Validity start'), doc=_('First date/time the token can be used'), ), DateTime( 'ipatokennotafter?', cli_name='not_after', label=_('Validity end'), doc=_('Last date/time the token can be used'), ), Str( 'ipatokenvendor?', cli_name='vendor', label=_('Vendor'), doc=_('Token vendor name (informational only)'), ), Str( 'ipatokenmodel?', cli_name='model', label=_('Model'), doc=_('Token model (informational only)'), ), Str( 'ipatokenserial?', cli_name='serial', label=_('Serial'), doc=_('Token serial (informational only)'), ), OTPTokenKey( 'ipatokenotpkey?', cli_name='key', label=_('Key'), doc=_('Token secret (Base32; default: random)'), default_from=lambda: os.urandom(KEY_LENGTH), autofill=True, # force server-side conversion normalizer=lambda x: x, flags=('no_display', 'no_update', 'no_search'), ), StrEnum( 'ipatokenotpalgorithm?', cli_name='algo', label=_('Algorithm'), doc=_('Token hash algorithm'), default=u'sha1', autofill=True, flags=('no_update'), values=(u'sha1', u'sha256', u'sha384', u'sha512'), ), IntEnum( 'ipatokenotpdigits?', cli_name='digits', label=_('Digits'), doc=_('Number of digits each token code will have'), values=(6, 8), default=6, autofill=True, flags=('no_update'), ), Int( 'ipatokentotpclockoffset?', cli_name='offset', label=_('Clock offset'), doc=_('TOTP token / FreeIPA server time difference'), default=0, autofill=True, flags=('no_update'), ), Int( 'ipatokentotptimestep?', cli_name='interval', label=_('Clock interval'), doc=_('Length of TOTP token code validity'), default=30, autofill=True, minvalue=5, flags=('no_update'), ), Int( 'ipatokenhotpcounter?', cli_name='counter', label=_('Counter'), doc=_('Initial counter for the HOTP token'), default=0, autofill=True, minvalue=0, flags=('no_update'), ), Str( 'uri?', label=_('URI'), flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'}, ), )
class user(baseuser): """ User object. """ container_dn = baseuser.active_container_dn label = _('Users') label_singular = _('User') object_name = _('user') object_name_plural = _('users') managed_permissions = { 'System: Read User Standard Attributes': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'anonymous', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'objectclass', 'cn', 'sn', 'description', 'title', 'uid', 'displayname', 'givenname', 'initials', 'manager', 'gecos', 'gidnumber', 'homedirectory', 'loginshell', 'uidnumber', 'ipantsecurityidentifier' }, }, 'System: Read User Addressbook Attributes': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'seealso', 'telephonenumber', 'facsimiletelephonenumber', 'l', 'ou', 'st', 'postalcode', 'street', 'destinationindicator', 'internationalisdnnumber', 'physicaldeliveryofficename', 'postaladdress', 'postofficebox', 'preferreddeliverymethod', 'registeredaddress', 'teletexterminalidentifier', 'telexnumber', 'x121address', 'carlicense', 'departmentnumber', 'employeenumber', 'employeetype', 'preferredlanguage', 'mail', 'mobile', 'pager', 'audio', 'businesscategory', 'homephone', 'homepostaladdress', 'jpegphoto', 'labeleduri', 'o', 'photo', 'roomnumber', 'secretary', 'usercertificate', 'usersmimecertificate', 'x500uniqueidentifier', 'inetuserhttpurl', 'inetuserstatus', 'ipacertmapdata', }, 'fixup_function': fix_addressbook_permission_bindrule, }, 'System: Read User IPA Attributes': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'ipauniqueid', 'ipasshpubkey', 'ipauserauthtype', 'userclass', }, 'fixup_function': fix_addressbook_permission_bindrule, }, 'System: Read User Kerberos Attributes': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'krbprincipalname', 'krbcanonicalname', 'krbprincipalaliases', 'krbprincipalexpiration', 'krbpasswordexpiration', 'krblastpwdchange', 'nsaccountlock', 'krbprincipaltype', }, }, 'System: Read User Kerberos Login Attributes': { 'replaces_global_anonymous_aci': True, 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'krblastsuccessfulauth', 'krblastfailedauth', 'krblastpwdchange', 'krblastadminunlock', 'krbloginfailedcount', 'krbpwdpolicyreference', 'krbticketpolicyreference', 'krbupenabled', }, 'default_privileges': {'User Administrators'}, }, 'System: Read User Membership': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'memberof', }, }, 'System: Read UPG Definition': { # Required for adding users 'replaces_global_anonymous_aci': True, 'non_object': True, 'ipapermlocation': UPG_DEFINITION_DN, 'ipapermtarget': UPG_DEFINITION_DN, 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': {'*'}, 'default_privileges': {'User Administrators'}, }, 'System: Add Users': { 'ipapermright': {'add'}, 'replaces': [ '(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Users";allow (add) groupdn = "ldap:///cn=Add Users,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'User Administrators'}, }, 'System: Add User to default group': { 'non_object': True, 'ipapermright': {'write'}, 'ipapermlocation': DN(api.env.container_group, api.env.basedn), 'ipapermtarget': DN('cn=ipausers', api.env.container_group, api.env.basedn), 'ipapermdefaultattr': {'member'}, 'replaces': [ '(targetattr = "member")(target = "ldap:///cn=ipausers,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add user to default group";allow (write) groupdn = "ldap:///cn=Add user to default group,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'User Administrators'}, }, 'System: Change User password': { 'ipapermright': {'write'}, 'ipapermtargetfilter': [ '(objectclass=posixaccount)', '(!(memberOf=%s))' % DN('cn=admins', api.env.container_group, api.env.basedn), ], 'ipapermdefaultattr': { 'krbprincipalkey', 'passwordhistory', 'sambalmpassword', 'sambantpassword', 'userpassword', 'krbpasswordexpiration' }, 'replaces': [ '(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:Change a user password";allow (write) groupdn = "ldap:///cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX";)', '(targetfilter = "(!(memberOf=cn=admins,cn=groups,cn=accounts,$SUFFIX))")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(targetattr = "userpassword || krbprincipalkey || sambalmpassword || sambantpassword || passwordhistory")(version 3.0;acl "permission:Change a user password";allow (write) groupdn = "ldap:///cn=Change a user password,cn=permissions,cn=pbac,$SUFFIX";)', '(targetattr = "userPassword || krbPrincipalKey || sambaLMPassword || sambaNTPassword || passwordHistory")(version 3.0; acl "Windows PassSync service can write passwords"; allow (write) userdn="ldap:///uid=passsync,cn=sysaccounts,cn=etc,$SUFFIX";)', ], 'default_privileges': { 'User Administrators', 'Modify Users and Reset passwords', 'PassSync Service', }, }, 'System: Manage User SSH Public Keys': { 'ipapermright': {'write'}, 'ipapermdefaultattr': {'ipasshpubkey'}, 'replaces': [ '(targetattr = "ipasshpubkey")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage User SSH Public Keys";allow (write) groupdn = "ldap:///cn=Manage User SSH Public Keys,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'User Administrators'}, }, 'System: Manage User Certificates': { 'ipapermright': {'write'}, 'ipapermdefaultattr': {'usercertificate'}, 'default_privileges': { 'User Administrators', 'Modify Users and Reset passwords', }, }, 'System: Manage User Principals': { 'ipapermright': {'write'}, 'ipapermdefaultattr': {'krbprincipalname', 'krbcanonicalname'}, 'default_privileges': { 'User Administrators', 'Modify Users and Reset passwords', }, }, 'System: Modify Users': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'businesscategory', 'carlicense', 'cn', 'departmentnumber', 'description', 'displayname', 'employeetype', 'employeenumber', 'facsimiletelephonenumber', 'gecos', 'givenname', 'homephone', 'inetuserhttpurl', 'initials', 'l', 'labeleduri', 'loginshell', 'manager', 'mail', 'mepmanagedentry', 'mobile', 'objectclass', 'ou', 'pager', 'postalcode', 'roomnumber', 'secretary', 'seealso', 'sn', 'st', 'street', 'telephonenumber', 'title', 'userclass', 'preferredlanguage', }, 'replaces': [ '(targetattr = "givenname || sn || cn || displayname || title || initials || loginshell || gecos || homephone || mobile || pager || facsimiletelephonenumber || telephonenumber || street || roomnumber || l || st || postalcode || manager || secretary || description || carlicense || labeleduri || inetuserhttpurl || seealso || employeetype || businesscategory || ou || mepmanagedentry || objectclass")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Users";allow (write) groupdn = "ldap:///cn=Modify Users,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': { 'User Administrators', 'Modify Users and Reset passwords', }, }, 'System: Remove Users': { 'ipapermright': {'delete'}, 'replaces': [ '(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Users";allow (delete) groupdn = "ldap:///cn=Remove Users,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'User Administrators'}, }, 'System: Unlock User': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'krblastadminunlock', 'krbloginfailedcount', 'nsaccountlock', }, 'replaces': [ '(targetattr = "krbLastAdminUnlock || krbLoginFailedCount")(target = "ldap:///uid=*,cn=users,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Unlock user accounts";allow (write) groupdn = "ldap:///cn=Unlock user accounts,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'User Administrators'}, }, 'System: Read User Compat Tree': { 'non_object': True, 'ipapermbindruletype': 'anonymous', 'ipapermlocation': api.env.basedn, 'ipapermtarget': DN('cn=users', 'cn=compat', api.env.basedn), 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'objectclass', 'uid', 'cn', 'gecos', 'gidnumber', 'uidnumber', 'homedirectory', 'loginshell', }, }, 'System: Read User Views Compat Tree': { 'non_object': True, 'ipapermbindruletype': 'anonymous', 'ipapermlocation': api.env.basedn, 'ipapermtarget': DN('cn=users', 'cn=*', 'cn=views', 'cn=compat', api.env.basedn), 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'objectclass', 'uid', 'cn', 'gecos', 'gidnumber', 'uidnumber', 'homedirectory', 'loginshell', }, }, 'System: Read User NT Attributes': { 'ipapermbindruletype': 'permission', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'ntuserdomainid', 'ntuniqueid', 'ntuseracctexpires', 'ntusercodepage', 'ntuserdeleteaccount', 'ntuserlastlogoff', 'ntuserlastlogon', }, 'default_privileges': {'PassSync Service'}, }, 'System: Manage User Certificate Mappings': { 'ipapermright': {'write'}, 'ipapermdefaultattr': {'ipacertmapdata', 'objectclass'}, 'default_privileges': {'Certificate Identity Mapping Administrators'}, }, } takes_params = baseuser.takes_params + ( Bool( 'nsaccountlock?', cli_name=('disabled'), default=False, label=_('Account disabled'), ), Bool( 'preserved?', label=_('Preserved user'), default=False, flags=['virtual_attribute', 'no_create', 'no_update'], ), ) def get_delete_dn(self, *keys, **options): active_dn = self.get_dn(*keys, **options) return DN(active_dn[0], self.delete_container_dn, api.env.basedn) def get_either_dn(self, *keys, **options): ''' Returns the DN of a user The user can be active (active container) or delete (delete container) If the user does not exist, returns the Active user DN ''' ldap = self.backend # Check that this value is a Active user try: active_dn = self.get_dn(*keys, **options) ldap.get_entry(active_dn, ['dn']) # The Active user exists dn = active_dn except errors.NotFound: # Check that this value is a Delete user delete_dn = self.get_delete_dn(*keys, **options) try: ldap.get_entry(delete_dn, ['dn']) # The Delete user exists dn = delete_dn except errors.NotFound: # The user is neither Active/Delete -> returns that Active DN dn = active_dn return dn def _normalize_manager(self, manager): """ Given a userid verify the user's existence and return the dn. """ return super(user, self).normalize_manager(manager, self.active_container_dn) def get_preserved_attribute(self, entry, options): if options.get('raw', False): return delete_container_dn = DN(self.delete_container_dn, api.env.basedn) if entry.dn.endswith(delete_container_dn): entry['preserved'] = True elif options.get('all', False): entry['preserved'] = False
class selinuxusermap(LDAPObject): """ SELinux User Map object. """ container_dn = api.env.container_selinux object_name = _('SELinux User Map rule') object_name_plural = _('SELinux User Map rules') object_class = ['ipaassociation', 'ipaselinuxusermap'] permission_filter_objectclasses = ['ipaselinuxusermap'] default_attributes = [ 'cn', 'ipaenabledflag', 'description', 'usercategory', 'hostcategory', 'ipaenabledflag', 'memberuser', 'memberhost', 'seealso', 'ipaselinuxuser', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], } managed_permissions = { 'System: Read SELinux User Maps': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'accesstime', 'cn', 'description', 'hostcategory', 'ipaenabledflag', 'ipaselinuxuser', 'ipauniqueid', 'memberhost', 'memberuser', 'seealso', 'usercategory', 'objectclass', 'member', }, }, 'System: Add SELinux User Maps': { 'ipapermright': {'add'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=usermap,cn=selinux,$SUFFIX")(version 3.0;acl "permission:Add SELinux User Maps";allow (add) groupdn = "ldap:///cn=Add SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'SELinux User Map Administrators'}, }, 'System: Modify SELinux User Maps': { 'ipapermright': {'write'}, 'ipapermdefaultattr': { 'cn', 'ipaenabledflag', 'ipaselinuxuser', 'memberhost', 'memberuser', 'seealso' }, 'replaces': [ '(targetattr = "cn || memberuser || memberhost || seealso || ipaselinuxuser || ipaenabledflag")(target = "ldap:///ipauniqueid=*,cn=usermap,cn=selinux,$SUFFIX")(version 3.0;acl "permission:Modify SELinux User Maps";allow (write) groupdn = "ldap:///cn=Modify SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'SELinux User Map Administrators'}, }, 'System: Remove SELinux User Maps': { 'ipapermright': {'delete'}, 'replaces': [ '(target = "ldap:///ipauniqueid=*,cn=usermap,cn=selinux,$SUFFIX")(version 3.0;acl "permission:Remove SELinux User Maps";allow (delete) groupdn = "ldap:///cn=Remove SELinux User Maps,cn=permissions,cn=pbac,$SUFFIX";)', ], 'default_privileges': {'SELinux User Map Administrators'}, }, } # These maps will not show as members of other entries label = _('SELinux User Maps') label_singular = _('SELinux User Map') takes_params = ( Str( 'cn', cli_name='name', label=_('Rule name'), primary_key=True, ), Str( 'ipaselinuxuser', validate_selinuxuser, cli_name='selinuxuser', label=_('SELinux User'), ), Str( 'seealso?', cli_name='hbacrule', label=_('HBAC Rule'), doc=_('HBAC Rule that defines the users, groups and hostgroups'), ), StrEnum( 'usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum( 'hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), Str( 'description?', cli_name='desc', label=_('Description'), ), Bool( 'ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), Str( 'memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), ) def _normalize_seealso(self, seealso): """ Given a HBAC rule name verify its existence and return the dn. """ if not seealso: return None try: dn = DN(seealso) return str(dn) except ValueError: try: entry_attrs = self.backend.find_entry_by_attr( self.api.Object['hbacrule'].primary_key.name, seealso, self.api.Object['hbacrule'].object_class, [''], DN(self.api.Object['hbacrule'].container_dn, api.env.basedn)) seealso = entry_attrs.dn except errors.NotFound: raise errors.NotFound( reason=_('HBAC rule %(rule)s not found') % dict(rule=seealso)) return seealso def _convert_seealso(self, ldap, entry_attrs, **options): """ Convert an HBAC rule dn into a name """ if options.get('raw', False): return if 'seealso' in entry_attrs: hbac_attrs = ldap.get_entry(entry_attrs['seealso'][0], ['cn']) entry_attrs['seealso'] = hbac_attrs['cn'][0]
class user_del(baseuser_del): __doc__ = _('Delete a user.') msg_summary = _('Deleted user "%(value)s"') takes_options = baseuser_del.takes_options + (Bool( 'preserve?', exclude='cli', ), ) def _preserve_user(self, pkey, delete_container, **options): assert isinstance(delete_container, DN) dn = self.obj.get_either_dn(pkey, **options) delete_dn = DN(dn[0], delete_container) ldap = self.obj.backend self.log.debug("preserve move %s -> %s" % (dn, delete_dn)) if dn.endswith(delete_container): raise errors.ExecutionError( _('%s: user is already preserved' % pkey)) # Check that this value is a Active user try: original_entry_attrs = self._exc_wrapper(pkey, options, ldap.get_entry)(dn, ['dn']) except errors.NotFound: self.obj.handle_not_found(pkey) for callback in self.get_callbacks('pre'): dn = callback(self, ldap, dn, pkey, **options) assert isinstance(dn, DN) # start to move the entry to Delete container self._exc_wrapper(pkey, options, ldap.move_entry)(dn, delete_dn, del_old=True) # Then clear the credential attributes attrs_to_clear = [ 'krbPrincipalKey', 'krbLastPwdChange', 'krbPasswordExpiration', 'userPassword' ] entry_attrs = self._exc_wrapper(pkey, options, ldap.get_entry)(delete_dn, attrs_to_clear) clearedCredential = False for attr in attrs_to_clear: if attr.lower() in entry_attrs: del entry_attrs[attr] clearedCredential = True if clearedCredential: self._exc_wrapper(pkey, options, ldap.update_entry)(entry_attrs) # Then restore some original entry attributes attrs_to_restore = [ 'secretary', 'managedby', 'manager', 'ipauniqueid', 'uidnumber', 'gidnumber', 'passwordHistory' ] entry_attrs = self._exc_wrapper(pkey, options, ldap.get_entry)(delete_dn, attrs_to_restore) restoreAttr = False for attr in attrs_to_restore: if ((attr.lower() in original_entry_attrs) and not (attr.lower() in entry_attrs)): restoreAttr = True entry_attrs[attr.lower()] = original_entry_attrs[attr.lower()] if restoreAttr: self._exc_wrapper(pkey, options, ldap.update_entry)(entry_attrs) def pre_callback(self, ldap, dn, *keys, **options): dn = self.obj.get_either_dn(*keys, **options) # For User life Cycle: user-del is a common plugin # command to delete active user (active container) and # delete user (delete container). # If the target entry is a Delete entry, skip the orphaning/removal # of OTP tokens. check_protected_member(keys[-1]) if not options.get('preserve', False): # Remove any ID overrides tied with this user try: remove_ipaobject_overrides(self.obj.backend, self.obj.api, dn) except errors.NotFound: self.obj.handle_not_found(*keys) if dn.endswith(DN(self.obj.delete_container_dn, api.env.basedn)): return dn # Delete all tokens owned and managed by this user. # Orphan all tokens owned but not managed by this user. owner = self.api.Object.user.get_primary_key_from_dn(dn) results = self.api.Command.otptoken_find(ipatokenowner=owner, no_members=False)['result'] for token in results: orphan = not [ x for x in token.get('managedby_user', []) if x == owner ] token = self.api.Object.otptoken.get_primary_key_from_dn( token['dn']) if orphan: self.api.Command.otptoken_mod(token, ipatokenowner=None) else: self.api.Command.otptoken_del(token) return dn def execute(self, *keys, **options): # We are going to permanent delete or the user is already in the delete container. delete_container = DN(self.obj.delete_container_dn, self.api.env.basedn) # The user to delete is active and there is no 'no_preserve' option if options.get('preserve', False): failed = [] preserved = [] for pkey in keys[-1]: try: self._preserve_user(pkey, delete_container, **options) preserved.append(pkey_to_value(pkey, options)) except Exception: if not options.get('continue', False): raise failed.append(pkey_to_value(pkey, options)) val = dict(result=dict(failed=failed), value=preserved) return val else: return super(user_del, self).execute(*keys, **options)
class config(LDAPObject): """ IPA configuration object """ object_name = _('configuration options') default_attributes = [ 'ipamaxusernamelength', 'ipahomesrootdir', 'ipadefaultloginshell', 'ipadefaultprimarygroup', 'ipadefaultemaildomain', 'ipasearchtimelimit', 'ipasearchrecordslimit', 'ipausersearchfields', 'ipagroupsearchfields', 'ipamigrationenabled', 'ipacertificatesubjectbase', 'ipapwdexpadvnotify', 'ipaselinuxusermaporder', 'ipaselinuxusermapdefault', 'ipaconfigstring', 'ipakrbauthzdata', 'ipauserauthtype' ] container_dn = DN(('cn', 'ipaconfig'), ('cn', 'etc')) permission_filter_objectclasses = ['ipaguiconfig'] managed_permissions = { 'System: Read Global Configuration': { 'replaces_global_anonymous_aci': True, 'ipapermbindruletype': 'all', 'ipapermright': {'read', 'search', 'compare'}, 'ipapermdefaultattr': { 'cn', 'objectclass', 'ipacertificatesubjectbase', 'ipaconfigstring', 'ipadefaultemaildomain', 'ipadefaultloginshell', 'ipadefaultprimarygroup', 'ipagroupobjectclasses', 'ipagroupsearchfields', 'ipahomesrootdir', 'ipakrbauthzdata', 'ipamaxusernamelength', 'ipamigrationenabled', 'ipapwdexpadvnotify', 'ipaselinuxusermapdefault', 'ipaselinuxusermaporder', 'ipasearchrecordslimit', 'ipasearchtimelimit', 'ipauserauthtype', 'ipauserobjectclasses', 'ipausersearchfields', 'ipacustomfields', }, }, } label = _('Configuration') label_singular = _('Configuration') takes_params = ( Int('ipamaxusernamelength', cli_name='maxusername', label=_('Maximum username length'), minvalue=1, maxvalue=255, ), IA5Str('ipahomesrootdir', cli_name='homedirectory', label=_('Home directory base'), doc=_('Default location of home directories'), ), Str('ipadefaultloginshell', cli_name='defaultshell', label=_('Default shell'), doc=_('Default shell for new users'), ), Str('ipadefaultprimarygroup', cli_name='defaultgroup', label=_('Default users group'), doc=_('Default group for new users'), ), Str('ipadefaultemaildomain?', cli_name='emaildomain', label=_('Default e-mail domain'), doc=_('Default e-mail domain'), ), Int('ipasearchtimelimit', cli_name='searchtimelimit', label=_('Search time limit'), doc=_('Maximum amount of time (seconds) for a search (-1 or 0 is unlimited)'), minvalue=-1, ), Int('ipasearchrecordslimit', cli_name='searchrecordslimit', label=_('Search size limit'), doc=_('Maximum number of records to search (-1 or 0 is unlimited)'), minvalue=-1, ), IA5Str('ipausersearchfields', cli_name='usersearch', label=_('User search fields'), doc=_('A comma-separated list of fields to search in when searching for users'), ), IA5Str('ipagroupsearchfields', cli_name='groupsearch', label='Group search fields', doc=_('A comma-separated list of fields to search in when searching for groups'), ), Bool('ipamigrationenabled', cli_name='enable_migration', label=_('Enable migration mode'), doc=_('Enable migration mode'), ), DNParam('ipacertificatesubjectbase', cli_name='subject', label=_('Certificate Subject base'), doc=_('Base for certificate subjects (OU=Test,O=Example)'), flags=['no_update'], ), Str('ipagroupobjectclasses+', cli_name='groupobjectclasses', label=_('Default group objectclasses'), doc=_('Default group objectclasses (comma-separated list)'), ), Str('ipauserobjectclasses+', cli_name='userobjectclasses', label=_('Default user objectclasses'), doc=_('Default user objectclasses (comma-separated list)'), ), Int('ipapwdexpadvnotify', cli_name='pwdexpnotify', label=_('Password Expiration Notification (days)'), doc=_('Number of days\'s notice of impending password expiration'), minvalue=0, ), StrEnum('ipaconfigstring*', cli_name='ipaconfigstring', label=_('Password plugin features'), doc=_('Extra hashes to generate in password plug-in'), values=(u'AllowNThash', u'KDC:Disable Last Success', u'KDC:Disable Lockout', u'KDC:Disable Default Preauth for SPNs'), ), Str('ipaselinuxusermaporder', label=_('SELinux user map order'), doc=_('Order in increasing priority of SELinux users, delimited by $'), ), Str('ipaselinuxusermapdefault?', label=_('Default SELinux user'), doc=_('Default SELinux user when no match is found in SELinux map rule'), ), StrEnum('ipakrbauthzdata*', cli_name='pac_type', label=_('Default PAC types'), doc=_('Default types of PAC supported for services'), values=(u'MS-PAC', u'PAD', u'nfs:NONE'), ), StrEnum('ipauserauthtype*', cli_name='user_auth_type', label=_('Default user authentication types'), doc=_('Default types of supported user authentication'), values=(u'password', u'radius', u'otp', u'disabled'), ), Str( 'ipa_master_server*', label=_('IPA masters'), doc=_('List of all IPA masters'), flags={'virtual_attribute', 'no_create', 'no_update'} ), Str( 'ca_server_server*', label=_('IPA CA servers'), doc=_('IPA servers configured as certificate authority'), flags={'virtual_attribute', 'no_create', 'no_update'} ), Str( 'ntp_server_server*', label=_('IPA NTP servers'), doc=_('IPA servers with enabled NTP'), flags={'virtual_attribute', 'no_create', 'no_update'} ), Str( 'ca_renewal_master_server?', label=_('IPA CA renewal master'), doc=_('Renewal master for IPA certificate authority'), flags={'virtual_attribute', 'no_create'} ) ) def get_dn(self, *keys, **kwargs): return DN(('cn', 'ipaconfig'), ('cn', 'etc'), api.env.basedn) def show_servroles_attributes(self, entry_attrs, **options): if options.get('raw', False): return backend = self.api.Backend.serverroles for role in ("CA server", "IPA master", "NTP server"): config = backend.config_retrieve(role) entry_attrs.update(config)
class selinuxusermap(LDAPObject): """ SELinux User Map object. """ container_dn = api.env.container_selinux object_name = _('SELinux User Map rule') object_name_plural = _('SELinux User Map rules') object_class = ['ipaassociation', 'ipaselinuxusermap'] default_attributes = [ 'cn', 'ipaenabledflag', 'description', 'usercategory', 'hostcategory', 'ipaenabledflag', 'memberuser', 'memberhost', 'memberhostgroup', 'seealso', 'ipaselinuxuser', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], } # These maps will not show as members of other entries label = _('SELinux User Maps') label_singular = _('SELinux User Map') takes_params = ( Str( 'cn', cli_name='name', label=_('Rule name'), primary_key=True, ), Str( 'ipaselinuxuser', validate_selinuxuser, cli_name='selinuxuser', label=_('SELinux User'), ), Str( 'seealso?', cli_name='hbacrule', label=_('HBAC Rule'), doc=_('HBAC Rule that defines the users, groups and hostgroups'), ), StrEnum( 'usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum( 'hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), Str( 'description?', cli_name='desc', label=_('Description'), ), Bool( 'ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), Str( 'memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), ) def _normalize_seealso(self, seealso): """ Given a HBAC rule name verify its existence and return the dn. """ if not seealso: return None try: dn = DN(seealso) return str(dn) except ValueError: try: (dn, entry_attrs) = self.backend.find_entry_by_attr( self.api.Object['hbacrule'].primary_key.name, seealso, self.api.Object['hbacrule'].object_class, [''], self.api.Object['hbacrule'].container_dn) seealso = dn except errors.NotFound: raise errors.NotFound( reason=_('HBAC rule %(rule)s not found') % dict(rule=seealso)) return seealso def _convert_seealso(self, ldap, entry_attrs, **options): """ Convert an HBAC rule dn into a name """ if options.get('raw', False): return if 'seealso' in entry_attrs: (hbac_dn, hbac_attrs) = ldap.get_entry(entry_attrs['seealso'][0], ['cn']) entry_attrs['seealso'] = hbac_attrs['cn'][0]
def convert_nsaccountlock(entry_attrs): if not 'nsaccountlock' in entry_attrs: entry_attrs['nsaccountlock'] = False else: nsaccountlock = Bool('temp') entry_attrs['nsaccountlock'] = nsaccountlock.convert(entry_attrs['nsaccountlock'][0])
class sudorule(LDAPObject): """ Sudo Rule object. """ container_dn = api.env.container_sudorule object_name = _('sudo rule') object_name_plural = _('sudo rules') object_class = ['ipaassociation', 'ipasudorule'] default_attributes = [ 'cn', 'ipaenabledflag', 'externaluser', 'description', 'usercategory', 'hostcategory', 'cmdcategory', 'memberuser', 'memberhost', 'memberallowcmd', 'memberdenycmd', 'ipasudoopt', 'ipasudorunas', 'ipasudorunasgroup', 'ipasudorunasusercategory', 'ipasudorunasgroupcategory', 'sudoorder', ] uuid_attribute = 'ipauniqueid' rdn_attribute = 'ipauniqueid' attribute_members = { 'memberuser': ['user', 'group'], 'memberhost': ['host', 'hostgroup'], 'memberallowcmd': ['sudocmd', 'sudocmdgroup'], 'memberdenycmd': ['sudocmd', 'sudocmdgroup'], 'ipasudorunas': ['user', 'group'], 'ipasudorunasgroup': ['group'], } label = _('Sudo Rules') label_singular = _('Sudo Rule') takes_params = ( Str( 'cn', cli_name='sudorule_name', label=_('Rule name'), primary_key=True, ), Str( 'description?', cli_name='desc', label=_('Description'), ), Bool( 'ipaenabledflag?', label=_('Enabled'), flags=['no_option'], ), StrEnum( 'usercategory?', cli_name='usercat', label=_('User category'), doc=_('User category the rule applies to'), values=(u'all', ), ), StrEnum( 'hostcategory?', cli_name='hostcat', label=_('Host category'), doc=_('Host category the rule applies to'), values=(u'all', ), ), StrEnum( 'cmdcategory?', cli_name='cmdcat', label=_('Command category'), doc=_('Command category the rule applies to'), values=(u'all', ), ), StrEnum( 'ipasudorunasusercategory?', cli_name='runasusercat', label=_('RunAs User category'), doc=_('RunAs User category the rule applies to'), values=(u'all', ), ), StrEnum( 'ipasudorunasgroupcategory?', cli_name='runasgroupcat', label=_('RunAs Group category'), doc=_('RunAs Group category the rule applies to'), values=(u'all', ), ), Int( 'sudoorder?', cli_name='order', label=_('Sudo order'), doc=_('integer to order the Sudo rules'), default=0, minvalue=0, ), Str( 'memberuser_user?', label=_('Users'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberuser_group?', label=_('User Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_host?', label=_('Hosts'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberhost_hostgroup?', label=_('Host Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberallowcmd_sudocmd?', label=_('Sudo Allow Commands'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberdenycmd_sudocmd?', label=_('Sudo Deny Commands'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberallowcmd_sudocmdgroup?', label=_('Sudo Allow Command Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'memberdenycmd_sudocmdgroup?', label=_('Sudo Deny Command Groups'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunas_user?', label=_('RunAs Users'), doc=_('Run as a user'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunas_group?', label=_('Groups of RunAs Users'), doc=_('Run as any user within a specified group'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'externaluser?', validate_externaluser, cli_name='externaluser', label=_('External User'), doc=_('External User the rule applies to (sudorule-find only)'), ), Str( 'ipasudorunasextuser?', validate_runasextuser, cli_name='runasexternaluser', label=_('RunAs External User'), doc=_( 'External User the commands can run as (sudorule-find only)'), ), Str( 'ipasudorunasextgroup?', validate_runasextgroup, cli_name='runasexternalgroup', label=_('RunAs External Group'), doc=_( 'External Group the commands can run as (sudorule-find only)'), ), Str( 'ipasudoopt?', label=_('Sudo Option'), flags=['no_create', 'no_update', 'no_search'], ), Str( 'ipasudorunasgroup_group?', label=_('RunAs Groups'), doc=_('Run with the gid of a specified POSIX group'), flags=['no_create', 'no_update', 'no_search'], ), external_host_param, ) order_not_unique_msg = _( 'order must be a unique value (%(order)d already used by %(rule)s)') def check_order_uniqueness(self, *keys, **options): if 'sudoorder' in options: entries = self.methods.find( sudoorder=options['sudoorder'])['result'] if len(entries) > 0: rule_name = entries[0]['cn'][0] raise errors.ValidationError(name='order', error=self.order_not_unique_msg % { 'order': options['sudoorder'], 'rule': rule_name, })