Beispiel #1
0
class permission_add_noaci(LDAPCreate):
    __doc__ = _('Add a system permission without an ACI')

    msg_summary = _('Added permission "%(value)s"')
    has_output_params = LDAPCreate.has_output_params + output_params
    NO_CLI = True

    takes_options = (StrEnum(
        'permissiontype?',
        label=_('Permission type'),
        values=(u'SYSTEM', ),
    ), )

    def get_args(self):
        # do not validate system permission names
        yield self.obj.primary_key.clone(pattern=None, pattern_errmsg=None)

    def get_options(self):
        for option in super(permission_add_noaci, self).get_options():
            # filter out ACI options
            if option.name in self.obj.aci_attributes:
                continue
            yield option

    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
                     **options):
        assert isinstance(dn, DN)
        permission_type = options.get('permissiontype')
        if permission_type:
            entry_attrs['ipapermissiontype'] = [permission_type]
        return dn
Beispiel #2
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']
    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,
                                             })
Beispiel #3
0
class topologysegment(LDAPObject):
    """
    Topology segment.
    """
    parent_object = 'topologysuffix'
    container_dn = api.env.container_topology
    object_name = _('segment')
    object_name_plural = _('segments')
    object_class = ['iparepltoposegment']
    default_attributes = [
        'cn', 'ipaReplTopoSegmentdirection', 'ipaReplTopoSegmentrightNode',
        'ipaReplTopoSegmentLeftNode', 'nsds5replicastripattrs',
        'nsds5replicatedattributelist', 'nsds5replicatedattributelisttotal',
        'nsds5replicatimeout', 'nsds5replicaenabled'
    ]
    search_display_attributes = [
        'cn', 'ipaReplTopoSegmentdirection', 'ipaReplTopoSegmentrightNode',
        'ipaReplTopoSegmentLeftNode'
    ]

    label = _('Topology Segments')
    label_singular = _('Topology Segment')

    takes_params = (
        Str(
            'cn',
            maxlength=255,
            cli_name='name',
            primary_key=True,
            label=_('Segment name'),
            default_from=lambda iparepltoposegmentleftnode,
            iparepltoposegmentrightnode: '%s-to-%s' %
            (iparepltoposegmentleftnode, iparepltoposegmentrightnode),
            normalizer=lambda value: value.lower(),
            doc=_('Arbitrary string identifying the segment'),
        ),
        Str(
            'iparepltoposegmentleftnode',
            pattern='^[a-zA-Z0-9.][a-zA-Z0-9.-]*[a-zA-Z0-9.$-]?$',
            pattern_errmsg='may only include letters, numbers, -, . and $',
            maxlength=255,
            cli_name='leftnode',
            label=_('Left node'),
            normalizer=lambda value: value.lower(),
            doc=_('Left replication node - an IPA server'),
            flags={'no_update'},
        ),
        Str(
            'iparepltoposegmentrightnode',
            pattern='^[a-zA-Z0-9.][a-zA-Z0-9.-]*[a-zA-Z0-9.$-]?$',
            pattern_errmsg='may only include letters, numbers, -, . and $',
            maxlength=255,
            cli_name='rightnode',
            label=_('Right node'),
            normalizer=lambda value: value.lower(),
            doc=_('Right replication node - an IPA server'),
            flags={'no_update'},
        ),
        StrEnum(
            'iparepltoposegmentdirection',
            cli_name='direction',
            label=_('Connectivity'),
            values=(u'both', u'left-right', u'right-left'),
            default=u'both',
            autofill=True,
            doc=_(
                'Direction of replication between left and right replication '
                'node'),
            flags={'no_option', 'no_update'},
        ),
        Str('nsds5replicastripattrs?',
            cli_name='stripattrs',
            label=_('Attributes to strip'),
            normalizer=lambda value: value.lower(),
            doc=_(
                'A space separated list of attributes which are removed from '
                'replication updates.')),
        Str(
            'nsds5replicatedattributelist?',
            cli_name='replattrs',
            label='Attributes to replicate',
            doc=_('Attributes that are not replicated to a consumer server '
                  'during a fractional update. E.g., `(objectclass=*) '
                  '$ EXCLUDE accountlockout memberof'),
        ),
        Str(
            'nsds5replicatedattributelisttotal?',
            cli_name='replattrstotal',
            label=_('Attributes for total update'),
            doc=_('Attributes that are not replicated to a consumer server '
                  'during a total update. E.g. (objectclass=*) $ EXCLUDE '
                  'accountlockout'),
        ),
        Int(
            'nsds5replicatimeout?',
            cli_name='timeout',
            label=_('Session timeout'),
            minvalue=0,
            doc=_('Number of seconds outbound LDAP operations waits for a '
                  'response from the remote replica before timing out and '
                  'failing'),
        ),
        StrEnum(
            'nsds5replicaenabled?',
            cli_name='enabled',
            label=_('Replication agreement enabled'),
            doc=_('Whether a replication agreement is active, meaning whether '
                  'replication is occurring per that agreement'),
            values=(u'on', u'off'),
            flags={'no_option'},
        ),
    )

    def validate_nodes(self, ldap, dn, entry_attrs, suffix):
        leftnode = entry_attrs.get('iparepltoposegmentleftnode')
        rightnode = entry_attrs.get('iparepltoposegmentrightnode')

        if not leftnode and not rightnode:
            return  # nothing to check

        # check if nodes are IPA servers
        masters = self.api.Command.server_find('',
                                               sizelimit=0,
                                               no_members=False)['result']
        m_hostnames = [master['cn'][0].lower() for master in masters]

        if leftnode and leftnode not in m_hostnames:
            raise errors.ValidationError(
                name='leftnode',
                error=_('left node is not a topology node: %(leftnode)s') %
                dict(leftnode=leftnode))

        if rightnode and rightnode not in m_hostnames:
            raise errors.ValidationError(
                name='rightnode',
                error=_('right node is not a topology node: %(rightnode)s') %
                dict(rightnode=rightnode))

        # prevent creation of reflexive relation
        key = 'leftnode'
        if not leftnode or not rightnode:  # get missing end
            _entry_attrs = ldap.get_entry(dn, ['*'])
            if not leftnode:
                key = 'rightnode'
                leftnode = _entry_attrs['iparepltoposegmentleftnode'][0]
            else:
                rightnode = _entry_attrs['iparepltoposegmentrightnode'][0]

        if leftnode == rightnode:
            raise errors.ValidationError(
                name=key,
                error=_('left node and right node must not be the same'))

        # don't allow segment between nodes where both don't have the suffix
        masters_to_suffix = map_masters_to_suffixes(masters)
        suffix_masters = masters_to_suffix.get(suffix, [])
        suffix_m_hostnames = [m['cn'][0].lower() for m in suffix_masters]

        if leftnode not in suffix_m_hostnames:
            raise errors.ValidationError(
                name='leftnode',
                error=_("left node ({host}) does not support "
                        "suffix '{suff}'").format(host=leftnode, suff=suffix))

        if rightnode not in suffix_m_hostnames:
            raise errors.ValidationError(
                name='rightnode',
                error=_("right node ({host}) does not support "
                        "suffix '{suff}'").format(host=rightnode, suff=suffix))
Beispiel #4
0
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)
Beispiel #5
0
class netgroup(LDAPObject):
    """
    Netgroup object.
    """
    container_dn = api.env.container_netgroup
    object_name = _('netgroup')
    object_name_plural = _('netgroups')
    object_class = ['ipaobject', 'ipaassociation', 'ipanisnetgroup']
    default_attributes = [
        'cn',
        'description',
        'memberof',
        'externalhost',
        'nisdomainname',
        'memberuser',
        'memberhost',
        'member',
        'memberindirect',
        'usercategory',
        'hostcategory',
    ]
    uuid_attribute = 'ipauniqueid'
    rdn_attribute = 'ipauniqueid'
    attribute_members = {
        'member': ['netgroup'],
        'memberof': ['netgroup'],
        'memberindirect': ['netgroup'],
        'memberuser': ['user', 'group'],
        'memberhost': ['host', 'hostgroup'],
    }
    relationships = {
        'member': ('Member', '', 'no_'),
        'memberof': ('Member Of', 'in_', 'not_in_'),
        'memberindirect': ('Indirect Member', None, 'no_indirect_'),
        'memberuser': ('Member', '', 'no_'),
        'memberhost': ('Member', '', 'no_'),
    }

    label = _('Netgroups')
    label_singular = _('Netgroup')

    takes_params = (
        Str(
            'cn',
            pattern=NETGROUP_PATTERN,
            pattern_errmsg=NETGROUP_PATTERN_ERRMSG,
            cli_name='name',
            label=_('Netgroup name'),
            primary_key=True,
            normalizer=lambda value: value.lower(),
        ),
        Str(
            'description',
            cli_name='desc',
            label=_('Description'),
            doc=_('Netgroup description'),
        ),
        Str(
            'nisdomainname?',
            pattern=NISDOMAIN_PATTERN,
            pattern_errmsg=NISDOMAIN_PATTERN_ERRMSG,
            cli_name='nisdomain',
            label=_('NIS domain name'),
        ),
        Str(
            'ipauniqueid?',
            cli_name='uuid',
            label='IPA unique ID',
            doc=_('IPA unique ID'),
            flags=['no_create', 'no_update'],
        ),
        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', ),
        ),
        external_host_param,
    )
Beispiel #6
0
        csv=True,
        alwaysask=True,
    ),
    Str('key',
        label=_('Attribute Key'),
        doc=
        _('Attribute to filter via regex. For example fqdn for a host, or manager for a user'
          ),
        flags=['no_create', 'no_update', 'no_search']),
)

group_type = (StrEnum(
    'type',
    label=_('Grouping Type'),
    doc=_('Grouping to which the rule applies'),
    values=(
        u'group',
        u'hostgroup',
    ),
), )

automember_rule = (Str(
    'cn',
    cli_name='automember_rule',
    label=_('Automember Rule'),
    doc=_('Automember Rule'),
    normalizer=lambda value: value.lower(),
), )


@register()
Beispiel #7
0
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'},
        ),
    )
Beispiel #8
0
class service(LDAPObject):
    """
    Service object.
    """
    container_dn = api.env.container_service
    object_name = _('service')
    object_name_plural = _('services')
    object_class = [
        'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject',
        'ipaservice', 'pkiuser'
    ]
    possible_objectclasses = ['ipakrbprincipal', 'ipaallowedoperations']
    permission_filter_objectclasses = ['ipaservice']
    search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata']
    default_attributes = [
        'krbprincipalname', 'krbcanonicalname', 'usercertificate', 'managedby',
        'ipakrbauthzdata', 'memberof', 'ipaallowedtoperform',
        'krbprincipalauthind']
    uuid_attribute = 'ipauniqueid'
    attribute_members = {
        'managedby': ['host'],
        'memberof': ['role'],
        'ipaallowedtoperform_read_keys': ['user', 'group', 'host', 'hostgroup'],
        'ipaallowedtoperform_write_keys': ['user', 'group', 'host', 'hostgroup'],
    }
    bindable = True
    relationships = {
        'managedby': ('Managed by', 'man_by_', 'not_man_by_'),
        'ipaallowedtoperform_read_keys': ('Allow to retrieve keytab by', 'retrieve_keytab_by_', 'not_retrieve_keytab_by_'),
        'ipaallowedtoperform_write_keys': ('Allow to create keytab by', 'write_keytab_by_', 'not_write_keytab_by'),
    }
    password_attributes = [('krbprincipalkey', 'has_keytab')]
    managed_permissions = {
        'System: Read Services': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'ipauniqueid', 'managedby', 'memberof', 'usercertificate',
                'krbprincipalname', 'krbcanonicalname', 'krbprincipalaliases',
                'krbprincipalexpiration', 'krbpasswordexpiration',
                'krblastpwdchange', 'ipakrbauthzdata', 'ipakrbprincipalalias',
                'krbobjectreferences', 'krbprincipalauthind',
            },
        },
        'System: Add Services': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Services";allow (add) groupdn = "ldap:///cn=Add Services,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Service Administrators'},
        },
        'System: Manage Service Keytab': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey'},
            'replaces': [
                '(targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage service keytab";allow (write) groupdn = "ldap:///cn=Manage service keytab,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Service Administrators', 'Host Administrators'},
        },
        'System: Manage Service Keytab Permissions': {
            'ipapermright': {'read', 'search', 'compare', 'write'},
            'ipapermdefaultattr': {
                'ipaallowedtoperform;write_keys',
                'ipaallowedtoperform;read_keys', 'objectclass'
            },
            'default_privileges': {'Service Administrators', 'Host Administrators'},
        },
        'System: Modify Services': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'usercertificate', 'krbprincipalauthind'},
            'replaces': [
                '(targetattr = "usercertificate")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Services";allow (write) groupdn = "ldap:///cn=Modify Services,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Service Administrators'},
        },
        'System: Manage Service Principals': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'krbprincipalname', 'krbcanonicalname'},
            'default_privileges': {
                'Service Administrators',
            },
        },
        'System: Remove Services': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Services";allow (delete) groupdn = "ldap:///cn=Remove Services,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Service Administrators'},
        },
    }

    label = _('Services')
    label_singular = _('Service')

    takes_params = (
        Principal(
            'krbcanonicalname',
            validate_realm,
            cli_name='canonical_principal',
            label=_('Principal name'),
            doc=_('Service principal'),
            primary_key=True,
            normalizer=normalize_principal,
            require_service=True
        ),
        Principal(
            'krbprincipalname*',
            validate_realm,
            cli_name='principal',
            label=_('Principal alias'),
            doc=_('Service principal alias'),
            normalizer=normalize_principal,
            require_service=True,
            flags={'no_create'}
        ),
        Certificate('usercertificate*',
            cli_name='certificate',
            label=_('Certificate'),
            doc=_('Base-64 encoded service certificate'),
            flags=['no_search',],
        ),
        Str('subject',
            label=_('Subject'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('serial_number',
            label=_('Serial Number'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('serial_number_hex',
            label=_('Serial Number (hex)'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('issuer',
            label=_('Issuer'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('valid_not_before',
            label=_('Not Before'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('valid_not_after',
            label=_('Not After'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('sha1_fingerprint',
            label=_('Fingerprint (SHA1)'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('sha256_fingerprint',
            label=_('Fingerprint (SHA256)'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('revocation_reason?',
            label=_('Revocation reason'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        StrEnum('ipakrbauthzdata*',
            cli_name='pac_type',
            label=_('PAC type'),
            doc=_("Override default list of supported PAC types."
                  " Use 'NONE' to disable PAC support for this service,"
                  " e.g. this might be necessary for NFS services."),
            values=(u'MS-PAC', u'PAD', u'NONE'),
        ),
        Str('krbprincipalauthind*',
            cli_name='auth_ind',
            label=_('Authentication Indicators'),
            doc=_("Defines a whitelist for Authentication Indicators."
                  " Use 'otp' to allow OTP-based 2FA authentications."
                  " Use 'radius' to allow RADIUS-based 2FA authentications."
                  " Other values may be used for custom configurations."),
        ),
    ) + ticket_flags_params

    def validate_ipakrbauthzdata(self, entry):
        new_value = entry.get('ipakrbauthzdata', [])

        if not new_value:
            return

        if not isinstance(new_value, (list, tuple)):
            new_value = set([new_value])
        else:
            new_value = set(new_value)

        if u'NONE' in new_value and len(new_value) > 1:
            raise errors.ValidationError(name='ipakrbauthzdata',
                error=_('NONE value cannot be combined with other PAC types'))

    def get_dn(self, *keys, **kwargs):
        key = keys[0]
        if isinstance(key, str):
            key = kerberos.Principal(key)

        key = unicode(normalize_principal(key))

        parent_dn = DN(self.container_dn, self.api.env.basedn)
        true_rdn = 'krbprincipalname'

        return self.backend.make_dn_from_attr(
            true_rdn, key, parent_dn
        )

    def get_primary_key_from_dn(self, dn):
        """
        If the entry has krbcanonicalname set return the value of the
        attribute. If the attribute is not found, assume old-style entry which
        should have only single value of krbprincipalname and return it.

        Otherwise return input DN.
        """
        assert isinstance(dn, DN)

        try:
            entry_attrs = self.backend.get_entry(
                dn, [self.primary_key.name]
            )
            try:
                return entry_attrs[self.primary_key.name][0]
            except (KeyError, IndexError):
                return ''
        except errors.NotFound:
            pass

        try:
            return dn['krbprincipalname']
        except KeyError:
            return unicode(dn)

    def populate_krbcanonicalname(self, entry_attrs, options):
        if options.get('raw', False):
            return

        entry_attrs.setdefault(
            'krbcanonicalname', entry_attrs['krbprincipalname'])
Beispiel #9
0
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]
Beispiel #10
0
class service(LDAPObject):
    """
    Service object.
    """
    container_dn = api.env.container_service
    object_name = _('service')
    object_name_plural = _('services')
    object_class = [
        'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject',
        'ipaservice', 'pkiuser'
    ]
    possible_objectclasses = ['ipakrbprincipal']
    search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata']
    default_attributes = [
        'krbprincipalname',
        'usercertificate',
        'managedby',
        'ipakrbauthzdata',
    ]
    uuid_attribute = 'ipauniqueid'
    attribute_members = {
        'managedby': ['host'],
    }
    bindable = True
    relationships = {
        'managedby': ('Managed by', 'man_by_', 'not_man_by_'),
    }
    password_attributes = [('krbprincipalkey', 'has_keytab')]

    label = _('Services')
    label_singular = _('Service')

    takes_params = (
        Str(
            'krbprincipalname',
            validate_principal,
            cli_name='principal',
            label=_('Principal'),
            doc=_('Service principal'),
            primary_key=True,
            normalizer=lambda value: normalize_principal(value),
        ),
        Bytes(
            'usercertificate?',
            validate_certificate,
            cli_name='certificate',
            label=_('Certificate'),
            doc=_('Base-64 encoded server certificate'),
            flags=[
                'no_search',
            ],
        ),
        StrEnum(
            'ipakrbauthzdata*',
            cli_name='pac_type',
            label=_('PAC type'),
            doc=_("Override default list of supported PAC types."
                  " Use 'NONE' to disable PAC support for this service"),
            values=(u'MS-PAC', u'PAD', u'NONE'),
            csv=True,
        ),
    )

    def validate_ipakrbauthzdata(self, entry):
        new_value = entry.get('ipakrbauthzdata', [])

        if not new_value:
            return

        if not isinstance(new_value, (list, tuple)):
            new_value = set([new_value])
        else:
            new_value = set(new_value)

        if u'NONE' in new_value and len(new_value) > 1:
            raise errors.ValidationError(
                name='ipakrbauthzdata',
                error=_('NONE value cannot be combined with other PAC types'))
Beispiel #11
0
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'))
Beispiel #12
0
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'],
        ),
    )
Beispiel #13
0
class trust_add(LDAPCreate):
    __doc__ = _('''
Add new trust to use.

This command establishes trust relationship to another domain
which becomes 'trusted'. As result, users of the trusted domain
may access resources of this domain.

Only trusts to Active Directory domains are supported right now.

The command can be safely run multiple times against the same domain,
this will cause change to trust relationship credentials on both
sides.
    ''')

    takes_options = LDAPCreate.takes_options + (
        StrEnum(
            'trust_type',
            cli_name='type',
            label=_('Trust type (ad for Active Directory, default)'),
            values=(u'ad', ),
            default=u'ad',
            autofill=True,
        ),
        Str(
            'realm_admin?',
            cli_name='admin',
            label=_("Active Directory domain administrator"),
        ),
        Password(
            'realm_passwd?',
            cli_name='password',
            label=_("Active directory domain administrator's password"),
            confirm=False,
        ),
        Str(
            'realm_server?',
            cli_name='server',
            label=_(
                'Domain controller for the Active Directory domain (optional)'
            ),
        ),
        Password(
            'trust_secret?',
            cli_name='trust_secret',
            label=_('Shared secret for the trust'),
            confirm=False,
        ),
        Int(
            'base_id?',
            cli_name='base_id',
            label=_(
                'First Posix ID of the range reserved for the trusted domain'),
        ),
        Int('range_size?',
            cli_name='range_size',
            label=_('Size of the ID range reserved for the trusted domain'),
            default=200000,
            autofill=True),
    )

    msg_summary = _('Added Active Directory trust for realm "%(value)s"')
    has_output_params = LDAPCreate.has_output_params + trust_output_params

    def execute(self, *keys, **options):
        if not _murmur_installed and 'base_id' not in options:
            raise errors.ValidationError(name=_('missing base_id'),
                error=_('pysss_murmur is not available on the server ' \
                        'and no base-id is given.'))

        if 'trust_type' in options:
            if options['trust_type'] == u'ad':
                result = self.execute_ad(*keys, **options)
            else:
                raise errors.ValidationError(name=_('trust type'),
                                             error=_('only "ad" is supported'))
        else:
            raise errors.RequirementError(name=_('trust type'))

        self.add_range(*keys, **options)

        trust_filter = "cn=%s" % result['value']
        ldap = self.obj.backend
        (trusts,
         truncated) = ldap.find_entries(base_dn=DN(api.env.container_trusts,
                                                   api.env.basedn),
                                        filter=trust_filter)

        result['result'] = trusts[0][1]
        result['result']['trusttype'] = [
            trust_type_string(result['result']['ipanttrusttype'][0])
        ]
        result['result']['trustdirection'] = [
            trust_direction_string(result['result']['ipanttrustdirection'][0])
        ]
        result['result']['truststatus'] = [
            trust_status_string(result['verified'])
        ]
        del result['verified']

        return result

    def add_range(self, *keys, **options):
        new_obj = api.Command['trust_show'](keys[-1])
        dom_sid = new_obj['result']['ipanttrusteddomainsid'][0]

        range_name = keys[-1].upper() + '_id_range'

        try:
            old_range = api.Command['idrange_show'](range_name)
        except errors.NotFound, e:
            old_range = None

        if old_range:
            old_dom_sid = old_range['result']['ipanttrusteddomainsid'][0]

            if old_dom_sid == dom_sid:
                return

            raise errors.ValidationError(name=_('range exists'),
                    error=_('ID range with the same name but different ' \
                            'domain SID already exists. The ID range for ' \
                            'the new trusted domain must be created manually.'))

        if 'base_id' in options:
            base_id = options['base_id']
        else:
            base_id = 200000 + (pysss_murmur.murmurhash3(
                dom_sid, len(dom_sid), 0xdeadbeef) % 10000) * 200000

        try:
            new_range = api.Command['idrange_add'](
                range_name,
                ipabaseid=base_id,
                ipaidrangesize=options['range_size'],
                ipabaserid=0,
                ipanttrusteddomainsid=dom_sid)
        except Exception, e:
            raise errors.ValidationError(
                name=_('ID range exists'),
                error=_('ID range already exists, must be added manually'))
Beispiel #14
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']
    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,
    )
Beispiel #15
0
    perm = perm.strip().lower()
    if perm not in _valid_permissions_values:
        return '"%s" is not a valid permission' % perm


def _normalize_permissions(perm):
    valid_permissions = []
    perm = perm.strip().lower()
    if perm not in valid_permissions:
        valid_permissions.append(perm)
    return ','.join(valid_permissions)

_prefix_option = StrEnum('aciprefix',
                cli_name='prefix',
                label=_('ACI prefix'),
                doc=_('Prefix used to distinguish ACI types ' \
                    '(permission, delegation, selfservice, none)'),
                values=_valid_prefix_values,
                )


@register()
class aci(Object):
    """
    ACI object.
    """
    NO_CLI = True

    label = _('ACIs')

    takes_params = (
Beispiel #16
0
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_blacklist_option': 'userignoreobjectclass',
            'attr_blacklist_option': 'userignoreattribute',
            'pre_callback': _pre_migrate_user,
            'post_callback': _post_migrate_user,
            'exc_callback': None
        },
        'group': {
            'filter_template': '(&(|%s)(cn=*))',
            'oc_option': 'groupobjectclass',
            'oc_blacklist_option': 'groupignoreobjectclass',
            'attr_blacklist_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=_('Comma-separated list of objectclasses used to search for user entries in DS'),
            csv=True,
            default=(u'person',),
            autofill=True,
        ),
        Str('groupobjectclass+',
            cli_name='group_objectclass',
            label=_('Group object class'),
            doc=_('Comma-separated list of objectclasses used to search for group entries in DS'),
            csv=True,
            default=(u'groupOfUniqueNames', u'groupOfNames'),
            autofill=True,
        ),
        Str('userignoreobjectclass*',
            cli_name='user_ignore_objectclass',
            label=_('Ignore user object class'),
            doc=_('Comma-separated list of objectclasses to be ignored for user entries in DS'),
            csv=True,
            default=tuple(),
            autofill=True,
        ),
        Str('userignoreattribute*',
            cli_name='user_ignore_attribute',
            label=_('Ignore user attribute'),
            doc=_('Comma-separated list of attributes to be ignored for user entries in DS'),
            csv=True,
            default=tuple(),
            autofill=True,
        ),
        Str('groupignoreobjectclass*',
            cli_name='group_ignore_objectclass',
            label=_('Ignore group object class'),
            doc=_('Comma-separated list of objectclasses to be ignored for group entries in DS'),
            csv=True,
            default=tuple(),
            autofill=True,
        ),
        Str('groupignoreattribute*',
            cli_name='group_ignore_attribute',
            label=_('Ignore group attribute'),
            doc=_('Comma-separated list of attributes to be ignored for group entries in DS'),
            csv=True,
            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,
        ),
    )

    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 = _('comma-separated list of %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''')

    migration_disabled_msg = _('''\
Migration mode is disabled. Use \'ipa config-mod\' to enable it.''')

    pwd_migration_msg = _('''\
Passwords have been migrated in pre-hashed format.
IPA is unable to generate Kerberos keys unless provided
with clear text passwords. All migrated users need to
login at https://your.domain/ipa/migration/ before they
can use their Kerberos accounts.''')

    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,
                      csv=True,
                      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.
        """
        for p in self.params():
            if p.csv:
                if options[p.name]:
                    options[p.name] = tuple(v.lower() for v in options[p.name])
                else:
                    options[p.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()
        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],
                    _ldap.SCOPE_ONELEVEL,
                    time_limit=0,
                    size_limit=-1,
                    search_refs=True  # migrated DS may contain search references
                )
            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:
                self.log.error('%s: %s' %
                               (ldap_obj.name, self.truncated_err_msg))

            blacklists = {}
            for blacklist in ('oc_blacklist', 'attr_blacklist'):
                blacklist_option = self.migrate_objects[ldap_obj_name][
                    blacklist + '_option']
                if blacklist_option is not None:
                    blacklists[blacklist] = options.get(
                        blacklist_option, tuple())
                else:
                    blacklists[blacklist] = tuple()

            # get default primary group for new users
            if 'def_group_dn' not in context:
                def_group = config.get('ipadefaultprimarygroup')
                context['def_group_dn'] = api.Object.group.get_dn(def_group)
                try:
                    (g_dn, g_attrs) = 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)
                if 'gidnumber' in g_attrs:
                    context['def_group_gid'] = g_attrs['gidnumber'][0]

            context['has_upg'] = ldap.has_upg()

            valid_gids = []
            invalid_gids = []
            context['migrate_cnt'] = 0
            migrate_cnt = 0
            for (dn, entry_attrs) in entries:
                context['migrate_cnt'] = migrate_cnt
                s = datetime.datetime.now()
                if dn is None:  # LDAP search reference
                    failed[ldap_obj_name][entry_attrs[0]] = unicode(
                        _ref_err_msg)
                    continue

                try:
                    dn = DN(dn)
                except ValueError:
                    failed[ldap_obj_name][dn] = unicode(_dn_err_msg)
                    continue

                ava = 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

                dn = ldap_obj.get_dn(pkey)
                assert isinstance(dn, DN)
                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:
                        dn = callback(ldap,
                                      pkey,
                                      dn,
                                      entry_attrs,
                                      failed[ldap_obj_name],
                                      config,
                                      context,
                                      schema=options['schema'],
                                      search_bases=search_bases,
                                      valid_gids=valid_gids,
                                      invalid_gids=invalid_gids,
                                      **blacklists)
                        assert isinstance(dn, DN)
                        if not dn:
                            continue
                    except errors.NotFound, e:
                        failed[ldap_obj_name][pkey] = unicode(e.reason)
                        continue

                try:
                    ldap.add_entry(dn, entry_attrs)
                except errors.ExecutionError, e:
                    callback = self.migrate_objects[ldap_obj_name][
                        'exc_callback']
                    if callable(callback):
                        try:
                            callback(ldap, dn, entry_attrs, e, options)
                        except errors.ExecutionError, e:
                            failed[ldap_obj_name][pkey] = unicode(e)
                            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,
                        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:
                    api.log.info("%d %ss migrated. %s elapsed." %
                                 (migrate_cnt, ldap_obj_name, total_dur))
                api.log.debug("%d %ss migrated, duration: %s (total %s)" %
                              (migrate_cnt, ldap_obj_name, d, total_dur))
Beispiel #17
0
class server_state(crud.PKQuery):
    __doc__ = _("Set enabled/hidden state of a server.")

    takes_options = (StrEnum(
        'state',
        values=(u'enabled', u'hidden'),
        label=_('State'),
        doc=_('Server state'),
        flags={'virtual_attribute', 'no_create', 'no_search'},
    ), )

    msg_summary = _('Changed server state of "%(value)s".')

    has_output = output.standard_boolean

    def _check_hide_server(self, fqdn):
        result = self.api.Command.config_show()['result']
        err = []
        # single value entries
        if result.get("ca_renewal_master_server") == fqdn:
            err.append(_("Cannot hide CA renewal master."))
        if result.get("dnssec_key_master_server") == fqdn:
            err.append(_("Cannot hide DNSSec key master."))
        # multi value entries, only fail if we are the last one
        checks = [
            ("ca_server_server", "CA"),
            ("dns_server_server", "DNS"),
            ("ipa_master_server", "IPA"),
            ("kra_server_server", "KRA"),
        ]
        for key, name in checks:
            values = result.get(key, [])
            if values == [fqdn]:  # fqdn is the only entry
                err.append(
                    _("Cannot hide last enabled %(name)s server.") %
                    {'name': name})
        if err:
            raise errors.ValidationError(name=fqdn,
                                         error=' '.join(str(e) for e in err))

    def execute(self, *keys, **options):
        fqdn = keys[0]
        if options['state'] == u'enabled':
            to_status = ENABLED
            from_status = HIDDEN
        else:
            to_status = HIDDEN
            from_status = ENABLED

        roles = self.api.Command.server_role_find(
            server_server=fqdn,
            status=from_status,
            include_master=True,
        )['result']
        from_roles = [r[u'role_servrole'] for r in roles]
        if not from_roles:
            # no server role is in source status
            raise errors.EmptyModlist

        if to_status == ENABLED:
            enable_services(fqdn)
        else:
            self._check_hide_server(fqdn)
            hide_services(fqdn)

        # update system roles
        result = self.api.Command.dns_update_system_records()
        if not result.get('value'):
            self.add_message(messages.AutomaticDNSRecordsUpdateFailed())

        return {
            'value': fqdn,
            'result': True,
        }
Beispiel #18
0
class dnsserver(LDAPObject):
    """
    DNS Servers
    """
    container_dn = api.env.container_dnsservers
    object_name = _('DNS server')
    object_name_plural = _('DNS servers')
    object_class = dnsserver_object_class
    default_attributes = [
        'idnsServerId',
        'idnsSOAmName',
        'idnsForwarders',
        'idnsForwardPolicy',
    ]
    label = _('DNS Servers')
    label_singular = _('DNS Server')

    permission_filter_objectclasses = ['idnsServerConfigObject']

    managed_permissions = {
        'System: Read DNS Servers Configuration': {
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'idnsServerId',
                'idnsSOAmName',
                'idnsForwarders',
                'idnsForwardPolicy',
                'idnsSubstitutionVariable',
            },
            'ipapermlocation': api.env.basedn,
            'default_privileges': {'DNS Servers', 'DNS Administrators'},
        },
        'System: Modify DNS Servers Configuration': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'idnsSOAmName',
                'idnsForwarders',
                'idnsForwardPolicy',
                'idnsSubstitutionVariable',
            },
            'ipapermlocation': api.env.basedn,
            'default_privileges': {'DNS Administrators'},
        },
    }

    takes_params = (
        Str(
            'idnsserverid',
            hostname_validator,
            cli_name='hostname',
            primary_key=True,
            label=_('Server name'),
            doc=_('DNS Server name'),
            normalizer=normalize_hostname,
        ),
        DNSNameParam(
            'idnssoamname?',
            cli_name='soa_mname_override',
            label=_('SOA mname override'),
            doc=_('SOA mname (authoritative server) override'),
        ),
        Str(
            'idnsforwarders*',
            validate_bind_forwarder,
            cli_name='forwarder',
            label=_('Forwarders'),
            doc=_('Per-server forwarders. A custom port can be specified '
                  'for each forwarder using a standard format '
                  '"IP_ADDRESS port PORT"'),
        ),
        StrEnum(
            'idnsforwardpolicy?',
            cli_name='forward_policy',
            label=_('Forward policy'),
            doc=_('Per-server conditional forwarding policy. Set to "none" to '
                  'disable forwarding to global forwarder for this zone. In '
                  'that case, conditional zone forwarders are disregarded.'),
            values=(u'only', u'first', u'none'),
        ),
    )

    def get_dn(self, *keys, **options):
        if not dns_container_exists(self.api.Backend.ldap2):
            raise errors.NotFound(reason=_('DNS is not configured'))
        return super(dnsserver, self).get_dn(*keys, **options)
Beispiel #19
0
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)
Beispiel #20
0
class netgroup(LDAPObject):
    """
    Netgroup object.
    """
    container_dn = api.env.container_netgroup
    object_name = _('netgroup')
    object_name_plural = _('netgroups')
    object_class = ['ipaobject', 'ipaassociation', 'ipanisnetgroup']
    permission_filter_objectclasses = ['ipanisnetgroup']
    default_attributes = [
        'cn',
        'description',
        'memberof',
        'externalhost',
        'nisdomainname',
        'memberuser',
        'memberhost',
        'member',
        'memberindirect',
        'usercategory',
        'hostcategory',
    ]
    uuid_attribute = 'ipauniqueid'
    rdn_attribute = 'ipauniqueid'
    attribute_members = {
        'member': ['netgroup'],
        'memberof': ['netgroup'],
        'memberindirect': ['netgroup'],
        'memberuser': ['user', 'group'],
        'memberhost': ['host', 'hostgroup'],
    }
    relationships = {
        'member': ('Member', '', 'no_'),
        'memberof': ('Member Of', 'in_', 'not_in_'),
        'memberindirect': ('Indirect Member', None, 'no_indirect_'),
        'memberuser': ('Member', '', 'no_'),
        'memberhost': ('Member', '', 'no_'),
    }
    managed_permissions = {
        'System: Read Netgroups': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'description',
                'hostcategory',
                'ipaenabledflag',
                'ipauniqueid',
                'nisdomainname',
                'usercategory',
                'objectclass',
            },
        },
        'System: Read Netgroup Membership': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'externalhost',
                'member',
                'memberof',
                'memberuser',
                'memberhost',
                'objectclass',
            },
        },
        'System: Add Netgroups': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Add netgroups";allow (add) groupdn = "ldap:///cn=Add netgroups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Netgroups Administrators'},
        },
        'System: Modify Netgroup Membership': {
            'ipapermright': {'write'},
            'ipapermdefaultattr':
            {'externalhost', 'member', 'memberhost', 'memberuser'},
            'replaces': [
                '(targetattr = "memberhost || externalhost || memberuser || member")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Modify netgroup membership";allow (write) groupdn = "ldap:///cn=Modify netgroup membership,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Netgroups Administrators'},
        },
        'System: Modify Netgroups': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'description'},
            'replaces': [
                '(targetattr = "description")(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0; acl "permission:Modify netgroups";allow (write) groupdn = "ldap:///cn=Modify netgroups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Netgroups Administrators'},
        },
        'System: Remove Netgroups': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///ipauniqueid=*,cn=ng,cn=alt,$SUFFIX")(version 3.0;acl "permission:Remove netgroups";allow (delete) groupdn = "ldap:///cn=Remove netgroups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Netgroups Administrators'},
        },
        'System: Read Netgroup Compat Tree': {
            'non_object': True,
            'ipapermbindruletype': 'anonymous',
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN('cn=ng', 'cn=compat', api.env.basedn),
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'cn',
                'membernisnetgroup',
                'nisnetgrouptriple',
            },
        },
    }

    label = _('Netgroups')
    label_singular = _('Netgroup')

    takes_params = (
        Str(
            'cn',
            pattern=NETGROUP_PATTERN,
            pattern_errmsg=NETGROUP_PATTERN_ERRMSG,
            cli_name='name',
            label=_('Netgroup name'),
            primary_key=True,
            normalizer=lambda value: value.lower(),
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('Netgroup description'),
        ),
        Str(
            'nisdomainname?',
            pattern=NISDOMAIN_PATTERN,
            pattern_errmsg=NISDOMAIN_PATTERN_ERRMSG,
            cli_name='nisdomain',
            label=_('NIS domain name'),
        ),
        Str(
            'ipauniqueid?',
            cli_name='uuid',
            label='IPA unique ID',
            doc=_('IPA unique ID'),
            flags=['no_create', 'no_update'],
        ),
        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', ),
        ),
        external_host_param,
    )
Beispiel #21
0
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)
Beispiel #22
0
class vault_archive_internal(PKQuery):
    __doc__ = _('Archive data into a vault.')

    NO_CLI = True

    takes_options = vault_options + (
        Bytes(
            'session_key',
            doc=_('Session key wrapped with transport certificate'),
        ),
        Bytes(
            'vault_data',
            doc=_('Vault data encrypted with session key'),
        ),
        Bytes(
            'nonce',
            doc=_('Nonce'),
        ),
        StrEnum(
            'wrapping_algo?',
            doc=_('Key wrapping algorithm'),
            values=VAULT_WRAPPING_SUPPORTED_ALGOS,
            default=VAULT_WRAPPING_DEFAULT_ALGO,
            autofill=True,
        ),
    )

    has_output = output.standard_entry

    msg_summary = _('Archived data into vault "%(value)s"')

    def execute(self, *args, **options):

        if not self.api.Command.kra_is_enabled()['result']:
            raise errors.InvocationError(
                format=_('KRA service is not enabled'))

        wrapped_vault_data = options.pop('vault_data')
        nonce = options.pop('nonce')
        wrapped_session_key = options.pop('session_key')

        wrapping_algo = options.pop('wrapping_algo', None)
        algorithm_oid = self.obj._translate_algorithm(wrapping_algo)

        # retrieve vault info
        vault = self.api.Command.vault_show(*args, **options)['result']

        # connect to KRA
        with self.api.Backend.kra.get_client() as kra_client:
            kra_account = pki.account.AccountClient(kra_client.connection)
            kra_account.login()

            client_key_id = self.obj.get_key_id(vault['dn'])

            # deactivate existing vault record in KRA
            response = kra_client.keys.list_keys(
                client_key_id,
                pki.key.KeyClient.KEY_STATUS_ACTIVE)

            for key_info in response.key_infos:
                kra_client.keys.modify_key_status(
                    key_info.get_key_id(),
                    pki.key.KeyClient.KEY_STATUS_INACTIVE)

            # forward wrapped data to KRA
            kra_client.keys.archive_encrypted_data(
                client_key_id,
                pki.key.KeyClient.PASS_PHRASE_TYPE,
                wrapped_vault_data,
                wrapped_session_key,
                algorithm_oid=algorithm_oid,
                nonce_iv=nonce,
            )

            kra_account.logout()

        response = {
            'value': args[-1],
            'result': {},
        }

        response['summary'] = self.msg_summary % response

        return response
Beispiel #23
0
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]
Beispiel #24
0
class vault_retrieve_internal(PKQuery):
    __doc__ = _('Retrieve data from a vault.')

    NO_CLI = True

    takes_options = vault_options + (
        Bytes(
            'session_key',
            doc=_('Session key wrapped with transport certificate'),
        ),
        StrEnum(
            'wrapping_algo?',
            doc=_('Key wrapping algorithm'),
            values=VAULT_WRAPPING_SUPPORTED_ALGOS,
            default=VAULT_WRAPPING_DEFAULT_ALGO,
            autofill=True,
        ),
    )

    has_output = output.standard_entry

    msg_summary = _('Retrieved data from vault "%(value)s"')

    def execute(self, *args, **options):

        if not self.api.Command.kra_is_enabled()['result']:
            raise errors.InvocationError(
                format=_('KRA service is not enabled'))

        wrapped_session_key = options.pop('session_key')

        wrapping_algo = options.pop('wrapping_algo', None)
        algorithm_oid = self.obj._translate_algorithm(wrapping_algo)

        # retrieve vault info
        vault = self.api.Command.vault_show(*args, **options)['result']

        # connect to KRA
        with self.api.Backend.kra.get_client() as kra_client:
            kra_account = pki.account.AccountClient(kra_client.connection)
            kra_account.login()

            client_key_id = self.obj.get_key_id(vault['dn'])

            # find vault record in KRA
            response = kra_client.keys.list_keys(
                client_key_id,
                pki.key.KeyClient.KEY_STATUS_ACTIVE)

            if not len(response.key_infos):
                raise errors.NotFound(reason=_('No archived data.'))

            key_info = response.key_infos[0]

            # XXX hack
            kra_client.keys.encrypt_alg_oid = algorithm_oid

            # retrieve encrypted data from KRA
            key = kra_client.keys.retrieve_key(
                key_info.get_key_id(),
                wrapped_session_key)

            kra_account.logout()

        response = {
            'value': args[-1],
            'result': {
                'vault_data': key.encrypted_data,
                'nonce': key.nonce_data,
            },
        }

        response['summary'] = self.msg_summary % response

        return response
Beispiel #25
0
class idrange(LDAPObject):
    """
    Range object.
    """

    range_type = ('domain', 'ad', 'ipa')
    container_dn = api.env.container_ranges
    object_name = ('range')
    object_name_plural = ('ranges')
    object_class = ['ipaIDrange']
    permission_filter_objectclasses = ['ipaidrange']
    possible_objectclasses = ['ipadomainidrange', 'ipatrustedaddomainrange']
    default_attributes = [
        'cn', 'ipabaseid', 'ipaidrangesize', 'ipabaserid',
        'ipasecondarybaserid', 'ipanttrusteddomainsid', 'iparangetype'
    ]
    managed_permissions = {
        'System: Read ID Ranges': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'objectclass',
                'ipabaseid',
                'ipaidrangesize',
                'iparangetype',
                'ipabaserid',
                'ipasecondarybaserid',
                'ipanttrusteddomainsid',
            },
        },
    }

    label = _('ID Ranges')
    label_singular = _('ID Range')

    # The commented range types are planned but not yet supported
    range_types = {
        u'ipa-local':
        unicode(_('local domain range')),
        # u'ipa-ad-winsync': unicode(_('Active Directory winsync range')),
        u'ipa-ad-trust':
        unicode(_('Active Directory domain range')),
        u'ipa-ad-trust-posix':
        unicode(_('Active Directory trust range with '
                  'POSIX attributes')),
        # u'ipa-ipa-trust': unicode(_('IPA trust range')),
    }

    takes_params = (Str(
        'cn',
        cli_name='name',
        label=_('Range name'),
        primary_key=True,
    ),
                    Int(
                        'ipabaseid',
                        cli_name='base_id',
                        label=_("First Posix ID of the range"),
                    ),
                    Int(
                        'ipaidrangesize',
                        cli_name='range_size',
                        label=_("Number of IDs in the range"),
                    ),
                    Int(
                        'ipabaserid?',
                        cli_name='rid_base',
                        label=_('First RID of the corresponding RID range'),
                    ),
                    Int(
                        'ipasecondarybaserid?',
                        cli_name='secondary_rid_base',
                        label=_('First RID of the secondary RID range'),
                    ),
                    Str(
                        'ipanttrusteddomainsid?',
                        cli_name='dom_sid',
                        flags=('no_update', ),
                        label=_('Domain SID of the trusted domain'),
                    ),
                    Str(
                        'ipanttrusteddomainname?',
                        cli_name='dom_name',
                        flags=('no_search', 'virtual_attribute', 'no_update'),
                        label=_('Name of the trusted domain'),
                    ),
                    StrEnum(
                        'iparangetype?',
                        label=_('Range type'),
                        cli_name='type',
                        doc=(_('ID range type, one of {vals}'.format(
                            vals=', '.join(sorted(range_types))))),
                        values=sorted(range_types),
                        flags=['no_update'],
                    ))

    def handle_iparangetype(self,
                            entry_attrs,
                            options,
                            keep_objectclass=False):
        if not any(
            (options.get('pkey_only', False), options.get('raw', False))):
            range_type = entry_attrs['iparangetype'][0]
            entry_attrs['iparangetyperaw'] = [range_type]
            entry_attrs['iparangetype'] = [
                self.range_types.get(range_type, None)
            ]

        # Remove the objectclass
        if not keep_objectclass:
            if not options.get('all', False) or options.get(
                    'pkey_only', False):
                entry_attrs.pop('objectclass', None)

    def handle_ipabaserid(self, entry_attrs, options):
        if any((options.get('pkey_only', False), options.get('raw', False))):
            return
        if entry_attrs['iparangetype'][0] == u'ipa-ad-trust-posix':
            entry_attrs.pop('ipabaserid', None)

    def check_ids_in_modified_range(self, old_base, old_size, new_base,
                                    new_size):
        if new_base is None and new_size is None:
            # nothing to check
            return
        if new_base is None:
            new_base = old_base
        if new_size is None:
            new_size = old_size
        old_interval = (old_base, old_base + old_size - 1)
        new_interval = (new_base, new_base + new_size - 1)
        checked_intervals = []
        low_diff = new_interval[0] - old_interval[0]
        if low_diff > 0:
            checked_intervals.append(
                (old_interval[0], min(old_interval[1], new_interval[0] - 1)))
        high_diff = old_interval[1] - new_interval[1]
        if high_diff > 0:
            checked_intervals.append(
                (max(old_interval[0], new_interval[1] + 1), old_interval[1]))

        if not checked_intervals:
            # range is equal or covers the entire old range, nothing to check
            return

        ldap = self.backend
        id_filter_base = [
            "(objectclass=posixAccount)", "(objectclass=posixGroup)",
            "(objectclass=ipaIDObject)"
        ]
        id_filter_ids = []

        for id_low, id_high in checked_intervals:
            id_filter_ids.append(
                "(&(uidNumber>=%(low)d)(uidNumber<=%(high)d))" %
                dict(low=id_low, high=id_high))
            id_filter_ids.append(
                "(&(gidNumber>=%(low)d)(gidNumber<=%(high)d))" %
                dict(low=id_low, high=id_high))
        id_filter = ldap.combine_filters([
            ldap.combine_filters(id_filter_base, "|"),
            ldap.combine_filters(id_filter_ids, "|")
        ], "&")

        try:
            ldap.find_entries(filter=id_filter,
                              attrs_list=['uid', 'cn'],
                              base_dn=DN(api.env.container_accounts,
                                         api.env.basedn))
        except errors.NotFound:
            # no objects in this range found, allow the command
            pass
        else:
            raise errors.ValidationError(
                name="ipabaseid,ipaidrangesize",
                error=_('range modification leaving objects with ID out '
                        'of the defined range is not allowed'))

    def get_domain_validator(self):
        if not _dcerpc_bindings_installed:
            raise errors.NotFound(reason=_(
                'Cannot perform SID validation '
                'without Samba 4 support installed. Make sure you have '
                'installed server-trust-ad sub-package of IPA on the server'))

        domain_validator = ipaserver.dcerpc.DomainValidator(self.api)

        if not domain_validator.is_configured():
            raise errors.NotFound(reason=_(
                'Cross-realm trusts are not '
                'configured. Make sure you have run ipa-adtrust-install '
                'on the IPA server first'))

        return domain_validator

    def validate_trusted_domain_sid(self, sid):

        domain_validator = self.get_domain_validator()

        if not domain_validator.is_trusted_domain_sid_valid(sid):
            raise errors.ValidationError(
                name='domain SID',
                error=_('SID is not recognized as a valid SID for a '
                        'trusted domain'))

    def get_trusted_domain_sid_from_name(self, name):
        """ Returns unicode string representation for given trusted domain name
        or None if SID forthe given trusted domain name could not be found."""

        domain_validator = self.get_domain_validator()

        sid = domain_validator.get_sid_from_domain_name(name)

        if sid is not None:
            sid = unicode(sid)

        return sid

    # checks that primary and secondary rid ranges do not overlap
    def are_rid_ranges_overlapping(self, rid_base, secondary_rid_base, size):

        # if any of these is None, the check does not apply
        if any(attr is None for attr in (rid_base, secondary_rid_base, size)):
            return False

        # sort the bases
        if rid_base > secondary_rid_base:
            rid_base, secondary_rid_base = secondary_rid_base, rid_base

        # rid_base is now <= secondary_rid_base,
        # so the following check is sufficient
        if rid_base + size <= secondary_rid_base:
            return False
        else:
            return True
Beispiel #26
0
class vault(LDAPObject):
    __doc__ = _("""
    Vault object.
    """)

    container_dn = api.env.container_vault

    object_name = _('vault')
    object_name_plural = _('vaults')

    object_class = ['ipaVault']
    permission_filter_objectclasses = ['ipaVault']
    default_attributes = [
        'cn',
        'description',
        'ipavaulttype',
        'ipavaultsalt',
        'ipavaultpublickey',
        'owner',
        'member',
    ]
    search_display_attributes = [
        'cn',
        'description',
        'ipavaulttype',
    ]
    attribute_members = {
        'owner': ['user', 'group', 'service'],
        'member': ['user', 'group', 'service'],
    }

    label = _('Vaults')
    label_singular = _('Vault')

    managed_permissions = {
        'System: Read Vaults': {
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN(api.env.container_vault, api.env.basedn),
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass', 'cn', 'description', 'ipavaulttype',
                'ipavaultsalt', 'ipavaultpublickey', 'owner', 'member',
                'memberuser', 'memberhost',
            },
            'default_privileges': {'Vault Administrators'},
        },
        'System: Add Vaults': {
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN(api.env.container_vault, api.env.basedn),
            'ipapermright': {'add'},
            'default_privileges': {'Vault Administrators'},
        },
        'System: Delete Vaults': {
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN(api.env.container_vault, api.env.basedn),
            'ipapermright': {'delete'},
            'default_privileges': {'Vault Administrators'},
        },
        'System: Modify Vaults': {
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN(api.env.container_vault, api.env.basedn),
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'objectclass', 'cn', 'description', 'ipavaulttype',
                'ipavaultsalt', 'ipavaultpublickey',
            },
            'default_privileges': {'Vault Administrators'},
        },
        'System: Manage Vault Ownership': {
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN(api.env.container_vault, api.env.basedn),
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'owner',
            },
            'default_privileges': {'Vault Administrators'},
        },
        'System: Manage Vault Membership': {
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN(api.env.container_vault, api.env.basedn),
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'member',
            },
            'default_privileges': {'Vault Administrators'},
        },
    }

    takes_params = (
        Str(
            'cn',
            cli_name='name',
            label=_('Vault name'),
            primary_key=True,
            pattern='^[a-zA-Z0-9_.-]+$',
            pattern_errmsg='may only include letters, numbers, _, ., and -',
            maxlength=255,
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('Vault description'),
        ),
        StrEnum(
            'ipavaulttype?',
            cli_name='type',
            label=_('Type'),
            doc=_('Vault type'),
            values=(u'standard', u'symmetric', u'asymmetric', ),
            default=u'symmetric',
            autofill=True,
        ),
        Bytes(
            'ipavaultsalt?',
            cli_name='salt',
            label=_('Salt'),
            doc=_('Vault salt'),
            flags=['no_search'],
        ),
        Bytes(
            'ipavaultpublickey?',
            cli_name='public_key',
            label=_('Public key'),
            doc=_('Vault public key'),
            flags=['no_search'],
        ),
        Str(
            'owner_user?',
            label=_('Owner users'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'owner_group?',
            label=_('Owner groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'owner_service?',
            label=_('Owner services'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'owner?',
            label=_('Failed owners'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'service?',
            label=_('Vault service'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Flag(
            'shared?',
            label=_('Shared vault'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'username?',
            label=_('Vault user'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
    )

    def _translate_algorithm(self, name):
        if name is None:
            name = VAULT_WRAPPING_DEFAULT_ALGO
        if name not in VAULT_WRAPPING_SUPPORTED_ALGOS:
            msg = _("{algo} is not a supported vault wrapping algorithm")
            raise errors.ValidationError(msg.format(algo=name))
        if name == VAULT_WRAPPING_3DES:
            return DES_EDE3_CBC_OID
        elif name == VAULT_WRAPPING_AES128_CBC:
            return AES_128_CBC_OID
        else:
            # unreachable
            raise ValueError(name)

    def get_dn(self, *keys, **options):
        """
        Generates vault DN from parameters.
        """
        service = options.get('service')
        shared = options.get('shared')
        user = options.get('username')

        count = (bool(service) + bool(shared) + bool(user))
        if count > 1:
            raise errors.MutuallyExclusiveError(
                reason=_('Service, shared, and user options ' +
                         'cannot be specified simultaneously'))

        # TODO: create container_dn after object initialization then reuse it
        container_dn = DN(self.container_dn, self.api.env.basedn)

        dn = super(vault, self).get_dn(*keys, **options)
        assert dn.endswith(container_dn)
        rdns = DN(*dn[:-len(container_dn)])

        if not count:
            principal = kerberos.Principal(getattr(context, 'principal'))

            if principal.is_host:
                raise errors.NotImplementedError(
                    reason=_('Host is not supported'))
            elif principal.is_service:
                service = unicode(principal)
            else:
                user = principal.username

        if service:
            parent_dn = DN(('cn', service), ('cn', 'services'), container_dn)
        elif shared:
            parent_dn = DN(('cn', 'shared'), container_dn)
        elif user:
            parent_dn = DN(('cn', user), ('cn', 'users'), container_dn)
        else:
            raise RuntimeError

        return DN(rdns, parent_dn)

    def create_container(self, dn, owner_dn):
        """
        Creates vault container and its parents.
        """

        # TODO: create container_dn after object initialization then reuse it
        container_dn = DN(self.container_dn, self.api.env.basedn)

        entries = []

        while dn:
            assert dn.endswith(container_dn)

            rdn = dn[0]
            entry = self.backend.make_entry(
                dn,
                {
                    'objectclass': ['ipaVaultContainer'],
                    'cn': rdn['cn'],
                    'owner': [owner_dn],
                })

            # if entry can be added, return
            try:
                self.backend.add_entry(entry)
                break

            except errors.NotFound:
                pass

            # otherwise, create parent entry first
            dn = DN(*dn[1:])
            entries.insert(0, entry)

        # then create the entries again
        for entry in entries:
            self.backend.add_entry(entry)

    def get_key_id(self, dn):
        """
        Generates a client key ID to archive/retrieve data in KRA.
        """

        # TODO: create container_dn after object initialization then reuse it
        container_dn = DN(self.container_dn, self.api.env.basedn)

        # make sure the DN is a vault DN
        if not dn.endswith(container_dn, 1):
            raise ValueError('Invalid vault DN: %s' % dn)

        # construct the vault ID from the bottom up
        id = u''
        for rdn in dn[:-len(container_dn)]:
            name = rdn['cn']
            id = u'/' + name + id

        return 'ipa:' + id

    def get_container_attribute(self, entry, options):
        if options.get('raw', False):
            return
        container_dn = DN(self.container_dn, self.api.env.basedn)
        if entry.dn.endswith(DN(('cn', 'services'), container_dn)):
            entry['service'] = entry.dn[1]['cn']
        elif entry.dn.endswith(DN(('cn', 'shared'), container_dn)):
            entry['shared'] = True
        elif entry.dn.endswith(DN(('cn', 'users'), container_dn)):
            entry['username'] = entry.dn[1]['cn']
Beispiel #27
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,
    )
Beispiel #28
0
    perm = perm.strip().lower()
    if perm not in _valid_permissions_values:
        return '"%s" is not a valid permission' % perm


def _normalize_permissions(perm):
    valid_permissions = []
    perm = perm.strip().lower()
    if perm not in valid_permissions:
        valid_permissions.append(perm)
    return ','.join(valid_permissions)

_prefix_option = StrEnum('aciprefix',
                cli_name='prefix',
                label=_('ACI prefix'),
                doc=_('Prefix used to distinguish ACI types ' \
                    '(permission, delegation, selfservice, none)'),
                values=_valid_prefix_values,
                flags={'no_create', 'no_update', 'no_search'},
                )


@register()
class aci(Object):
    """
    ACI object.
    """
    NO_CLI = True

    label = _('ACIs')

    takes_params = (
Beispiel #29
0
class baseuser(LDAPObject):
    """
    baseuser object.
    """

    stage_container_dn        = api.env.container_stageuser
    active_container_dn       = api.env.container_user
    delete_container_dn       = api.env.container_deleteuser
    object_class = ['posixaccount']
    object_class_config = 'ipauserobjectclasses'
    possible_objectclasses = [
        'meporiginentry', 'ipauserauthtypeclass', 'ipauser',
        'ipatokenradiusproxyuser', 'ipacertmapobject'
    ]
    disallow_object_classes = ['krbticketpolicyaux']
    permission_filter_objectclasses = ['posixaccount']
    search_attributes_config = 'ipausersearchfields'
    default_attributes = [
        'uid', 'givenname', 'sn', 'homedirectory', 'loginshell',
        'uidnumber', 'gidnumber', 'mail', 'ou',
        'telephonenumber', 'title', 'memberof', 'nsaccountlock',
        'memberofindirect', 'ipauserauthtype', 'userclass',
        'ipatokenradiusconfiglink', 'ipatokenradiususername',
        'krbprincipalexpiration', 'usercertificate;binary',
        'krbprincipalname', 'krbcanonicalname',
        'ipacertmapdata'
    ]
    search_display_attributes = [
        'uid', 'givenname', 'sn', 'homedirectory', 'krbcanonicalname',
        'krbprincipalname', 'loginshell',
        'mail', 'telephonenumber', 'title', 'nsaccountlock',
        'uidnumber', 'gidnumber', 'sshpubkeyfp',
    ]
    uuid_attribute = 'ipauniqueid'
    attribute_members = {
        'manager': ['user'],
        'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
        'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
    }
    allow_rename = True
    bindable = True
    password_attributes = [('userpassword', 'has_password'),
                           ('krbprincipalkey', 'has_keytab')]
    label = _('Users')
    label_singular = _('User')

    takes_params = (
        Str('uid',
            pattern=PATTERN_GROUPUSER_NAME,
            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'),
            default_from=lambda givenname, sn: '%s %s' % (givenname, sn),
            autofill=True,
        ),
        Str('loginshell?',
            cli_name='shell',
            label=_('Login shell'),
        ),
        Principal(
            'krbcanonicalname?',
            validate_realm,
            label=_('Principal name'),
            flags={'no_option', 'no_create', 'no_update', 'no_search'},
            normalizer=normalize_user_principal
        ),
        Principal(
            'krbprincipalname*',
            validate_realm,
            cli_name='principal',
            label=_('Principal alias'),
            default_from=lambda uid: kerberos.Principal(
                uid.lower(), realm=api.env.realm),
            autofill=True,
            normalizer=normalize_user_principal,
        ),
        DateTime('krbprincipalexpiration?',
            cli_name='principal_expiration',
            label=_('Kerberos principal expiration'),
        ),
        DateTime('krbpasswordexpiration?',
            cli_name='password_expiration',
            label=_('User password expiration'),
        ),
        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)'),
            minvalue=1,
        ),
        Int('gidnumber?',
            label=_('GID'),
            doc=_('Group ID Number'),
            minvalue=1,
        ),
        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'),
        ),
        # keep backward compatibility using single value manager option
        Str('manager?',
            label=_('Manager'),
        ),
        Str('carlicense*',
            label=_('Car License'),
        ),
        Str('ipasshpubkey*', validate_sshpubkey,
            cli_name='sshpubkey',
            label=_('SSH public key'),
            normalizer=normalize_sshpubkey,
            flags=['no_search'],
        ),
        Str('sshpubkeyfp*',
            label=_('SSH public key fingerprint'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        StrEnum('ipauserauthtype*',
            cli_name='user_auth_type',
            label=_('User authentication types'),
            doc=_('Types of supported user authentication'),
            values=(u'password', u'radius', u'otp'),
        ),
        Str('userclass*',
            cli_name='class',
            label=_('Class'),
            doc=_('User category (semantics placed on this attribute are for '
                  'local interpretation)'),
        ),
        Str('ipatokenradiusconfiglink?',
            cli_name='radius',
            label=_('RADIUS proxy configuration'),
        ),
        Str('ipatokenradiususername?',
            cli_name='radius_username',
            label=_('RADIUS proxy username'),
        ),
        Str('departmentnumber*',
            label=_('Department Number'),
        ),
        Str('employeenumber?',
            label=_('Employee Number'),
        ),
        Str('employeetype?',
            label=_('Employee Type'),
        ),
        Str('preferredlanguage?',
            label=_('Preferred Language'),
            pattern='^(([a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?(;q\=((0(\.[0-9]{0,3})?)|(1(\.0{0,3})?)))?' \
             + '(\s*,\s*[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?(;q\=((0(\.[0-9]{0,3})?)|(1(\.0{0,3})?)))?)*)|(\*))$',
            pattern_errmsg='must match RFC 2068 - 14.4, e.g., "da, en-gb;q=0.8, en;q=0.7"',
        ),
        Bytes('usercertificate*', validate_certificate,
            cli_name='certificate',
            label=_('Certificate'),
            doc=_('Base-64 encoded user certificate'),
        ),
        Str(
            'ipacertmapdata*',
            cli_name='certmapdata',
            label=_('Certificate mapping data'),
            doc=_('Certificate mapping data'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
    )

    def normalize_and_validate_email(self, email, config=None):
        if not config:
            config = self.backend.get_ipa_config()

        # 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, six.string_types):
                    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, container):
        """
        Given a userid verify the user's existence (in the appropriate containter) and return the dn.
        """
        if not manager:
            return None

        if not isinstance(manager, list):
            manager = [manager]

        try:
            container_dn = DN(container, api.env.basedn)
            for i, mgr in enumerate(manager):
                if isinstance(mgr, DN) and mgr.endswith(container_dn):
                    continue
                entry_attrs = self.backend.find_entry_by_attr(
                        self.primary_key.name, mgr, self.object_class, [''],
                        container_dn
                    )
                manager[i] = entry_attrs.dn
        except errors.NotFound:
            raise errors.NotFound(reason=_('manager %(manager)s not found') % dict(manager=mgr))

        return manager

    def _user_status(self, user, container):
        assert isinstance(user, DN)
        return user.endswith(container)

    def active_user(self, user):
        assert isinstance(user, DN)
        return self._user_status(user, DN(self.active_container_dn, api.env.basedn))

    def stage_user(self, user):
        assert isinstance(user, DN)
        return self._user_status(user, DN(self.stage_container_dn, api.env.basedn))

    def delete_user(self, user):
        assert isinstance(user, DN)
        return self._user_status(user, DN(self.delete_container_dn, api.env.basedn))

    def convert_usercertificate_pre(self, entry_attrs):
        if 'usercertificate' in entry_attrs:
            entry_attrs['usercertificate;binary'] = entry_attrs.pop(
                'usercertificate')

    def convert_usercertificate_post(self, entry_attrs, **options):
        if 'usercertificate;binary' in entry_attrs:
            entry_attrs['usercertificate'] = entry_attrs.pop(
                'usercertificate;binary')

    def convert_attribute_members(self, entry_attrs, *keys, **options):
        super(baseuser, self).convert_attribute_members(
            entry_attrs, *keys, **options)

        if options.get("raw", False):
            return

        # due the backward compatibility, managers have to be returned in
        # 'manager' attribute instead of 'manager_user'
        try:
            entry_attrs['failed_manager'] = entry_attrs.pop('manager')
        except KeyError:
            pass

        try:
            entry_attrs['manager'] = entry_attrs.pop('manager_user')
        except KeyError:
            pass
Beispiel #30
0
class aci(Object):
    """
    ACI object.
    """
    NO_CLI = True

    label = _('ACIs')

    takes_params = (
        Str('aciname',
            cli_name='name',
            label=_('ACI name'),
            primary_key=True,
            flags=('virtual_attribute',),
        ),
        Str('permission?',
            cli_name='permission',
            label=_('Permission'),
            doc=_('Permission ACI grants access to'),
            flags=('virtual_attribute',),
        ),
        Str('group?',
            cli_name='group',
            label=_('User group'),
            doc=_('User group ACI grants access to'),
            flags=('virtual_attribute',),
        ),
        Str('permissions+', validate_permissions,
            cli_name='permissions',
            label=_('Permissions'),
            doc=_('Permissions to grant' \
                '(read, write, add, delete, all)'),
            normalizer=_normalize_permissions,
            flags=('virtual_attribute',),
        ),
        Str('attrs*',
            cli_name='attrs',
            label=_('Attributes to which the permission applies'),
            doc=_('Attributes'),
            flags=('virtual_attribute',),
        ),
        StrEnum('type?',
            cli_name='type',
            label=_('Type'),
            doc=_('type of IPA object (user, group, host, hostgroup, service, netgroup)'),
            values=(u'user', u'group', u'host', u'service', u'hostgroup', u'netgroup', u'dnsrecord'),
            flags=('virtual_attribute',),
        ),
        Str('memberof?',
            cli_name='memberof',
            label=_('Member of'),  # FIXME: Does this label make sense?
            doc=_('Member of a group'),
            flags=('virtual_attribute',),
        ),
        Str('filter?',
            cli_name='filter',
            label=_('Filter'),
            doc=_('Legal LDAP filter (e.g. ou=Engineering)'),
            flags=('virtual_attribute',),
        ),
        Str('subtree?',
            cli_name='subtree',
            label=_('Subtree'),
            doc=_('Subtree to apply ACI to'),
            flags=('virtual_attribute',),
        ),
        Str('targetgroup?',
            cli_name='targetgroup',
            label=_('Target group'),
            doc=_('Group to apply ACI to'),
            flags=('virtual_attribute',),
        ),
        Flag('selfaci?',
             cli_name='self',
             label=_('Target your own entry (self)'),
             doc=_('Apply ACI to your own entry (self)'),
             flags=('virtual_attribute',),
        ),
        _prefix_option,
        Str('aci',
            label=_('ACI'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
    )