Esempio n. 1
0
class idoverridegroup(baseidoverride):

    object_name = _('Group ID override')
    object_name_plural = _('Group ID overrides')

    label = _('Group ID overrides')
    label_singular = _('Group ID override')
    rdn_is_primary_key = True

    permission_filter_objectclasses = ['ipaGroupOverride']
    managed_permissions = {
        'System: Read Group ID Overrides': {
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectClass',
                'ipaAnchorUUID',
                'gidNumber',
                'description',
                'cn',
            },
        },
    }

    object_class = baseidoverride.object_class + ['ipaGroupOverride']
    default_attributes = baseidoverride.default_attributes + [
        'gidNumber',
        'cn',
    ]

    takes_params = baseidoverride.takes_params + (
        Str(
            'cn?',
            pattern=PATTERN_GROUPUSER_NAME,
            pattern_errmsg='may only include letters, numbers, _, -, . and $',
            maxlength=255,
            cli_name='group_name',
            label=_('Group name'),
            normalizer=lambda value: value.lower(),
        ),
        Int(
            'gidnumber?',
            cli_name='gid',
            label=_('GID'),
            doc=_('Group ID Number'),
            minvalue=1,
        ),
    )

    override_object = 'group'
class deskprofileconfig(LDAPObject):
    """
    Global configuration for desktop profiles
    """
    object_name = _('configuration options')
    default_attributes = [
        'ipadeskprofilepriority',
    ]
    permission_filter_objectclasses = ['ipaguiconfig']
    managed_permissions = {
        'System: Read FleetCommander Desktop Profile Configuration': {
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'ipadeskprofilepriority',
                'objectclass',
            },
        },
        'System: Modify FleetCommander Desktop Profile Configuration': {
            'ipapermbindruletype': 'permission',
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'ipadeskprofilepriority',
            },
            'default_privileges':
            {'FleetCommander Desktop Profile Administrators'},
        },
    }

    label = _('Desktop Profile Global Configuration')
    label_singular = _('Dekstop Profile Global Configuration')

    takes_params = (Int(
        'ipadeskprofilepriority',
        cli_name='priority',
        label=_('Priority of profile application'),
        minvalue=1,
        maxvalue=24,
    ), )

    # Inject constants into the api.env before it is locked down
    def _on_finalize(self):
        self.env._merge(**dict(PLUGIN_CONFIG))
        self.container_dn = self.env.container_deskprofile
        super(deskprofileconfig, self)._on_finalize()

    def get_dn(self, *keys, **kwargs):
        return DN(self.container_dn, api.env.basedn)
Esempio n. 3
0
class cert_revoke(VirtualCommand):
    __doc__ = _('Revoke a certificate.')

    takes_args = _serial_number

    has_output_params = (Flag(
        'revoked',
        label=_('Revoked'),
    ), )
    operation = "revoke certificate"

    # FIXME: The default is 0.  Is this really an Int param?
    takes_options = (Int('revocation_reason',
                         label=_('Reason'),
                         doc=_('Reason for revoking the certificate (0-10)'),
                         minvalue=0,
                         maxvalue=10,
                         default=0,
                         autofill=True), )

    def execute(self, serial_number, **kw):
        ca_enabled_check()
        hostname = None
        try:
            self.check_access()
        except errors.ACIError as acierr:
            self.debug(
                "Not granted by ACI to revoke certificate, looking at principal"
            )
            try:
                # Let cert_show() handle verifying that the subject of the
                # cert we're dealing with matches the hostname in the principal
                result = api.Command['cert_show'](
                    unicode(serial_number))['result']
            except errors.NotImplementedError:
                pass
        revocation_reason = kw['revocation_reason']
        if revocation_reason == 7:
            raise errors.CertificateOperationError(
                error=_('7 is not a valid revocation reason'))
        return dict(result=self.Backend.ra.revoke_certificate(
            serial_number, revocation_reason=revocation_reason))
Esempio n. 4
0
class cosentry(LDAPObject):
    """
    Class of Service object used for linking policies with groups
    """
    NO_CLI = True

    container_dn = DN(('cn', 'costemplates'), api.env.container_accounts)
    object_class = ['top', 'costemplate', 'extensibleobject', 'krbcontainer']
    default_attributes = ['cn', 'cospriority', 'krbpwdpolicyreference']

    takes_params = (
        Str('cn', primary_key=True),
        DNParam('krbpwdpolicyreference'),
        Int('cospriority', minvalue=0),
    )

    priority_not_unique_msg = _(
        'priority must be a unique value (%(prio)d already used by %(gname)s)')

    def get_dn(self, *keys, **options):
        group_dn = self.api.Object.group.get_dn(keys[-1])
        return self.backend.make_dn_from_attr('cn', group_dn,
                                              self.container_dn)

    def check_priority_uniqueness(self, *keys, **options):
        if options.get('cospriority') is not None:
            entries = self.methods.find(
                cospriority=options['cospriority'])['result']
            if len(entries) > 0:
                group_name = self.api.Object.group.get_primary_key_from_dn(
                    DN(entries[0]['cn'][0]))
                raise errors.ValidationError(
                    name='priority',
                    error=self.priority_not_unique_msg % {
                        'prio': options['cospriority'],
                        'gname': group_name,
                    })
Esempio n. 5
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))
Esempio n. 6
0
class cosentry(LDAPObject):
    """
    Class of Service object used for linking policies with groups
    """
    NO_CLI = True

    container_dn = DN(('cn', 'costemplates'), api.env.container_accounts)
    object_class = ['top', 'costemplate', 'extensibleobject', 'krbcontainer']
    permission_filter_objectclasses = ['costemplate']
    default_attributes = ['cn', 'cospriority', 'krbpwdpolicyreference']
    managed_permissions = {
        'System: Read Group Password Policy costemplate': {
            'replaces_global_anonymous_aci': True,
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'cospriority',
                'krbpwdpolicyreference',
                'objectclass',
            },
            'default_privileges': {
                'Password Policy Readers',
                'Password Policy Administrator',
            },
        },
        'System: Add Group Password Policy costemplate': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=costemplates,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Group Password Policy costemplate";allow (add) groupdn = "ldap:///cn=Add Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
        'System: Delete Group Password Policy costemplate': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=costemplates,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Delete Group Password Policy costemplate";allow (delete) groupdn = "ldap:///cn=Delete Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
        'System: Modify Group Password Policy costemplate': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'cospriority'},
            'replaces': [
                '(targetattr = "cospriority")(target = "ldap:///cn=*,cn=costemplates,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group Password Policy costemplate";allow (write) groupdn = "ldap:///cn=Modify Group Password Policy costemplate,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
    }

    takes_params = (
        Str('cn', primary_key=True),
        DNParam('krbpwdpolicyreference'),
        Int('cospriority', minvalue=0),
    )

    priority_not_unique_msg = _(
        'priority must be a unique value (%(prio)d already used by %(gname)s)')

    def get_dn(self, *keys, **options):
        group_dn = self.api.Object.group.get_dn(keys[-1])
        return self.backend.make_dn_from_attr(
            'cn', group_dn, DN(self.container_dn, api.env.basedn))

    def check_priority_uniqueness(self, *keys, **options):
        if options.get('cospriority') is not None:
            entries = self.methods.find(
                cospriority=options['cospriority'])['result']
            if len(entries) > 0:
                group_name = self.api.Object.group.get_primary_key_from_dn(
                    DN(entries[0]['cn'][0]))
                raise errors.ValidationError(
                    name='priority',
                    error=self.priority_not_unique_msg % {
                        'prio': options['cospriority'],
                        'gname': group_name,
                    })
Esempio n. 7
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
Esempio n. 8
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'},
        ),
    )
Esempio n. 9
0
class idoverrideuser(baseidoverride):

    object_name = _('User ID override')
    object_name_plural = _('User ID overrides')

    label = _('User ID overrides')
    label_singular = _('User ID override')
    allow_rename = True

    # ID user overrides are bindable because we map SASL GSSAPI
    # authentication of trusted users to ID user overrides in the
    # default trust view.
    bindable = True

    permission_filter_objectclasses = ['ipaUserOverride']
    managed_permissions = {
        'System: Read User ID Overrides': {
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectClass', 'ipaAnchorUUID', 'uidNumber', 'description',
                'homeDirectory', 'uid', 'ipaOriginalUid', 'loginShell', 'gecos',
                'gidNumber', 'ipaSshPubkey', 'usercertificate', 'memberof'
            },
        },
    }

    object_class = baseidoverride.object_class + ['ipaUserOverride']
    possible_objectclasses = ['ipasshuser', 'ipaSshGroupOfPubKeys',
                              'nsmemberof']
    default_attributes = baseidoverride.default_attributes + [
       'homeDirectory', 'uidNumber', 'uid', 'ipaOriginalUid', 'loginShell',
       'ipaSshPubkey', 'gidNumber', 'gecos', 'usercertificate;binary',
       'memberofindirect', 'memberof'
    ]

    search_display_attributes = baseidoverride.default_attributes + [
       'homeDirectory', 'uidNumber', 'uid', 'ipaOriginalUid', 'loginShell',
       'ipaSshPubkey', 'gidNumber', 'gecos',
    ]

    attribute_members = {
        'memberof': ['group', 'role'],
        'memberofindirect': ['group', 'role'],
    }

    takes_params = baseidoverride.takes_params + (
        Str('uid?',
            pattern=PATTERN_GROUPUSER_NAME,
            pattern_errmsg='may only include letters, numbers, _, -, . and $',
            maxlength=255,
            cli_name='login',
            label=_('User login'),
            normalizer=lambda value: value.lower(),
        ),
        Int('uidnumber?',
            cli_name='uid',
            label=_('UID'),
            doc=_('User ID Number'),
            minvalue=1,
        ),
        Str('gecos?',
            label=_('GECOS'),
        ),
        Int('gidnumber?',
            label=_('GID'),
            doc=_('Group ID Number'),
            minvalue=1,
        ),
        Str('homedirectory?',
            cli_name='homedir',
            label=_('Home directory'),
        ),
        Str('loginshell?',
            cli_name='shell',
            label=_('Login shell'),
        ),
        Str('ipaoriginaluid?',
            flags=['no_option', 'no_output']
            ),
        Str('ipasshpubkey*', validate_sshpubkey,
            cli_name='sshpubkey',
            label=_('SSH public key'),
            normalizer=normalize_sshpubkey,
            flags=['no_search'],
        ),
        Certificate('usercertificate*',
              cli_name='certificate',
              label=_('Certificate'),
              doc=_('Base-64 encoded user certificate'),
              flags=['no_search',],
        ),
    )

    override_object = 'user'

    def update_original_uid_reference(self, entry_attrs):
        anchor = entry_attrs.single_value['ipaanchoruuid']
        try:
            original_uid = resolve_anchor_to_object_name(self.backend,
                                                         self.override_object,
                                                         anchor)
            entry_attrs['ipaOriginalUid'] = original_uid

        except (errors.NotFound, errors.ValidationError):
            # Anchor could not be resolved, this means we had to specify the
            # object to manipulate using a raw anchor value already, hence
            # we have no way to update the original_uid
            pass

    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')
Esempio n. 10
0
class cert_find(Search, CertMethod):
    __doc__ = _('Search for existing certificates.')

    takes_options = (
        Str(
            'subject?',
            label=_('Subject'),
            doc=_('Subject'),
            autofill=False,
        ),
        Int(
            'min_serial_number?',
            doc=_("minimum serial number"),
            autofill=False,
            minvalue=0,
            maxvalue=2147483647,
        ),
        Int(
            'max_serial_number?',
            doc=_("maximum serial number"),
            autofill=False,
            minvalue=0,
            maxvalue=2147483647,
        ),
        Flag(
            'exactly?',
            doc=_('match the common name exactly'),
            autofill=False,
        ),
        DateTime(
            'validnotafter_from?',
            doc=_('Valid not after from this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        DateTime(
            'validnotafter_to?',
            doc=_('Valid not after to this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        DateTime(
            'validnotbefore_from?',
            doc=_('Valid not before from this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        DateTime(
            'validnotbefore_to?',
            doc=_('Valid not before to this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        DateTime(
            'issuedon_from?',
            doc=_('Issued on from this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        DateTime(
            'issuedon_to?',
            doc=_('Issued on to this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        DateTime(
            'revokedon_from?',
            doc=_('Revoked on from this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        DateTime(
            'revokedon_to?',
            doc=_('Revoked on to this date (YYYY-mm-dd)'),
            normalizer=normalize_pkidate,
            autofill=False,
        ),
        Flag(
            'pkey_only?',
            label=_("Primary key only"),
            doc=_("Results should contain primary key attribute only "
                  "(\"certificate\")"),
        ),
        Int(
            'timelimit?',
            label=_('Time Limit'),
            doc=_('Time limit of search in seconds (0 is unlimited)'),
            minvalue=0,
        ),
        Int(
            'sizelimit?',
            label=_("Size Limit"),
            doc=_("Maximum number of entries returned (0 is unlimited)"),
            minvalue=0,
        ),
    )

    msg_summary = ngettext('%(count)d certificate matched',
                           '%(count)d certificates matched', 0)

    def get_options(self):
        for option in super(cert_find, self).get_options():
            if option.name == 'no_members':
                option = option.clone(default=True,
                                      flags=set(option.flags) | {'no_option'})
            elif option.name == 'cacn':
                # make CA optional, so that user may directly
                # specify Issuer DN instead
                option = option.clone(default=None, autofill=None)
            yield option

        for owner in self.obj._owners():
            yield owner.primary_key.clone_rename(
                '{0}'.format(owner.name),
                required=False,
                multivalue=True,
                primary_key=False,
                query=True,
                cli_name='{0}s'.format(owner.name),
                doc=(_("Search for certificates with these owner %s.") %
                     owner.object_name_plural),
                label=owner.object_name,
            )
            yield owner.primary_key.clone_rename(
                'no_{0}'.format(owner.name),
                required=False,
                multivalue=True,
                primary_key=False,
                query=True,
                cli_name='no_{0}s'.format(owner.name),
                doc=(_("Search for certificates without these owner %s.") %
                     owner.object_name_plural),
                label=owner.object_name,
            )

    def _get_cert_key(self, cert):
        try:
            nss_cert = x509.load_certificate(cert, x509.DER)
        except NSPRError as e:
            message = messages.SearchResultTruncated(
                reason=_("failed to load certificate: %s") % e, )
            self.add_message(message)

            raise ValueError("failed to load certificate")

        return (DN(unicode(nss_cert.issuer)), nss_cert.serial_number)

    def _get_cert_obj(self, cert, all, raw, pkey_only):
        obj = {'certificate': unicode(base64.b64encode(cert))}

        full = not pkey_only and all
        if not raw:
            self.obj._parse(obj, full)
        if not full:
            del obj['certificate']

        return obj

    def _cert_search(self, all, raw, pkey_only, **options):
        result = collections.OrderedDict()

        try:
            cert = options['certificate']
        except KeyError:
            return result, False, False

        try:
            key = self._get_cert_key(cert)
        except ValueError:
            return result, True, True

        result[key] = self._get_cert_obj(cert, all, raw, pkey_only)

        return result, False, True

    def _ca_search(self, all, raw, pkey_only, sizelimit, exactly, **options):
        ra_options = {}
        for name in ('revocation_reason', 'issuer', 'subject',
                     'min_serial_number', 'max_serial_number',
                     'validnotafter_from', 'validnotafter_to',
                     'validnotbefore_from', 'validnotbefore_to',
                     'issuedon_from', 'issuedon_to', 'revokedon_from',
                     'revokedon_to'):
            try:
                value = options[name]
            except KeyError:
                continue
            if isinstance(value, datetime.datetime):
                value = value.strftime(PKIDATE_FORMAT)
            elif isinstance(value, DN):
                value = unicode(value)
            ra_options[name] = value
        if sizelimit:
            ra_options['sizelimit'] = sizelimit
        if exactly:
            ra_options['exactly'] = True

        result = collections.OrderedDict()
        complete = bool(ra_options)

        try:
            ca_enabled_check()
        except errors.NotFound:
            if ra_options:
                raise
            return result, False, complete

        ca_objs = self.api.Command.ca_find()['result']
        ca_objs = {DN(ca['ipacasubjectdn'][0]): ca for ca in ca_objs}

        ra = self.api.Backend.ra
        for ra_obj in ra.find(ra_options):
            issuer = DN(ra_obj['issuer'])
            serial_number = ra_obj['serial_number']

            try:
                ca_obj = ca_objs[issuer]
            except KeyError:
                continue

            if pkey_only:
                obj = {'serial_number': serial_number}
            else:
                obj = ra_obj
                if all:
                    obj.update(ra.get_certificate(str(serial_number)))

                if not raw:
                    obj['issuer'] = issuer
                    obj['subject'] = DN(ra_obj['subject'])
                    obj['revoked'] = (ra_obj['status']
                                      in (u'REVOKED', u'REVOKED_EXPIRED'))
                    if all:
                        obj['certificate'] = (obj['certificate'].replace(
                            '\r\n', ''))
                        self.obj._parse(obj)

            obj['cacn'] = ca_obj['cn'][0]

            result[issuer, serial_number] = obj

        return result, False, complete

    def _ldap_search(self, all, raw, pkey_only, no_members, timelimit,
                     sizelimit, **options):
        ldap = self.api.Backend.ldap2

        filters = []
        for owner in self.obj._owners():
            for prefix, rule in (('', ldap.MATCH_ALL), ('no_',
                                                        ldap.MATCH_NONE)):
                try:
                    value = options[prefix + owner.name]
                except KeyError:
                    continue

                filter = ldap.make_filter_from_attr('objectclass',
                                                    owner.object_class,
                                                    ldap.MATCH_ALL)
                if filter not in filters:
                    filters.append(filter)

                filter = ldap.make_filter_from_attr(owner.primary_key.name,
                                                    value, rule)
                filters.append(filter)

        result = collections.OrderedDict()
        complete = bool(filters)

        cert = options.get('certificate')
        if cert is not None:
            filter = ldap.make_filter_from_attr('usercertificate', cert)
        else:
            filter = '(usercertificate=*)'
        filters.append(filter)

        filter = ldap.combine_filters(filters, ldap.MATCH_ALL)
        try:
            entries, truncated = ldap.find_entries(
                base_dn=self.api.env.basedn,
                filter=filter,
                attrs_list=['usercertificate'],
                time_limit=timelimit,
                size_limit=sizelimit,
            )
        except errors.EmptyResult:
            entries = []
            truncated = False
        else:
            try:
                ldap.handle_truncated_result(truncated)
            except errors.LimitsExceeded as e:
                self.add_message(messages.SearchResultTruncated(reason=e))

            truncated = bool(truncated)

        for entry in entries:
            for attr in ('usercertificate', 'usercertificate;binary'):
                for cert in entry.get(attr, []):
                    try:
                        key = self._get_cert_key(cert)
                    except ValueError:
                        truncated = True
                        continue

                    try:
                        obj = result[key]
                    except KeyError:
                        obj = self._get_cert_obj(cert, all, raw, pkey_only)
                        result[key] = obj

                    if not pkey_only and (all or not no_members):
                        owners = obj.setdefault('owner', [])
                        if entry.dn not in owners:
                            owners.append(entry.dn)

        if not raw:
            for obj in six.itervalues(result):
                self.obj._fill_owners(obj)

        return result, truncated, complete

    def execute(self,
                criteria=None,
                all=False,
                raw=False,
                pkey_only=False,
                no_members=True,
                timelimit=None,
                sizelimit=None,
                **options):
        if 'cacn' in options:
            ca_obj = api.Command.ca_show(options['cacn'])['result']
            ca_sdn = unicode(ca_obj['ipacasubjectdn'][0])
            if 'issuer' in options:
                if DN(ca_sdn) != DN(options['issuer']):
                    # client has provided both 'ca' and 'issuer' but
                    # issuer DNs don't match; result must be empty
                    return dict(result=[], count=0, truncated=False)
            else:
                options['issuer'] = ca_sdn

        if criteria is not None:
            return dict(result=[], count=0, truncated=False)

        result = collections.OrderedDict()
        truncated = False
        complete = False

        for sub_search in (self._cert_search, self._ca_search,
                           self._ldap_search):
            sub_result, sub_truncated, sub_complete = sub_search(
                all=all,
                raw=raw,
                pkey_only=pkey_only,
                no_members=no_members,
                timelimit=timelimit,
                sizelimit=sizelimit,
                **options)

            if sub_complete:
                sizelimit = None

                for key in tuple(result):
                    if key not in sub_result:
                        del result[key]

            for key, sub_obj in six.iteritems(sub_result):
                try:
                    obj = result[key]
                except KeyError:
                    if complete:
                        continue
                    result[key] = sub_obj
                else:
                    obj.update(sub_obj)

            truncated = truncated or sub_truncated
            complete = complete or sub_complete

        result = list(six.itervalues(result))

        ret = dict(result=result)
        ret['count'] = len(ret['result'])
        ret['truncated'] = bool(truncated)
        return ret
Esempio n. 11
0
class krbtpolicy(baseldap.LDAPObject):
    """
    Kerberos Ticket Policy object
    """
    container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos'))
    object_name = _('kerberos ticket policy settings')
    default_attributes = [
        'krbmaxticketlife', 'krbmaxrenewableage', 'krbauthindmaxticketlife',
        'krbauthindmaxrenewableage'
    ]
    limit_object_classes = ['krbticketpolicyaux']
    # permission_filter_objectclasses is deliberately missing,
    # so it is not possible to create a permission of `--type krbtpolicy`.
    # This is because we need two permissions to cover both global and per-user
    # policies.
    managed_permissions = {
        'System: Read Default Kerberos Ticket Policy': {
            'non_object': True,
            'replaces_global_anonymous_aci': True,
            'ipapermtargetfilter': ['(objectclass=krbticketpolicyaux)'],
            'ipapermlocation': DN(container_dn, api.env.basedn),
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'krbdefaultencsalttypes',
                'krbmaxrenewableage',
                'krbmaxticketlife',
                'krbsupportedencsalttypes',
                'objectclass',
                'krbauthindmaxticketlife',
                'krbauthindmaxrenewableage',
            },
            'default_privileges': {
                'Kerberos Ticket Policy Readers',
            },
        },
        'System: Read User Kerberos Ticket Policy': {
            'non_object': True,
            'replaces_global_anonymous_aci': True,
            'ipapermlocation': DN(api.env.container_user, api.env.basedn),
            'ipapermtargetfilter': ['(objectclass=krbticketpolicyaux)'],
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'krbmaxrenewableage',
                'krbmaxticketlife',
                'krbauthindmaxticketlife',
                'krbauthindmaxrenewableage',
            },
            'default_privileges': {
                'Kerberos Ticket Policy Readers',
            },
        },
    }

    label = _('Kerberos Ticket Policy')
    label_singular = _('Kerberos Ticket Policy')

    takes_params = (
        Str(
            'uid?',
            cli_name='user',
            label=_('User name'),
            doc=_('Manage ticket policy for specific user'),
            primary_key=True,
        ),
        Int(
            'krbmaxticketlife?',
            cli_name='maxlife',
            label=_('Max life'),
            doc=_('Maximum ticket life (seconds)'),
            minvalue=1,
        ),
        Int(
            'krbmaxrenewableage?',
            cli_name='maxrenew',
            label=_('Max renew'),
            doc=_('Maximum renewable age (seconds)'),
            minvalue=1,
        ),
        Int('krbauthindmaxticketlife_otp?',
            cli_name='otp_maxlife',
            label=_('OTP max life'),
            doc=_('OTP token maximum ticket life (seconds)'),
            minvalue=1),
        Int('krbauthindmaxrenewableage_otp?',
            cli_name='otp_maxrenew',
            label=_('OTP max renew'),
            doc=_('OTP token ticket maximum renewable age (seconds)'),
            minvalue=1),
        Int('krbauthindmaxticketlife_radius?',
            cli_name='radius_maxlife',
            label=_('RADIUS max life'),
            doc=_('RADIUS maximum ticket life (seconds)'),
            minvalue=1),
        Int('krbauthindmaxrenewableage_radius?',
            cli_name='radius_maxrenew',
            label=_('RADIUS max renew'),
            doc=_('RADIUS ticket maximum renewable age (seconds)'),
            minvalue=1),
        Int('krbauthindmaxticketlife_pkinit?',
            cli_name='pkinit_maxlife',
            label=_('PKINIT max life'),
            doc=_('PKINIT maximum ticket life (seconds)'),
            minvalue=1),
        Int('krbauthindmaxrenewableage_pkinit?',
            cli_name='pkinit_maxrenew',
            label=_('PKINIT max renew'),
            doc=_('PKINIT ticket maximum renewable age (seconds)'),
            minvalue=1),
        Int('krbauthindmaxticketlife_hardened?',
            cli_name='hardened_maxlife',
            label=_('Hardened max life'),
            doc=_('Hardened ticket maximum ticket life (seconds)'),
            minvalue=1),
        Int('krbauthindmaxrenewableage_hardened?',
            cli_name='hardened_maxrenew',
            label=_('Hardened max renew'),
            doc=_('Hardened ticket maximum renewable age (seconds)'),
            minvalue=1),
    )

    def get_dn(self, *keys, **kwargs):
        if keys[-1] is not None:
            return self.api.Object.user.get_dn(*keys, **kwargs)
        return DN(self.container_dn, api.env.basedn)
Esempio n. 12
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,
                                             })
class deskprofilerule(LDAPObject):
    """
    Desktop profile object.
    """
    container_dn = None
    object_name = _('FleetCommander Desktop Profile Rule Map')
    object_name_plural = _('FleetCommander Desktop Profile Rule Maps')
    object_class = ['ipaassociation', 'ipadeskprofilerule']
    permission_filter_objectclasses = ['ipadeskprofilerule']
    default_attributes = [
        'cn',
        'ipaenabledflag',
        'ipadeskprofiletarget'
        'description',
        'usercategory',
        'hostcategory',
        'memberuser',
        'memberhost',
        'ipadeskprofilepriority',
        'seealso',
    ]
    uuid_attribute = 'ipauniqueid'
    rdn_is_primary_key = True
    attribute_members = {
        'memberuser': ['user', 'group'],
        'memberhost': ['host', 'hostgroup'],
    }
    managed_permissions = {
        'System: Read FleetCommander Desktop Profile Rule Map': {
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'description',
                'hostcategory',
                'ipaenabledflag',
                'ipauniqueid',
                'memberhost',
                'memberuser',
                'seealso',
                'usercategory',
                'objectclass',
                'member',
                'ipadeskprofilepriority',
                'ipadeskprofiletarget',
            },
        },
        'System: Add FleetCommander Desktop Profile Rule Map': {
            'ipapermbindruletype': 'permission',
            'ipapermright': {'add'},
            'default_privileges':
            {'FleetCommander Desktop Profile Administrators'},
        },
        'System: Modify FleetCommander Desktop Profile Rule Map': {
            'ipapermbindruletype': 'permission',
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'cn',
                'ipaenabledflag',
                'memberhost',
                'memberuser',
                'seealso',
                'ipadeskprofilepriority',
                'ipadeskprofiletarget',
            },
            'default_privileges':
            {'FleetCommander Desktop Profile Administrators'},
        },
        'System: Remove FleetCommander Desktop Profile Rule Map': {
            'ipapermbindruletype': 'permission',
            'ipapermright': {'delete'},
            'default_privileges':
            {'FleetCommander Desktop Profile Administrators'},
        },
    }

    label = _('FleetCommander Desktop Profile Rule Map')
    label_singular = _('FleetCommander Desktop Profile Rule Map')

    takes_params = (
        Str(
            'cn',
            cli_name='name',
            label=_('Rule name'),
            primary_key=True,
        ),
        Str(
            'ipadeskprofiletarget',
            cli_name='profile',
            label=_('Desktop profile'),
            doc=_('Desktop profile associated with the rule'),
        ),
        Int(
            'ipadeskprofilepriority',
            cli_name='prio',
            label=_('Desktop profile priority'),
            minvalue=1,
            maxvalue=100000,
            doc=_('Priority for desktop profile associated with the rule'),
        ),
        Str(
            'seealso?',
            cli_name='hbacrule',
            label=_('HBAC Rule'),
            doc=_('HBAC Rule that defines the users, groups and hostgroups'),
        ),
        StrEnum(
            'usercategory?',
            cli_name='usercat',
            label=_('User category'),
            doc=_('User category the rule applies to'),
            values=(u'all', ),
        ),
        StrEnum(
            'hostcategory?',
            cli_name='hostcat',
            label=_('Host category'),
            doc=_('Host category the rule applies to'),
            values=(u'all', ),
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
        ),
        Bool(
            'ipaenabledflag?',
            label=_('Enabled'),
            flags=['no_option'],
        ),
        Str(
            'memberuser_user?',
            label=_('Users'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberuser_group?',
            label=_('User Groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberhost_host?',
            label=_('Hosts'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberhost_hostgroup?',
            label=_('Host Groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
    )

    # Inject constants into the api.env before it is locked down
    def _on_finalize(self):
        self.env._merge(**dict(PLUGIN_CONFIG))
        self.container_dn = self.env.container_deskprofilerule
        super(deskprofilerule, self)._on_finalize()

    def _normalize_seealso(self, seealso):
        """
        Given a HBAC rule name verify its existence and return the dn.
        """
        if not seealso:
            return None

        try:
            dn = DN(seealso)
            return str(dn)
        except ValueError:
            try:
                entry_attrs = self.backend.find_entry_by_attr(
                    self.api.Object['hbacrule'].primary_key.name, seealso,
                    self.api.Object['hbacrule'].object_class, [''],
                    DN(self.api.Object['hbacrule'].container_dn,
                       api.env.basedn))
                seealso = entry_attrs.dn
            except errors.NotFound:
                raise errors.NotFound(
                    reason=_('HBAC rule %(rule)s not found') %
                    dict(rule=seealso))

        return seealso

    def _convert_seealso(self, ldap, entry_attrs, **options):
        """
        Convert an HBAC rule dn into a name
        """
        if options.get('raw', False):
            return

        if 'seealso' in entry_attrs:
            hbac_attrs = ldap.get_entry(entry_attrs['seealso'][0], ['cn'])
            entry_attrs['seealso'] = hbac_attrs['cn'][0]

    def _normalize_profile(self, profile):
        """
        Given a Desktop Profile name verify its existence and return the dn.
        """
        if not profile:
            return None

        try:
            dn = DN(profile)
            return str(dn)
        except ValueError:
            try:
                entry_attrs = self.backend.find_entry_by_attr(
                    self.api.Object['deskprofile'].primary_key.name, profile,
                    self.api.Object['deskprofile'].object_class, [''],
                    DN(self.api.Object['deskprofile'].container_dn,
                       api.env.basedn))
                return entry_attrs.dn
            except errors.NotFound:
                raise errors.NotFound(
                    reason=_('Desktop profile %(rule)s not found') %
                    dict(rule=profile))

    def _convert_profile(self, ldap, entry_attrs, **options):
        """
        Convert an Desktop Profile dn into a name
        """
        if options.get('raw', False):
            return

        if 'ipadeskprofiletarget' in entry_attrs:
            profile_attrs = ldap.get_entry(
                entry_attrs['ipadeskprofiletarget'][0], ['cn'])
            entry_attrs['ipadeskprofiletarget'] = profile_attrs['cn'][0]
Esempio n. 14
0
class cert_find(Command):
    __doc__ = _('Search for existing certificates.')

    takes_options = (
        Str(
            'subject?',
            label=_('Subject'),
            doc=_('Subject'),
            autofill=False,
        ),
        Int(
            'revocation_reason?',
            label=_('Reason'),
            doc=_('Reason for revoking the certificate (0-10)'),
            minvalue=0,
            maxvalue=10,
            autofill=False,
        ),
        Int(
            'min_serial_number?',
            doc=_("minimum serial number"),
            autofill=False,
            minvalue=0,
            maxvalue=2147483647,
        ),
        Int(
            'max_serial_number?',
            doc=_("maximum serial number"),
            autofill=False,
            minvalue=0,
            maxvalue=2147483647,
        ),
        Flag(
            'exactly?',
            doc=_('match the common name exactly'),
            autofill=False,
        ),
        Str(
            'validnotafter_from?',
            validate_pkidate,
            doc=_('Valid not after from this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Str(
            'validnotafter_to?',
            validate_pkidate,
            doc=_('Valid not after to this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Str(
            'validnotbefore_from?',
            validate_pkidate,
            doc=_('Valid not before from this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Str(
            'validnotbefore_to?',
            validate_pkidate,
            doc=_('Valid not before to this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Str(
            'issuedon_from?',
            validate_pkidate,
            doc=_('Issued on from this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Str(
            'issuedon_to?',
            validate_pkidate,
            doc=_('Issued on to this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Str(
            'revokedon_from?',
            validate_pkidate,
            doc=_('Revoked on from this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Str(
            'revokedon_to?',
            validate_pkidate,
            doc=_('Revoked on to this date (YYYY-mm-dd)'),
            autofill=False,
        ),
        Int(
            'sizelimit?',
            label=_('Size Limit'),
            doc=_('Maximum number of certs returned'),
            flags=['no_display'],
            minvalue=0,
            default=100,
        ),
    )

    has_output = output.standard_list_of_entries
    has_output_params = (
        Str(
            'serial_number_hex',
            label=_('Serial number (hex)'),
        ),
        Str(
            'serial_number',
            label=_('Serial number'),
        ),
        Str(
            'status',
            label=_('Status'),
        ),
    )

    msg_summary = ngettext('%(count)d certificate matched',
                           '%(count)d certificates matched', 0)

    def execute(self, **options):
        ca_enabled_check()
        ret = dict(result=self.Backend.ra.find(options))
        ret['count'] = len(ret['result'])
        ret['truncated'] = False
        return ret
Esempio n. 15
0
class hbactest(Command):
    __doc__ = _('Simulate use of Host-based access controls')

    has_output = (
        output.summary,
        output.Output('warning', (list, tuple, type(None)),   _('Warning')),
        output.Output('matched', (list, tuple, type(None)),   _('Matched rules')),
        output.Output('notmatched', (list, tuple, type(None)), _('Not matched rules')),
        output.Output('error', (list, tuple, type(None)), _('Non-existent or invalid rules')),
        output.Output('value',  bool, _('Result of simulation'), ['no_display']),
    )

    takes_options = (
        Str('user',
            cli_name='user',
            label=_('User name'),
            primary_key=True,
        ),
        Str('sourcehost?',
            deprecated=True,
            cli_name='srchost',
            label=_('Source host'),
            flags={'no_option'},
        ),
        Str('targethost',
            cli_name='host',
            label=_('Target host'),
        ),
        Str('service',
            cli_name='service',
            label=_('Service'),
        ),
        Str('rules*',
             cli_name='rules',
             label=_('Rules to test. If not specified, --enabled is assumed'),
        ),
        Flag('nodetail?',
             cli_name='nodetail',
             label=_('Hide details which rules are matched, not matched, or invalid'),
        ),
        Flag('enabled?',
             cli_name='enabled',
             label=_('Include all enabled IPA rules into test [default]'),
        ),
        Flag('disabled?',
             cli_name='disabled',
             label=_('Include all disabled IPA rules into test'),
        ),
        Int('sizelimit?',
            label=_('Size Limit'),
            doc=_('Maximum number of rules to process when no --rules is specified'),
            flags=['no_display'],
            minvalue=0,
            autofill=False,
        ),
    )

    def canonicalize(self, host):
        """
        Canonicalize the host name -- add default IPA domain if that is missing
        """
        if host.find('.') == -1:
            return u'%s.%s' % (host, self.env.domain)
        return host

    def execute(self, *args, **options):
        # First receive all needed information:
        # 1. HBAC rules (whether enabled or disabled)
        # 2. Required options are (user, target host, service)
        # 3. Options: rules to test (--rules, --enabled, --disabled), request for detail output
        rules = []

        # Use all enabled IPA rules by default
        all_enabled = True
        all_disabled = False

        # We need a local copy of test rules in order find incorrect ones
        testrules = {}
        if 'rules' in options:
            testrules = list(options['rules'])
            # When explicit rules are provided, disable assumptions
            all_enabled = False
            all_disabled = False

        sizelimit = None
        if 'sizelimit' in options:
            sizelimit = int(options['sizelimit'])

        # Check if --disabled is specified, include all disabled IPA rules
        if options['disabled']:
            all_disabled = True
            all_enabled = False

        # Finally, if enabled is specified implicitly, override above decisions
        if options['enabled']:
            all_enabled = True

        hbacset = []
        if len(testrules) == 0:
            hbacset = self.api.Command.hbacrule_find(
                sizelimit=sizelimit, no_members=False)['result']
        else:
            for rule in testrules:
                try:
                    hbacset.append(self.api.Command.hbacrule_show(rule)['result'])
                except Exception:
                    pass

        # We have some rules, import them
        # --enabled will import all enabled rules (default)
        # --disabled will import all disabled rules
        # --rules will implicitly add the rules from a rule list
        for rule in hbacset:
            ipa_rule = convert_to_ipa_rule(rule)
            if ipa_rule.name in testrules:
                ipa_rule.enabled = True
                rules.append(ipa_rule)
                testrules.remove(ipa_rule.name)
            elif all_enabled and ipa_rule.enabled:
                # Option --enabled forces to include all enabled IPA rules into test
                rules.append(ipa_rule)
            elif all_disabled and not ipa_rule.enabled:
                # Option --disabled forces to include all disabled IPA rules into test
                ipa_rule.enabled = True
                rules.append(ipa_rule)

        # Check if there are unresolved rules left
        if len(testrules) > 0:
            # Error, unresolved rules are left in --rules
            return {'summary' : unicode(_(u'Unresolved rules in --rules')),
                    'error': testrules, 'matched': None, 'notmatched': None,
                    'warning' : None, 'value' : False}

        # Rules are converted to pyhbac format, build request and then test it
        request = pyhbac.HbacRequest()

        if options['user'] != u'all':
            # check first if this is not a trusted domain user
            if _dcerpc_bindings_installed:
                is_valid_sid = ipaserver.dcerpc.is_sid_valid(options['user'])
            else:
                is_valid_sid = False
            components = util.normalize_name(options['user'])
            if is_valid_sid or 'domain' in components or 'flatname' in components:
                # this is a trusted domain user
                if not _dcerpc_bindings_installed:
                    raise errors.NotFound(reason=_(
                        'Cannot perform external member 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=_(
                        'Cannot search in trusted domains without own domain configured. '
                        'Make sure you have run ipa-adtrust-install on the IPA server first'))
                user_sid, group_sids = domain_validator.get_trusted_domain_user_and_groups(options['user'])
                request.user.name = user_sid

                # Now search for all external groups that have this user or
                # any of its groups in its external members. Found entires
                # memberOf links will be then used to gather all groups where
                # this group is assigned, including the nested ones
                filter_sids = "(&(objectclass=ipaexternalgroup)(|(ipaExternalMember=%s)))" \
                        % ")(ipaExternalMember=".join(group_sids + [user_sid])

                ldap = self.api.Backend.ldap2
                group_container = DN(api.env.container_group, api.env.basedn)
                try:
                    entries, _truncated = ldap.find_entries(
                        filter_sids, ['memberof'], group_container)
                except errors.NotFound:
                    request.user.groups = []
                else:
                    groups = []
                    for entry in entries:
                        memberof_dns = entry.get('memberof', [])
                        for memberof_dn in memberof_dns:
                            if memberof_dn.endswith(group_container):
                                groups.append(memberof_dn[0][0].value)
                    request.user.groups = sorted(set(groups))
            else:
                # try searching for a local user
                try:
                    request.user.name = options['user']
                    search_result = self.api.Command.user_show(request.user.name)['result']
                    groups = search_result['memberof_group']
                    if 'memberofindirect_group' in search_result:
                        groups += search_result['memberofindirect_group']
                    request.user.groups = sorted(set(groups))
                except Exception:
                    pass

        if options['service'] != u'all':
            try:
                request.service.name = options['service']
                service_result = self.api.Command.hbacsvc_show(request.service.name)['result']
                if 'memberof_hbacsvcgroup' in service_result:
                    request.service.groups = service_result['memberof_hbacsvcgroup']
            except Exception:
                pass

        if options['targethost'] != u'all':
            try:
                request.targethost.name = self.canonicalize(options['targethost'])
                tgthost_result = self.api.Command.host_show(request.targethost.name)['result']
                groups = tgthost_result['memberof_hostgroup']
                if 'memberofindirect_hostgroup' in tgthost_result:
                    groups += tgthost_result['memberofindirect_hostgroup']
                request.targethost.groups = sorted(set(groups))
            except Exception:
                pass

        matched_rules = []
        notmatched_rules = []
        error_rules = []
        warning_rules = []

        result = {'warning':None, 'matched':None, 'notmatched':None, 'error':None}
        if not options['nodetail']:
            # Validate runs rules one-by-one and reports failed ones
            for ipa_rule in rules:
                try:
                    res = request.evaluate([ipa_rule])
                    if res == pyhbac.HBAC_EVAL_ALLOW:
                        matched_rules.append(ipa_rule.name)
                    if res == pyhbac.HBAC_EVAL_DENY:
                        notmatched_rules.append(ipa_rule.name)
                except pyhbac.HbacError as e:
                    code, rule_name = e.args
                    if code == pyhbac.HBAC_EVAL_ERROR:
                        error_rules.append(rule_name)
                        self.log.info('Native IPA HBAC rule "%s" parsing error: %s' % \
                                      (rule_name, pyhbac.hbac_result_string(code)))
                except (TypeError, IOError) as info:
                    self.log.error('Native IPA HBAC module error: %s' % info)

            access_granted = len(matched_rules) > 0
        else:
            res = request.evaluate(rules)
            access_granted = (res == pyhbac.HBAC_EVAL_ALLOW)

        result['summary'] = _('Access granted: %s') % (access_granted)


        if len(matched_rules) > 0:
            result['matched'] = matched_rules
        if len(notmatched_rules) > 0:
            result['notmatched'] = notmatched_rules
        if len(error_rules) > 0:
            result['error'] = error_rules
        if len(warning_rules) > 0:
            result['warning'] = warning_rules

        result['value'] = access_granted
        return result
Esempio n. 16
0
user.takes_params += (Str('primarymail?',
                          cli_name='primary_mail',
                          label=_('Primary mail address')),
                      Str('alias*', cli_name='alias', label=_('Mail aliases')),
                      Str('sendalias*',
                          cli_name='send_alias',
                          label=_('Allowed sender aliases')),
                      Bool('canreceiveexternally?',
                           cli_name='can_receive_externally',
                           label='Can receive external mails'),
                      Bool('cansendexternally?',
                           cli_name='can_send_externally',
                           label='Can send mails to external locations'),
                      Int('mailboxquota?',
                          cli_name='mailbox_quota',
                          label='Mailbox quota [MB]'),
                      Str('mailboxtransport?',
                          cli_name='mailbox_transport',
                          label=_('Mailbox transport string')))

user.default_attributes = user.default_attributes + [
    'alias', 'sendalias', 'mailboxquota', 'mailboxtransport'
]

user.managed_permissions = {
    **user.managed_permissions,
    **{
        'System: Read User Mail Attributes': {
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
Esempio n. 17
0
class server(LDAPObject):
    """
    IPA server
    """
    container_dn = api.env.container_masters
    object_name = _('server')
    object_name_plural = _('servers')
    object_class = ['top']
    possible_objectclasses = ['ipaLocationMember']
    search_attributes = ['cn']
    default_attributes = [
        'cn', 'iparepltopomanagedsuffix', 'ipamindomainlevel',
        'ipamaxdomainlevel', 'ipalocation', 'ipaserviceweight'
    ]
    label = _('IPA Servers')
    label_singular = _('IPA Server')
    attribute_members = {
        'iparepltopomanagedsuffix': ['topologysuffix'],
        'ipalocation': ['location'],
        'role': ['servrole'],
    }
    relationships = {
        'iparepltopomanagedsuffix': ('Managed', '', 'no_'),
        'ipalocation': ('IPA', 'in_', 'not_in_'),
        'role': ('Enabled', '', 'no_'),
    }
    permission_filter_objectclasses = ['ipaConfigObject']
    managed_permissions = {
        'System: Read Locations of IPA Servers': {
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'cn',
                'ipalocation',
                'ipaserviceweight',
            },
            'default_privileges': {'DNS Administrators'},
        },
        'System: Read Status of Services on IPA Servers': {
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {'objectclass', 'cn', 'ipaconfigstring'},
            'default_privileges': {'DNS Administrators'},
        }
    }

    takes_params = (
        Str(
            'cn',
            cli_name='name',
            primary_key=True,
            label=_('Server name'),
            doc=_('IPA server hostname'),
        ),
        Str(
            'iparepltopomanagedsuffix*',
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'iparepltopomanagedsuffix_topologysuffix*',
            label=_('Managed suffixes'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Int(
            'ipamindomainlevel',
            cli_name='minlevel',
            label=_('Min domain level'),
            doc=_('Minimum domain level'),
            flags={'no_create', 'no_update'},
        ),
        Int(
            'ipamaxdomainlevel',
            cli_name='maxlevel',
            label=_('Max domain level'),
            doc=_('Maximum domain level'),
            flags={'no_create', 'no_update'},
        ),
        DNSNameParam(
            'ipalocation_location?',
            cli_name='location',
            label=_('Location'),
            doc=_('Server location'),
            only_relative=True,
            flags={'no_search'},
        ),
        Int(
            'ipaserviceweight?',
            cli_name='service_weight',
            label=_('Service weight'),
            doc=_('Weight for server services'),
            minvalue=0,
            maxvalue=65535,
            flags={'no_search'},
        ),
        Str(
            'service_relative_weight',
            label=_('Service relative weight'),
            doc=_('Relative weight for server services (counts per location)'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str('enabled_role_servrole*',
            label=_('Enabled server roles'),
            doc=_('List of enabled roles'),
            flags={'virtual_attribute', 'no_create', 'no_update',
                   'no_search'}),
    )

    def _get_suffixes(self):
        suffixes = self.api.Command.topologysuffix_find(
            all=True,
            raw=True,
        )['result']
        suffixes = [(s['iparepltopoconfroot'][0], s['dn']) for s in suffixes]
        return suffixes

    def _apply_suffixes(self, entry, suffixes):
        # change suffix DNs to topologysuffix entry DNs
        # this fixes LDAPObject.convert_attribute_members() for suffixes
        suffixes = dict(suffixes)
        if 'iparepltopomanagedsuffix' in entry:
            entry['iparepltopomanagedsuffix'] = [
                suffixes.get(m, m) for m in entry['iparepltopomanagedsuffix']
            ]

    def normalize_location(self, kw, **options):
        """
        Return the DN of location
        """
        if 'ipalocation_location' in kw:
            location = kw.pop('ipalocation_location')
            kw['ipalocation'] = ([self.api.Object.location.get_dn(location)]
                                 if location is not None else location)

    def convert_location(self, entry_attrs, **options):
        """
        Return a location name from DN
        """
        if options.get('raw'):
            return

        converted_locations = [
            DNSName(location_dn['idnsname'])
            for location_dn in entry_attrs.pop('ipalocation', [])
        ]

        if converted_locations:
            entry_attrs['ipalocation_location'] = converted_locations

    def get_enabled_roles(self, entry_attrs, **options):
        if not options.get('all', False) and options.get('no_members', False):
            return

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

        enabled_roles = self.api.Command.server_role_find(
            server_server=entry_attrs['cn'][0],
            status=ENABLED,
            include_master=True,
        )['result']

        enabled_role_names = [r[u'role_servrole'] for r in enabled_roles]

        entry_attrs['enabled_role_servrole'] = enabled_role_names
Esempio n. 18
0
class ca(LDAPObject):
    """
    Lightweight CA Object
    """
    container_dn = api.env.container_ca
    object_name = _('Certificate Authority')
    object_name_plural = _('Certificate Authorities')
    object_class = ['ipaca']
    permission_filter_objectclasses = ['ipaca']
    default_attributes = [
        'cn', 'description', 'ipacaid', 'ipacaissuerdn', 'ipacasubjectdn',
        'ipacarandomserialnumberversion',
    ]
    rdn_attribute = 'cn'
    allow_rename = True
    label = _('Certificate Authorities')
    label_singular = _('Certificate Authority')

    takes_params = (
        Str('cn',
            primary_key=True,
            cli_name='name',
            label=_('Name'),
            doc=_('Name for referencing the CA'),
        ),
        Str('description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('Description of the purpose of the CA'),
        ),
        Str('ipacaid',
            cli_name='id',
            label=_('Authority ID'),
            doc=_('Dogtag Authority ID'),
            flags=['no_create', 'no_update'],
        ),
        DNParam('ipacasubjectdn',
            cli_name='subject',
            label=_('Subject DN'),
            doc=_('Subject Distinguished Name'),
            flags=['no_update'],
        ),
        DNParam('ipacaissuerdn',
            cli_name='issuer',
            label=_('Issuer DN'),
            doc=_('Issuer Distinguished Name'),
            flags=['no_create', 'no_update'],
        ),
        Bytes(
            'certificate',
            label=_("Certificate"),
            doc=_("Base-64 encoded certificate."),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Bytes(
            'certificate_chain*',
            label=_("Certificate chain"),
            doc=_("X.509 certificate chain"),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Int(
            'ipacarandomserialnumberversion',
            cli_name='randomserialnumberversion',
            label=_('RSN Version'),
            doc=_('Random Serial Number Version'),
            flags={'no_create', 'no_update'},
        ),
    )

    permission_filter_objectclasses = ['ipaca']
    managed_permissions = {
        'System: Read CAs': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'description',
                'ipacaid',
                'ipacaissuerdn',
                'ipacasubjectdn',
                'ipacarandomserialnumberversion',
                'objectclass',
            },
        },
        'System: Add CA': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=cas,cn=ca,$SUFFIX")(version 3.0;acl "permission:Add CA";allow (add) groupdn = "ldap:///cn=Add CA,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'CA Administrator'},
        },
        'System: Delete CA': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=cas,cn=ca,$SUFFIX")(version 3.0;acl "permission:Delete CA";allow (delete) groupdn = "ldap:///cn=Delete CA,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'CA Administrator'},
        },
        'System: Modify CA': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'cn',
                'description',
            },
            'replaces': [
                '(targetattr = "cn || description")(target = "ldap:///cn=*,cn=cas,cn=ca,$SUFFIX")(version 3.0;acl "permission:Modify CA";allow (write) groupdn = "ldap:///cn=Modify CA,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'CA Administrator'},
        },
    }
Esempio n. 19
0
class BaseCertObject(Object):
    takes_params = (
        Str(
            'cacn?',
            cli_name='ca',
            default=IPA_CA_CN,
            autofill=True,
            label=_('Issuing CA'),
            doc=_('Name of issuing CA'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Bytes(
            'certificate',
            validate_certificate,
            label=_("Certificate"),
            doc=_("Base-64 encoded certificate."),
            normalizer=x509.normalize_certificate,
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNParam(
            'subject',
            label=_('Subject'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_rfc822name*',
            label=_('Subject email address'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNSNameParam(
            'san_dnsname*',
            label=_('Subject DNS name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_x400address*',
            label=_('Subject X.400 address'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNParam(
            'san_directoryname*',
            label=_('Subject directory name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_edipartyname*',
            label=_('Subject EDI Party name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_uri*',
            label=_('Subject URI'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_ipaddress*',
            label=_('Subject IP Address'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_oid*',
            label=_('Subject OID'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Principal(
            'san_other_upn*',
            label=_('Subject UPN'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Principal(
            'san_other_kpn*',
            label=_('Subject Kerberos principal name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_other*',
            label=_('Subject Other Name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNParam(
            'issuer',
            label=_('Issuer'),
            doc=_('Issuer DN'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DateTime(
            'valid_not_before',
            label=_('Not Before'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DateTime(
            'valid_not_after',
            label=_('Not After'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'md5_fingerprint',
            label=_('Fingerprint (MD5)'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'sha1_fingerprint',
            label=_('Fingerprint (SHA1)'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Int(
            'serial_number',
            label=_('Serial number'),
            doc=_(
                'Serial number in decimal or if prefixed with 0x in hexadecimal'
            ),
            normalizer=normalize_serial_number,
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'serial_number_hex',
            label=_('Serial number (hex)'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
    )

    def _parse(self, obj, full=True):
        """Extract certificate-specific data into a result object.

        ``obj``
            Result object containing certificate, into which extracted
            data will be inserted.
        ``full``
            Whether to include all fields, or only the ones we guess
            people want to see most of the time.  Also add
            recognised otherNames to the generic ``san_other``
            attribute when ``True`` in addition to the specialised
            attribute.

        """
        cert = obj.get('certificate')
        if cert is not None:
            cert = x509.load_certificate(cert)
            obj['subject'] = DN(unicode(cert.subject))
            obj['issuer'] = DN(unicode(cert.issuer))
            obj['serial_number'] = cert.serial_number
            if full:
                obj['valid_not_before'] = unicode(cert.valid_not_before_str)
                obj['valid_not_after'] = unicode(cert.valid_not_after_str)
                obj['md5_fingerprint'] = unicode(
                    nss.data_to_hex(nss.md5_digest(cert.der_data), 64)[0])
                obj['sha1_fingerprint'] = unicode(
                    nss.data_to_hex(nss.sha1_digest(cert.der_data), 64)[0])

            try:
                ext_san = cert.get_extension(nss.SEC_OID_X509_SUBJECT_ALT_NAME)
                general_names = x509.decode_generalnames(ext_san.value)
            except KeyError:
                general_names = []

            for name_type, _desc, name, der_name in general_names:
                try:
                    self._add_san_attribute(obj, full, name_type, name,
                                            der_name)
                except Exception:
                    # Invalid GeneralName (i.e. not a valid X.509 cert);
                    # don't fail but log something about it
                    root_logger.warning(
                        "Encountered bad GeneralName; skipping", exc_info=True)

        serial_number = obj.get('serial_number')
        if serial_number is not None:
            obj['serial_number_hex'] = u'0x%X' % serial_number

    def _add_san_attribute(self, obj, full, name_type, name, der_name):
        name_type_map = {
            nss.certRFC822Name: 'san_rfc822name',
            nss.certDNSName: 'san_dnsname',
            nss.certX400Address: 'san_x400address',
            nss.certDirectoryName: 'san_directoryname',
            nss.certEDIPartyName: 'san_edipartyname',
            nss.certURI: 'san_uri',
            nss.certIPAddress: 'san_ipaddress',
            nss.certRegisterID: 'san_oid',
            (nss.certOtherName, x509.SAN_UPN): 'san_other_upn',
            (nss.certOtherName, x509.SAN_KRB5PRINCIPALNAME): 'san_other_kpn',
        }
        default_attrs = {
            'san_rfc822name',
            'san_dnsname',
            'san_other_upn',
            'san_other_kpn',
        }

        attr_name = name_type_map.get(name_type, 'san_other')

        if full or attr_name in default_attrs:
            if attr_name != 'san_other':
                name_formatted = name
            else:
                # display as "OID : b64(DER)"
                name_formatted = u'{}:{}'.format(name_type[1],
                                                 base64.b64encode(der_name))
            attr_value = self.params[attr_name].type(name_formatted)
            obj.setdefault(attr_name, []).append(attr_value)

        if full and attr_name.startswith('san_other_'):
            # also include known otherName in generic otherName attribute
            name_formatted = u'{}:{}'.format(name_type[1],
                                             base64.b64encode(der_name))
            attr_value = self.params['san_other'].type(name_formatted)
            obj.setdefault('san_other', []).append(attr_value)
Esempio n. 20
0
class pwpolicy(LDAPObject):
    """
    Password Policy object
    """
    container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos'))
    object_name = _('password policy')
    object_name_plural = _('password policies')
    object_class = ['top', 'nscontainer', 'krbpwdpolicy', 'ipapwdpolicy']
    permission_filter_objectclasses = ['krbpwdpolicy', 'ipapwdpolicy']
    default_attributes = [
        'cn',
        'cospriority',
        'krbmaxpwdlife',
        'krbminpwdlife',
        'krbpwdhistorylength',
        'krbpwdmindiffchars',
        'krbpwdminlength',
        'krbpwdmaxfailure',
        'krbpwdfailurecountinterval',
        'krbpwdlockoutduration',
        'ipapwdmaxrepeat',
        'ipapwdmaxsequence',
        'ipapwddictcheck',
        'ipapwdusercheck',
    ]
    managed_permissions = {
        'System: Read Group Password Policy': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'permission',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'cospriority',
                'krbmaxpwdlife',
                'krbminpwdlife',
                'krbpwdfailurecountinterval',
                'krbpwdhistorylength',
                'krbpwdlockoutduration',
                'krbpwdmaxfailure',
                'krbpwdmindiffchars',
                'krbpwdminlength',
                'objectclass',
                'ipapwdmaxrepeat',
                'ipapwdmaxsequence',
                'ipapwddictcheck',
                'ipapwdusercheck',
            },
            'default_privileges': {
                'Password Policy Readers',
                'Password Policy Administrator',
            },
        },
        'System: Add Group Password Policy': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Add Group Password Policy";allow (add) groupdn = "ldap:///cn=Add Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
        'System: Delete Group Password Policy': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Delete Group Password Policy";allow (delete) groupdn = "ldap:///cn=Delete Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
        'System: Modify Group Password Policy': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'krbmaxpwdlife',
                'krbminpwdlife',
                'krbpwdfailurecountinterval',
                'krbpwdhistorylength',
                'krbpwdlockoutduration',
                'krbpwdmaxfailure',
                'krbpwdmindiffchars',
                'krbpwdminlength',
                'ipapwdmaxrepeat',
                'ipapwdmaxsequence',
                'ipapwddictcheck',
                'ipapwdusercheck',
            },
            'replaces': [
                '(targetattr = "krbmaxpwdlife || krbminpwdlife || krbpwdhistorylength || krbpwdmindiffchars || krbpwdminlength || krbpwdmaxfailure || krbpwdfailurecountinterval || krbpwdlockoutduration")(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=Modify Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
    }

    label = _('Password Policies')
    label_singular = _('Password Policy')

    takes_params = (
        Str(
            'cn?',
            cli_name='group',
            label=_('Group'),
            doc=_('Manage password policy for specific group'),
            primary_key=True,
        ),
        Int(
            'krbmaxpwdlife?',
            cli_name='maxlife',
            label=_('Max lifetime (days)'),
            doc=_('Maximum password lifetime (in days)'),
            minvalue=0,
            maxvalue=20000,  # a little over 54 years
        ),
        Int(
            'krbminpwdlife?',
            cli_name='minlife',
            label=_('Min lifetime (hours)'),
            doc=_('Minimum password lifetime (in hours)'),
            minvalue=0,
        ),
        Int(
            'krbpwdhistorylength?',
            cli_name='history',
            label=_('History size'),
            doc=_('Password history size'),
            minvalue=0,
        ),
        Int(
            'krbpwdmindiffchars?',
            cli_name='minclasses',
            label=_('Character classes'),
            doc=_('Minimum number of character classes'),
            minvalue=0,
            maxvalue=5,
        ),
        Int(
            'krbpwdminlength?',
            cli_name='minlength',
            label=_('Min length'),
            doc=_('Minimum length of password'),
            minvalue=0,
        ),
        Int(
            'cospriority',
            cli_name='priority',
            label=_('Priority'),
            doc=_(
                'Priority of the policy (higher number means lower priority'),
            minvalue=0,
            flags=('virtual_attribute', ),
        ),
        Int(
            'krbpwdmaxfailure?',
            cli_name='maxfail',
            label=_('Max failures'),
            doc=_('Consecutive failures before lockout'),
            minvalue=0,
        ),
        Int(
            'krbpwdfailurecountinterval?',
            cli_name='failinterval',
            label=_('Failure reset interval'),
            doc=_('Period after which failure count will be reset (seconds)'),
            minvalue=0,
        ),
        Int(
            'krbpwdlockoutduration?',
            cli_name='lockouttime',
            label=_('Lockout duration'),
            doc=_('Period for which lockout is enforced (seconds)'),
            minvalue=0,
        ),
        Int(
            'ipapwdmaxrepeat?',
            cli_name='maxrepeat',
            label=_('Max repeat'),
            doc=_('Maximum number of same consecutive characters'),
            minvalue=0,
            maxvalue=256,
            default=0,
        ),
        Int(
            'ipapwdmaxsequence?',
            cli_name='maxsequence',
            label=_('Max sequence'),
            doc=_('The max. length of monotonic character sequences (abcd)'),
            minvalue=0,
            maxvalue=256,
            default=0,
        ),
        Bool(
            'ipapwddictcheck?',
            cli_name='dictcheck',
            label=_('Dictionary check'),
            doc=_('Check if the password is a dictionary word'),
            default=False,
        ),
        Bool(
            'ipapwdusercheck?',
            cli_name='usercheck',
            label=_('User check'),
            doc=_('Check if the password contains the username'),
            default=False,
        ),
    )

    def get_dn(self, *keys, **options):
        if keys[-1] is not None:
            return self.backend.make_dn_from_attr(
                self.primary_key.name, keys[-1],
                DN(self.container_dn, api.env.basedn))
        return global_policy_dn

    def convert_time_for_output(self, entry_attrs, **options):
        # Convert seconds to hours and days for displaying to user
        if not options.get('raw', False):
            if 'krbmaxpwdlife' in entry_attrs:
                entry_attrs['krbmaxpwdlife'][0] = unicode(
                    int(entry_attrs['krbmaxpwdlife'][0]) // 86400)
            if 'krbminpwdlife' in entry_attrs:
                entry_attrs['krbminpwdlife'][0] = unicode(
                    int(entry_attrs['krbminpwdlife'][0]) // 3600)

    def convert_time_on_input(self, entry_attrs):
        # Convert hours and days to seconds for writing to LDAP
        if 'krbmaxpwdlife' in entry_attrs and entry_attrs['krbmaxpwdlife']:
            entry_attrs['krbmaxpwdlife'] = entry_attrs['krbmaxpwdlife'] * 86400
        if 'krbminpwdlife' in entry_attrs and entry_attrs['krbminpwdlife']:
            entry_attrs['krbminpwdlife'] = entry_attrs['krbminpwdlife'] * 3600

    def validate_minlength(self, ldap, entry_attrs, add=False, *keys):
        """
        If any of the libpwquality options are used then the minimum
        length must be >= 6 which is the built-in default of libpwquality.
        Allowing a lower value to be set will result in a failed policy
        check and a generic error message.
        """
        def get_val(entry, attr):
            """Get a single value from a list or a string"""
            val = entry.get(attr, 0)
            if isinstance(val, list):
                val = val[0]
            return val

        def has_pwquality_set(entry):
            for attr in [
                    'ipapwdmaxrepeat', 'ipapwdmaxsequence', 'ipapwddictcheck',
                    'ipapwdusercheck'
            ]:
                val = get_val(entry, attr)
                if val not in ('FALSE', '0', 0, None):
                    return True
            return False

        has_pwquality_value = False
        if not add:
            if len(keys) > 0:
                existing_entry = self.api.Command.pwpolicy_show(
                    keys[-1],
                    all=True,
                )['result']
            else:
                existing_entry = self.api.Command.pwpolicy_show(
                    all=True, )['result']
            existing_entry.update(entry_attrs)
            min_length = int(get_val(existing_entry, 'krbpwdminlength'))

            has_pwquality_value = has_pwquality_set(existing_entry)
        else:
            min_length = int(get_val(entry_attrs, 'krbpwdminlength'))
            has_pwquality_value = has_pwquality_set(entry_attrs)

        if min_length and min_length < 6 and has_pwquality_value:
            raise errors.ValidationError(
                name='minlength',
                error=_('Minimum length must be >= 6 if maxrepeat, '
                        'maxsequence, dictcheck or usercheck are defined'))

    def validate_lifetime(self, entry_attrs, add=False, *keys):
        """
        Ensure that the maximum lifetime is greater than the minimum.
        If there is no minimum lifetime set then don't return an error.
        """
        maxlife = entry_attrs.get('krbmaxpwdlife', None)
        minlife = entry_attrs.get('krbminpwdlife', None)
        existing_entry = {}
        if not add:  # then read existing entry
            existing_entry = self.api.Command.pwpolicy_show(
                keys[-1],
                all=True,
            )['result']
            if minlife is None and 'krbminpwdlife' in existing_entry:
                minlife = int(existing_entry['krbminpwdlife'][0]) * 3600
            if maxlife is None and 'krbmaxpwdlife' in existing_entry:
                maxlife = int(existing_entry['krbmaxpwdlife'][0]) * 86400

        if maxlife not in (None, 0) and minlife is not None:
            if minlife > maxlife:
                raise errors.ValidationError(
                    name='maxlife',
                    error=_("Maximum password life must be equal to "
                            "or greater than the minimum."),
                )

    def add_cospriority(self, entry, pwpolicy_name, rights=True):
        if pwpolicy_name and pwpolicy_name != global_policy_name:
            cos_entry = self.api.Command.cosentry_show(pwpolicy_name,
                                                       rights=rights,
                                                       all=rights)['result']
            if cos_entry.get('cospriority') is not None:
                entry['cospriority'] = cos_entry['cospriority']
                if rights:
                    entry['attributelevelrights']['cospriority'] = \
                        cos_entry['attributelevelrights']['cospriority']
Esempio n. 21
0
class radiusproxy(LDAPObject):
    """
    RADIUS Server object.
    """
    container_dn = api.env.container_radiusproxy
    object_name = _('RADIUS proxy server')
    object_name_plural = _('RADIUS proxy servers')
    object_class = ['ipatokenradiusconfiguration']
    default_attributes = [
        'cn', 'description', 'ipatokenradiusserver', 'ipatokenradiustimeout',
        'ipatokenradiusretries', 'ipatokenusermapattribute'
    ]
    search_attributes = ['cn', 'description', 'ipatokenradiusserver']
    rdn_is_primary_key = True
    label = _('RADIUS Servers')
    label_singular = _('RADIUS Server')

    takes_params = (
        Str(
            'cn',
            cli_name='name',
            label=_('RADIUS proxy server name'),
            primary_key=True,
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('A description of this RADIUS proxy server'),
        ),
        Str(
            'ipatokenradiusserver+',
            validate_radiusserver,
            cli_name='server',
            label=_('Server'),
            doc=_('The hostname or IP (with or without port)'),
        ),
        Password(
            'ipatokenradiussecret',
            cli_name='secret',
            label=_('Secret'),
            doc=_('The secret used to encrypt data'),
            confirm=True,
            flags=['no_option'],
        ),
        Int(
            'ipatokenradiustimeout?',
            cli_name='timeout',
            label=_('Timeout'),
            doc=_('The total timeout across all retries (in seconds)'),
            minvalue=1,
        ),
        Int(
            'ipatokenradiusretries?',
            cli_name='retries',
            label=_('Retries'),
            doc=_('The number of times to retry authentication'),
            minvalue=0,
            maxvalue=10,
        ),
        Str(
            'ipatokenusermapattribute?',
            validate_attributename,
            cli_name='userattr',
            label=_('User attribute'),
            doc=_('The username attribute on the user object'),
        ),
    )
Esempio n. 22
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'))
Esempio n. 23
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)
Esempio n. 24
0
class idoverrideuser(baseidoverride):

    object_name = _('User ID override')
    object_name_plural = _('User ID overrides')

    label = _('User ID overrides')
    label_singular = _('User ID override')
    rdn_is_primary_key = True

    permission_filter_objectclasses = ['ipaUserOverride']
    managed_permissions = {
        'System: Read User ID Overrides': {
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectClass',
                'ipaAnchorUUID',
                'uidNumber',
                'description',
                'homeDirectory',
                'uid',
                'ipaOriginalUid',
                'loginShell',
                'gecos',
                'gidNumber',
                'ipaSshPubkey',
            },
        },
    }

    object_class = baseidoverride.object_class + ['ipaUserOverride']
    possible_objectclasses = ['ipasshuser', 'ipaSshGroupOfPubKeys']
    default_attributes = baseidoverride.default_attributes + [
        'homeDirectory',
        'uidNumber',
        'uid',
        'ipaOriginalUid',
        'loginShell',
        'ipaSshPubkey',
        'gidNumber',
        'gecos',
    ]

    takes_params = baseidoverride.takes_params + (
        Str(
            'uid?',
            pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$',
            pattern_errmsg='may only include letters, numbers, _, -, . and $',
            maxlength=255,
            cli_name='login',
            label=_('User login'),
            normalizer=lambda value: value.lower(),
        ),
        Int(
            'uidnumber?',
            cli_name='uid',
            label=_('UID'),
            doc=_('User ID Number'),
            minvalue=1,
        ),
        Str(
            'gecos?',
            label=_('GECOS'),
        ),
        Int(
            'gidnumber?',
            label=_('GID'),
            doc=_('Group ID Number'),
            minvalue=1,
        ),
        Str(
            'homedirectory?',
            cli_name='homedir',
            label=_('Home directory'),
        ),
        Str(
            'loginshell?',
            cli_name='shell',
            label=_('Login shell'),
        ),
        Str('ipaoriginaluid?', flags=['no_option', 'no_output']),
        Str(
            'ipasshpubkey*',
            validate_sshpubkey,
            cli_name='sshpubkey',
            label=_('SSH public key'),
            normalizer=normalize_sshpubkey,
            csv=True,
            flags=['no_search'],
        ),
    )

    override_object = 'user'

    def update_original_uid_reference(self, entry_attrs):
        anchor = entry_attrs.single_value['ipaanchoruuid']
        try:
            original_uid = resolve_anchor_to_object_name(
                self.backend, self.override_object, anchor)
            entry_attrs['ipaOriginalUid'] = original_uid

        except (errors.NotFound, errors.ValidationError):
            # Anchor could not be resolved, this means we had to specify the
            # object to manipulate using a raw anchor value already, hence
            # we have no way to update the original_uid
            pass
Esempio n. 25
0
class pwpolicy(LDAPObject):
    """
    Password Policy object
    """
    container_dn = DN(('cn', api.env.realm), ('cn', 'kerberos'))
    object_name = _('password policy')
    object_name_plural = _('password policies')
    object_class = ['top', 'nscontainer', 'krbpwdpolicy']
    permission_filter_objectclasses = ['krbpwdpolicy']
    default_attributes = [
        'cn',
        'cospriority',
        'krbmaxpwdlife',
        'krbminpwdlife',
        'krbpwdhistorylength',
        'krbpwdmindiffchars',
        'krbpwdminlength',
        'krbpwdmaxfailure',
        'krbpwdfailurecountinterval',
        'krbpwdlockoutduration',
    ]
    managed_permissions = {
        'System: Read Group Password Policy': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'permission',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'cospriority',
                'krbmaxpwdlife',
                'krbminpwdlife',
                'krbpwdfailurecountinterval',
                'krbpwdhistorylength',
                'krbpwdlockoutduration',
                'krbpwdmaxfailure',
                'krbpwdmindiffchars',
                'krbpwdminlength',
                'objectclass',
            },
            'default_privileges': {
                'Password Policy Readers',
                'Password Policy Administrator',
            },
        },
        'System: Add Group Password Policy': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Add Group Password Policy";allow (add) groupdn = "ldap:///cn=Add Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
        'System: Delete Group Password Policy': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Delete Group Password Policy";allow (delete) groupdn = "ldap:///cn=Delete Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
        'System: Modify Group Password Policy': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'krbmaxpwdlife', 'krbminpwdlife', 'krbpwdfailurecountinterval',
                'krbpwdhistorylength', 'krbpwdlockoutduration',
                'krbpwdmaxfailure', 'krbpwdmindiffchars', 'krbpwdminlength'
            },
            'replaces': [
                '(targetattr = "krbmaxpwdlife || krbminpwdlife || krbpwdhistorylength || krbpwdmindiffchars || krbpwdminlength || krbpwdmaxfailure || krbpwdfailurecountinterval || krbpwdlockoutduration")(target = "ldap:///cn=*,cn=$REALM,cn=kerberos,$SUFFIX")(version 3.0;acl "permission:Modify Group Password Policy";allow (write) groupdn = "ldap:///cn=Modify Group Password Policy,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Password Policy Administrator'},
        },
    }

    label = _('Password Policies')
    label_singular = _('Password Policy')

    takes_params = (
        Str(
            'cn?',
            cli_name='group',
            label=_('Group'),
            doc=_('Manage password policy for specific group'),
            primary_key=True,
        ),
        Int(
            'krbmaxpwdlife?',
            cli_name='maxlife',
            label=_('Max lifetime (days)'),
            doc=_('Maximum password lifetime (in days)'),
            minvalue=0,
            maxvalue=20000,  # a little over 54 years
        ),
        Int(
            'krbminpwdlife?',
            cli_name='minlife',
            label=_('Min lifetime (hours)'),
            doc=_('Minimum password lifetime (in hours)'),
            minvalue=0,
        ),
        Int(
            'krbpwdhistorylength?',
            cli_name='history',
            label=_('History size'),
            doc=_('Password history size'),
            minvalue=0,
        ),
        Int(
            'krbpwdmindiffchars?',
            cli_name='minclasses',
            label=_('Character classes'),
            doc=_('Minimum number of character classes'),
            minvalue=0,
            maxvalue=5,
        ),
        Int(
            'krbpwdminlength?',
            cli_name='minlength',
            label=_('Min length'),
            doc=_('Minimum length of password'),
            minvalue=0,
        ),
        Int(
            'cospriority',
            cli_name='priority',
            label=_('Priority'),
            doc=_(
                'Priority of the policy (higher number means lower priority'),
            minvalue=0,
            flags=('virtual_attribute', ),
        ),
        Int(
            'krbpwdmaxfailure?',
            cli_name='maxfail',
            label=_('Max failures'),
            doc=_('Consecutive failures before lockout'),
            minvalue=0,
        ),
        Int(
            'krbpwdfailurecountinterval?',
            cli_name='failinterval',
            label=_('Failure reset interval'),
            doc=_('Period after which failure count will be reset (seconds)'),
            minvalue=0,
        ),
        Int(
            'krbpwdlockoutduration?',
            cli_name='lockouttime',
            label=_('Lockout duration'),
            doc=_('Period for which lockout is enforced (seconds)'),
            minvalue=0,
        ),
    )

    def get_dn(self, *keys, **options):
        if keys[-1] is not None:
            return self.backend.make_dn_from_attr(
                self.primary_key.name, keys[-1],
                DN(self.container_dn, api.env.basedn))
        return global_policy_dn

    def convert_time_for_output(self, entry_attrs, **options):
        # Convert seconds to hours and days for displaying to user
        if not options.get('raw', False):
            if 'krbmaxpwdlife' in entry_attrs:
                entry_attrs['krbmaxpwdlife'][0] = unicode(
                    int(entry_attrs['krbmaxpwdlife'][0]) // 86400)
            if 'krbminpwdlife' in entry_attrs:
                entry_attrs['krbminpwdlife'][0] = unicode(
                    int(entry_attrs['krbminpwdlife'][0]) // 3600)

    def convert_time_on_input(self, entry_attrs):
        # Convert hours and days to seconds for writing to LDAP
        if 'krbmaxpwdlife' in entry_attrs and entry_attrs['krbmaxpwdlife']:
            entry_attrs['krbmaxpwdlife'] = entry_attrs['krbmaxpwdlife'] * 86400
        if 'krbminpwdlife' in entry_attrs and entry_attrs['krbminpwdlife']:
            entry_attrs['krbminpwdlife'] = entry_attrs['krbminpwdlife'] * 3600

    def validate_lifetime(self, entry_attrs, add=False, *keys):
        """
        Ensure that the maximum lifetime is greater than the minimum.
        If there is no minimum lifetime set then don't return an error.
        """
        maxlife = entry_attrs.get('krbmaxpwdlife', None)
        minlife = entry_attrs.get('krbminpwdlife', None)
        existing_entry = {}
        if not add:  # then read existing entry
            existing_entry = self.api.Command.pwpolicy_show(
                keys[-1],
                all=True,
            )['result']
            if minlife is None and 'krbminpwdlife' in existing_entry:
                minlife = int(existing_entry['krbminpwdlife'][0]) * 3600
            if maxlife is None and 'krbmaxpwdlife' in existing_entry:
                maxlife = int(existing_entry['krbmaxpwdlife'][0]) * 86400

        if maxlife not in (None, 0) and minlife is not None:
            if minlife > maxlife:
                raise errors.ValidationError(
                    name='maxlife',
                    error=_(
                        'Maximum password life must be greater than minimum.'),
                )

    def add_cospriority(self, entry, pwpolicy_name, rights=True):
        if pwpolicy_name and pwpolicy_name != global_policy_name:
            cos_entry = self.api.Command.cosentry_show(pwpolicy_name,
                                                       rights=rights,
                                                       all=rights)['result']
            if cos_entry.get('cospriority') is not None:
                entry['cospriority'] = cos_entry['cospriority']
                if rights:
                    entry['attributelevelrights']['cospriority'] = \
                        cos_entry['attributelevelrights']['cospriority']
Esempio n. 26
0
class user(LDAPObject):
    """
    User object.
    """
    container_dn = api.env.container_user
    object_name = _('user')
    object_name_plural = _('users')
    object_class = ['posixaccount']
    object_class_config = 'ipauserobjectclasses'
    possible_objectclasses = ['meporiginentry']
    disallow_object_classes = ['krbticketpolicyaux']
    search_attributes_config = 'ipausersearchfields'
    default_attributes = [
        'uid', 'givenname', 'sn', 'homedirectory', 'loginshell',
        'uidnumber', 'gidnumber', 'mail', 'ou',
        'telephonenumber', 'title', 'memberof', 'nsaccountlock',
        'memberofindirect',
    ]
    search_display_attributes = [
        'uid', 'givenname', 'sn', 'homedirectory', 'loginshell',
        'mail', 'telephonenumber', 'title', 'nsaccountlock',
        'uidnumber', 'gidnumber', 'sshpubkeyfp',
    ]
    uuid_attribute = 'ipauniqueid'
    attribute_members = {
        'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
        'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
    }
    rdn_is_primary_key = True
    bindable = True
    password_attributes = [('userpassword', 'has_password'),
                           ('krbprincipalkey', 'has_keytab')]

    label = _('Users')
    label_singular = _('User')

    takes_params = (
        Str('uid',
            pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$',
            pattern_errmsg='may only include letters, numbers, _, -, . and $',
            maxlength=255,
            cli_name='login',
            label=_('User login'),
            primary_key=True,
            default_from=lambda givenname, sn: givenname[0] + sn,
            normalizer=lambda value: value.lower(),
        ),
        Str('givenname',
            cli_name='first',
            label=_('First name'),
        ),
        Str('sn',
            cli_name='last',
            label=_('Last name'),
        ),
        Str('cn',
            label=_('Full name'),
            default_from=lambda givenname, sn: '%s %s' % (givenname, sn),
            autofill=True,
        ),
        Str('displayname?',
            label=_('Display name'),
            default_from=lambda givenname, sn: '%s %s' % (givenname, sn),
            autofill=True,
        ),
        Str('initials?',
            label=_('Initials'),
            default_from=lambda givenname, sn: '%c%c' % (givenname[0], sn[0]),
            autofill=True,
        ),
        Str('homedirectory?',
            cli_name='homedir',
            label=_('Home directory'),
        ),
        Str('gecos?',
            label=_('GECOS field'),
            default_from=lambda givenname, sn: '%s %s' % (givenname, sn),
            autofill=True,
        ),
        Str('loginshell?',
            cli_name='shell',
            label=_('Login shell'),
        ),
        Str('krbprincipalname?', validate_principal,
            cli_name='principal',
            label=_('Kerberos principal'),
            default_from=lambda uid: '%s@%s' % (uid.lower(), api.env.realm),
            autofill=True,
            flags=['no_update'],
            normalizer=lambda value: normalize_principal(value),
        ),
        Str('mail*',
            cli_name='email',
            label=_('Email address'),
        ),
        Password('userpassword?',
            cli_name='password',
            label=_('Password'),
            doc=_('Prompt to set the user password'),
            # FIXME: This is temporary till bug is fixed causing updates to
            # bomb out via the webUI.
            exclude='webui',
        ),
        Flag('random?',
            doc=_('Generate a random user password'),
            flags=('no_search', 'virtual_attribute'),
            default=False,
        ),
        Str('randompassword?',
            label=_('Random password'),
            flags=('no_create', 'no_update', 'no_search', 'virtual_attribute'),
        ),
        Int('uidnumber',
            cli_name='uid',
            label=_('UID'),
            doc=_('User ID Number (system will assign one if not provided)'),
            autofill=True,
            default=DNA_MAGIC,
            minvalue=1,
        ),
        Int('gidnumber',
            label=_('GID'),
            doc=_('Group ID Number'),
            minvalue=1,
            default=DNA_MAGIC,
            autofill=True,
        ),
        Str('street?',
            cli_name='street',
            label=_('Street address'),
        ),
        Str('l?',
            cli_name='city',
            label=_('City'),
        ),
        Str('st?',
            cli_name='state',
            label=_('State/Province'),
        ),
        Str('postalcode?',
            label=_('ZIP'),
        ),
        Str('telephonenumber*',
            cli_name='phone',
            label=_('Telephone Number')
        ),
        Str('mobile*',
            label=_('Mobile Telephone Number')
        ),
        Str('pager*',
            label=_('Pager Number')
        ),
        Str('facsimiletelephonenumber*',
            cli_name='fax',
            label=_('Fax Number'),
        ),
        Str('ou?',
            cli_name='orgunit',
            label=_('Org. Unit'),
        ),
        Str('title?',
            label=_('Job Title'),
        ),
        Str('manager?',
            label=_('Manager'),
        ),
        Str('carlicense?',
            label=_('Car License'),
        ),
        Bool('nsaccountlock?',
            label=_('Account disabled'),
            flags=['no_option'],
        ),
        Str('ipasshpubkey*', validate_sshpubkey,
            cli_name='sshpubkey',
            label=_('SSH public key'),
            normalizer=normalize_sshpubkey,
            csv=True,
            flags=['no_search'],
        ),
    )

    def _normalize_and_validate_email(self, email, config=None):
        if not config:
            config = self.backend.get_ipa_config()[1]

        # check if default email domain should be added
        defaultdomain = config.get('ipadefaultemaildomain', [None])[0]
        if email:
            norm_email = []
            if not isinstance(email, (list, tuple)):
                email = [email]
            for m in email:
                if isinstance(m, basestring):
                    if '@' not in m and defaultdomain:
                        m = m + u'@' + defaultdomain
                    if not Email(m):
                        raise errors.ValidationError(name='email', error=_('invalid e-mail format: %(email)s') % dict(email=m))
                    norm_email.append(m)
                else:
                    if not Email(m):
                        raise errors.ValidationError(name='email', error=_('invalid e-mail format: %(email)s') % dict(email=m))
                    norm_email.append(m)
            return norm_email

        return email

    def _normalize_manager(self, manager):
        """
        Given a userid verify the user's existence and return the dn.
        """
        if not manager:
            return None

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

        return manager

    def _convert_manager(self, entry_attrs, **options):
        """
        Convert a manager dn into a userid
        """
        if options.get('raw', False):
             return

        if 'manager' in entry_attrs:
            for m in xrange(len(entry_attrs['manager'])):
                entry_attrs['manager'][m] = self.get_primary_key_from_dn(entry_attrs['manager'][m])
Esempio n. 27
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)
Esempio n. 28
0
class group(LDAPObject):
    """
    Group object.
    """
    container_dn = api.env.container_group
    object_name = _('group')
    object_name_plural = _('groups')
    object_class = ['ipausergroup']
    object_class_config = 'ipagroupobjectclasses'
    possible_objectclasses = ['posixGroup', 'mepManagedEntry', 'ipaExternalGroup']
    permission_filter_objectclasses = ['posixgroup', 'ipausergroup']
    search_attributes_config = 'ipagroupsearchfields'
    default_attributes = [
        'cn', 'description', 'gidnumber', 'member', 'memberof',
        'memberindirect', 'memberofindirect', 'ipaexternalmember',
    ]
    uuid_attribute = 'ipauniqueid'
    attribute_members = {
        'member': ['user', 'group'],
        'memberof': ['group', 'netgroup', 'role', 'hbacrule', 'sudorule'],
        'memberindirect': ['user', 'group'],
        'memberofindirect': ['group', 'netgroup', 'role', 'hbacrule',
        'sudorule'],
    }
    rdn_is_primary_key = True
    managed_permissions = {
        'System: Read Groups': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'anonymous',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'businesscategory', 'cn', 'description', 'gidnumber',
                'ipaexternalmember', 'ipauniqueid', 'mepmanagedby', 'o',
                'objectclass', 'ou', 'owner', 'seealso',
                'ipantsecurityidentifier'
            },
        },
        'System: Read Group Membership': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'member', 'memberof', 'memberuid', 'memberuser', 'memberhost',
            },
        },
        'System: Add Groups': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Groups";allow (add) groupdn = "ldap:///cn=Add Groups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Group Administrators'},
        },
        'System: Modify Group Membership': {
            'ipapermright': {'write'},
            'ipapermtargetfilter': [
                '(objectclass=ipausergroup)',
                '(!(cn=admins))',
            ],
            'ipapermdefaultattr': {'member'},
            'replaces': [
                '(targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group membership";allow (write) groupdn = "ldap:///cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX";)',
                '(targetfilter = "(!(cn=admins))")(targetattr = "member")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Group membership";allow (write) groupdn = "ldap:///cn=Modify Group membership,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {
                'Group Administrators', 'Modify Group membership'
            },
        },
        'System: Modify Groups': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'cn', 'description', 'gidnumber', 'ipauniqueid',
                'mepmanagedby', 'objectclass'
            },
            'replaces': [
                '(targetattr = "cn || description || gidnumber || objectclass || mepmanagedby || ipauniqueid")(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Groups";allow (write) groupdn = "ldap:///cn=Modify Groups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Group Administrators'},
        },
        'System: Remove Groups': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=groups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Groups";allow (delete) groupdn = "ldap:///cn=Remove Groups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Group Administrators'},
        },
        'System: Read Group Compat Tree': {
            'non_object': True,
            'ipapermbindruletype': 'anonymous',
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN('cn=groups', 'cn=compat', api.env.basedn),
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass', 'cn', 'memberuid', 'gidnumber',
            },
        },
        'System: Read Group Views Compat Tree': {
            'non_object': True,
            'ipapermbindruletype': 'anonymous',
            'ipapermlocation': api.env.basedn,
            'ipapermtarget': DN('cn=groups', 'cn=*', 'cn=views', 'cn=compat', api.env.basedn),
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass', 'cn', 'memberuid', 'gidnumber',
            },
        },
    }

    label = _('User Groups')
    label_singular = _('User Group')

    takes_params = (
        Str('cn',
            pattern='^[a-zA-Z0-9_.][a-zA-Z0-9_.-]{0,252}[a-zA-Z0-9_.$-]?$',
            pattern_errmsg='may only include letters, numbers, _, -, . and $',
            maxlength=255,
            cli_name='group_name',
            label=_('Group name'),
            primary_key=True,
            normalizer=lambda value: value.lower(),
        ),
        Str('description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('Group description'),
        ),
        Int('gidnumber?',
            cli_name='gid',
            label=_('GID'),
            doc=_('GID (use this option to set it manually)'),
            minvalue=1,
        ),
    )
Esempio n. 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
Esempio n. 30
0
class BaseCertObject(Object):
    takes_params = (
        Str(
            'cacn?',
            cli_name='ca',
            default=IPA_CA_CN,
            autofill=True,
            label=_('Issuing CA'),
            doc=_('Name of issuing CA'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Bytes(
            'certificate',
            validate_certificate,
            label=_("Certificate"),
            doc=_("Base-64 encoded certificate."),
            normalizer=x509.normalize_certificate,
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNParam(
            'subject',
            label=_('Subject'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_rfc822name*',
            label=_('Subject email address'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNSNameParam(
            'san_dnsname*',
            label=_('Subject DNS name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_x400address*',
            label=_('Subject X.400 address'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNParam(
            'san_directoryname*',
            label=_('Subject directory name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_edipartyname*',
            label=_('Subject EDI Party name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_uri*',
            label=_('Subject URI'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_ipaddress*',
            label=_('Subject IP Address'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_oid*',
            label=_('Subject OID'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Principal(
            'san_other_upn*',
            label=_('Subject UPN'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Principal(
            'san_other_kpn*',
            label=_('Subject Kerberos principal name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'san_other*',
            label=_('Subject Other Name'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DNParam(
            'issuer',
            label=_('Issuer'),
            doc=_('Issuer DN'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DateTime(
            'valid_not_before',
            label=_('Not Before'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        DateTime(
            'valid_not_after',
            label=_('Not After'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'md5_fingerprint',
            label=_('Fingerprint (MD5)'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'sha1_fingerprint',
            label=_('Fingerprint (SHA1)'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Int(
            'serial_number',
            label=_('Serial number'),
            doc=_(
                'Serial number in decimal or if prefixed with 0x in hexadecimal'
            ),
            normalizer=normalize_serial_number,
            flags={'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'serial_number_hex',
            label=_('Serial number (hex)'),
            flags={'no_create', 'no_update', 'no_search'},
        ),
    )

    def _parse(self, obj, full=True):
        """Extract certificate-specific data into a result object.

        ``obj``
            Result object containing certificate, into which extracted
            data will be inserted.
        ``full``
            Whether to include all fields, or only the ones we guess
            people want to see most of the time.  Also add
            recognised otherNames to the generic ``san_other``
            attribute when ``True`` in addition to the specialised
            attribute.

        """
        if 'certificate' in obj:
            cert = x509.load_certificate(obj['certificate'])
            obj['subject'] = DN(cert.subject)
            obj['issuer'] = DN(cert.issuer)
            obj['serial_number'] = cert.serial
            obj['valid_not_before'] = x509.format_datetime(
                cert.not_valid_before)
            obj['valid_not_after'] = x509.format_datetime(cert.not_valid_after)
            if full:
                obj['md5_fingerprint'] = x509.to_hex_with_colons(
                    cert.fingerprint(hashes.MD5()))
                obj['sha1_fingerprint'] = x509.to_hex_with_colons(
                    cert.fingerprint(hashes.SHA1()))

            general_names = x509.process_othernames(
                x509.get_san_general_names(cert))

            for gn in general_names:
                try:
                    self._add_san_attribute(obj, full, gn)
                except Exception:
                    # Invalid GeneralName (i.e. not a valid X.509 cert);
                    # don't fail but log something about it
                    root_logger.warning(
                        "Encountered bad GeneralName; skipping", exc_info=True)

        serial_number = obj.get('serial_number')
        if serial_number is not None:
            obj['serial_number_hex'] = u'0x%X' % serial_number

    def _add_san_attribute(self, obj, full, gn):
        name_type_map = {
            cryptography.x509.RFC822Name:
            ('san_rfc822name', attrgetter('value')),
            cryptography.x509.DNSName: ('san_dnsname', attrgetter('value')),
            # cryptography.x509.???: 'san_x400address',
            cryptography.x509.DirectoryName:
            ('san_directoryname', lambda x: DN(x.value)),
            # cryptography.x509.???: 'san_edipartyname',
            cryptography.x509.UniformResourceIdentifier: ('san_uri',
                                                          attrgetter('value')),
            cryptography.x509.IPAddress:
            ('san_ipaddress', attrgetter('value')),
            cryptography.x509.RegisteredID:
            ('san_oid', attrgetter('value.dotted_string')),
            cryptography.x509.OtherName: ('san_other', _format_othername),
            x509.UPN: ('san_other_upn', attrgetter('name')),
            x509.KRB5PrincipalName: ('san_other_kpn', attrgetter('name')),
        }
        default_attrs = {
            'san_rfc822name',
            'san_dnsname',
            'san_other_upn',
            'san_other_kpn',
        }

        if type(gn) not in name_type_map:
            return

        attr_name, format_name = name_type_map[type(gn)]

        if full or attr_name in default_attrs:
            attr_value = self.params[attr_name].type(format_name(gn))
            obj.setdefault(attr_name, []).append(attr_value)

        if full and attr_name.startswith('san_other_'):
            # also include known otherName in generic otherName attribute
            attr_value = self.params['san_other'].type(_format_othername(gn))
            obj.setdefault('san_other', []).append(attr_value)