Пример #1
0
""")

register = Registry()

# Options used by Condition Add and Remove.
INCLUDE_RE = 'automemberinclusiveregex'
EXCLUDE_RE = 'automemberexclusiveregex'

REBUILD_TASK_CONTAINER = DN(('cn', 'automember rebuild membership'),
                            ('cn', 'tasks'), ('cn', 'config'))

regex_attrs = (
    Str(
        'automemberinclusiveregex*',
        cli_name='inclusive_regex',
        label=_('Inclusive Regex'),
        doc=_('Inclusive Regex'),
        alwaysask=True,
        flags={'no_create', 'no_update', 'no_search'},
    ),
    Str(
        'automemberexclusiveregex*',
        cli_name='exclusive_regex',
        label=_('Exclusive Regex'),
        doc=_('Exclusive Regex'),
        alwaysask=True,
        flags={'no_create', 'no_update', 'no_search'},
    ),
)

regex_key = (Str(
    'key',
Пример #2
0
class json_metadata(Command):
    """
    Export plugin meta-data for the webUI.
    """
    NO_CLI = True


    takes_args = (
        Str('objname?',
            doc=_('Name of object to export'),
        ),
        Str('methodname?',
            doc=_('Name of method to export'),
        ),
    )

    takes_options = (
        Str('object?',
            doc=_('Name of object to export'),
        ),
        Str('method?',
            doc=_('Name of method to export'),
        ),
        Str('command?',
            doc=_('Name of command to export'),
        ),
    )

    has_output = (
        Output('objects', dict, doc=_('Dict of JSON encoded IPA Objects')),
        Output('methods', dict, doc=_('Dict of JSON encoded IPA Methods')),
        Output('commands', dict, doc=_('Dict of JSON encoded IPA Commands')),
    )

    def execute(self, objname=None, methodname=None, **options):
        objects = dict()
        methods = dict()
        commands = dict()

        empty = True

        try:
            if not objname:
                objname = options['object']
            if objname in self.api.Object:
                o = self.api.Object[objname]
                objects = dict([(o.name, json_serialize(o))])
            elif objname == "all":
                objects = dict(
                    (o.name, json_serialize(o)) for o in self.api.Object()
                    if o is self.api.Object[o.name]
                )
            empty = False
        except KeyError:
            pass

        try:
            if not methodname:
                methodname = options['method']
            if (methodname in self.api.Method and
                    not isinstance(self.api.Method[methodname], Local)):
                m = self.api.Method[methodname]
                methods = dict([(m.name, json_serialize(m))])
            elif methodname == "all":
                methods = dict(
                    (m.name, json_serialize(m)) for m in self.api.Method()
                    if (m is self.api.Method[m.name] and
                        not isinstance(m, Local))
                )
            empty = False
        except KeyError:
            pass

        try:
            cmdname = options['command']
            if (cmdname in self.api.Command and
                    not isinstance(self.api.Command[cmdname], Local)):
                c = self.api.Command[cmdname]
                commands = dict([(c.name, json_serialize(c))])
            elif cmdname == "all":
                commands = dict(
                    (c.name, json_serialize(c)) for c in self.api.Command()
                    if (c is self.api.Command[c.name] and
                        not isinstance(c, Local))
                )
            empty = False
        except KeyError:
            pass

        if empty:
            objects = dict(
                (o.name, json_serialize(o)) for o in self.api.Object()
                if o is self.api.Object[o.name]
            )
            methods = dict(
                (m.name, json_serialize(m)) for m in self.api.Method()
                if (m is self.api.Method[m.name] and
                    not isinstance(m, Local))
            )
            commands = dict(
                (c.name, json_serialize(c)) for c in self.api.Command()
                if (c is self.api.Command[c.name] and
                    not isinstance(c, Local))
            )

        retval = dict([
            ("objects", objects),
            ("methods", methods),
            ("commands", commands),
        ])

        return retval
Пример #3
0
""")

register = Registry()

topic = 'sudo'


def deprecated(attribute):
    raise errors.ValidationError(name=attribute,
                                 error=_('this option has been deprecated.'))


hostmask_membership_param = Str(
    'hostmask?',
    validate_hostmask,
    label=_('host masks of allowed hosts'),
    flags=['no_create', 'no_update', 'no_search'],
    multivalue=True,
)


def validate_externaluser(ugettext, value):
    deprecated('externaluser')


def validate_runasextuser(ugettext, value):
    deprecated('runasexternaluser')


def validate_runasextgroup(ugettext, value):
    deprecated('runasexternalgroup')
Пример #4
0
class vault_archive(ModVaultData):
    __doc__ = _('Archive data into a vault.')

    takes_options = (
        Bytes(
            'data?',
            doc=_('Binary data to archive'),
        ),
        Str(  # TODO: use File parameter
            'in?',
            doc=_('File containing data to archive'),
        ),
        Str(
            'password?',
            cli_name='password',
            doc=_('Vault password'),
        ),
        Str(  # TODO: use File parameter
            'password_file?',
            cli_name='password_file',
            doc=_('File containing the vault password'),
        ),
        Flag(
            'override_password?',
            doc=_('Override existing password'),
        ),
    )

    @classmethod
    def __NO_CLI_getter(cls):  # pylint: disable=unused-private-member, #4756
        return (api.Command.get_plugin('vault_archive_internal') is
                _fake_vault_archive_internal)

    NO_CLI = classproperty(__NO_CLI_getter)

    @property
    def api_version(self):
        return self.api.Command.vault_archive_internal.api_version

    def get_args(self):
        for arg in self.api.Command.vault_archive_internal.args():
            yield arg
        for arg in super(vault_archive, self).get_args():
            yield arg

    def get_options(self):
        for option in self.api.Command.vault_archive_internal.options():
            if option.name not in ('nonce', 'session_key', 'vault_data',
                                   'version'):
                yield option
        for option in super(vault_archive, self).get_options():
            yield option

    def get_output_params(self):
        for param in self.api.Command.vault_archive_internal.output_params():
            yield param
        for param in super(vault_archive, self).get_output_params():
            yield param

    def _iter_output(self):
        return self.api.Command.vault_archive_internal.output()

    def _wrap_data(self, algo, json_vault_data):
        """Encrypt data with wrapped session key and transport cert

        :param algo: wrapping algorithm instance
        :param bytes json_vault_data: dumped vault data
        :return:
        """
        nonce = os.urandom(algo.block_size // 8)

        # wrap vault_data with session key
        padder = PKCS7(algo.block_size).padder()
        padded_data = padder.update(json_vault_data)
        padded_data += padder.finalize()

        cipher = Cipher(algo, modes.CBC(nonce), backend=default_backend())
        encryptor = cipher.encryptor()
        wrapped_vault_data = encryptor.update(
            padded_data) + encryptor.finalize()

        return nonce, wrapped_vault_data

    def forward(self, *args, **options):
        data = options.get('data')
        input_file = options.get('in')

        password = options.get('password')
        password_file = options.get('password_file')

        override_password = options.pop('override_password', False)

        # don't send these parameters to server
        if 'data' in options:
            del options['data']
        if 'in' in options:
            del options['in']
        if 'password' in options:
            del options['password']
        if 'password_file' in options:
            del options['password_file']

        # get data
        if data and input_file:
            raise errors.MutuallyExclusiveError(
                reason=_('Input data specified multiple times'))

        elif data:
            if len(data) > MAX_VAULT_DATA_SIZE:
                raise errors.ValidationError(
                    name="data",
                    error=
                    _("Size of data exceeds the limit. Current vault data size "
                      "limit is %(limit)d B") % {'limit': MAX_VAULT_DATA_SIZE})

        elif input_file:
            try:
                stat = os.stat(input_file)
            except OSError as exc:
                raise errors.ValidationError(
                    name="in",
                    error=_("Cannot read file '%(filename)s': %(exc)s") % {
                        'filename': input_file,
                        'exc': exc.args[1]
                    })
            if stat.st_size > MAX_VAULT_DATA_SIZE:
                raise errors.ValidationError(
                    name="in",
                    error=
                    _("Size of data exceeds the limit. Current vault data size "
                      "limit is %(limit)d B") % {'limit': MAX_VAULT_DATA_SIZE})
            data = validated_read('in', input_file, mode='rb')

        else:
            data = b''

        if self.api.env.in_server:
            backend = self.api.Backend.ldap2
        else:
            backend = self.api.Backend.rpcclient
        if not backend.isconnected():
            backend.connect()

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

        vault_type = vault['ipavaulttype'][0]

        if vault_type == u'standard':

            encrypted_key = None

        elif vault_type == u'symmetric':

            # get password
            if password and password_file:
                raise errors.MutuallyExclusiveError(
                    reason=_('Password specified multiple times'))

            elif password:
                pass

            elif password_file:
                password = validated_read('password-file',
                                          password_file,
                                          encoding='utf-8')
                password = password.rstrip('\n')

            else:
                if override_password:
                    password = self.api.Backend.textui.prompt_password(
                        'New password')
                else:
                    password = self.api.Backend.textui.prompt_password(
                        'Password', confirm=False)

            if not override_password:
                # verify password by retrieving existing data
                opts = options.copy()
                opts['password'] = password
                try:
                    self.api.Command.vault_retrieve(*args, **opts)
                except errors.NotFound:
                    pass

            salt = vault['ipavaultsalt'][0]

            # generate encryption key from vault password
            encryption_key = generate_symmetric_key(password, salt)

            # encrypt data with encryption key
            data = encrypt(data, symmetric_key=encryption_key)

            encrypted_key = None

        elif vault_type == u'asymmetric':

            public_key = vault['ipavaultpublickey'][0]

            # generate encryption key
            encryption_key = base64.b64encode(os.urandom(32))

            # encrypt data with encryption key
            data = encrypt(data, symmetric_key=encryption_key)

            # encrypt encryption key with public key
            encrypted_key = encrypt(encryption_key, public_key=public_key)

        else:
            raise errors.ValidationError(name='vault_type',
                                         error=_('Invalid vault type'))

        vault_data = {'data': base64.b64encode(data).decode('utf-8')}
        if encrypted_key:
            vault_data[u'encrypted_key'] = base64.b64encode(encrypted_key)\
                .decode('utf-8')

        json_vault_data = json.dumps(vault_data).encode('utf-8')

        # get config
        transport_cert, wrapping_algo = self._get_vaultconfig()
        # let options override wrapping algo
        # For backwards compatibility do not send old legacy wrapping algo
        # to server. Only send the option when non-3DES is used.
        wrapping_algo = options.pop('wrapping_algo', wrapping_algo)
        if wrapping_algo != constants.VAULT_WRAPPING_3DES:
            options['wrapping_algo'] = wrapping_algo

        # generate session key
        algo = self._generate_session_key(wrapping_algo)
        # wrap vault data
        nonce, wrapped_vault_data = self._wrap_data(algo, json_vault_data)
        options.update(nonce=nonce, vault_data=wrapped_vault_data)
        return self.internal(algo, transport_cert, *args, **options)
Пример #5
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']
    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',
            },
            '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',
            },
            '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,
        ),
    )

    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)
Пример #6
0
class caacl(LDAPObject):
    """
    CA ACL object.
    """
    container_dn = api.env.container_caacl
    object_name = _('CA ACL')
    object_name_plural = _('CA ACLs')
    object_class = ['ipaassociation', 'ipacaacl']
    permission_filter_objectclasses = ['ipacaacl']
    default_attributes = [
        'cn',
        'description',
        'ipaenabledflag',
        'ipacacategory',
        'ipamemberca',
        'ipacertprofilecategory',
        'ipamembercertprofile',
        'usercategory',
        'memberuser',
        'hostcategory',
        'memberhost',
        'servicecategory',
        'memberservice',
    ]
    uuid_attribute = 'ipauniqueid'
    rdn_attribute = 'ipauniqueid'
    attribute_members = {
        'memberuser': ['user', 'group'],
        'memberhost': ['host', 'hostgroup'],
        'memberservice': ['service'],
        'ipamembercertprofile': ['certprofile'],
    }
    managed_permissions = {
        'System: Read CA ACLs': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'description',
                'ipaenabledflag',
                'ipacacategory',
                'ipamemberca',
                'ipacertprofilecategory',
                'ipamembercertprofile',
                'usercategory',
                'memberuser',
                'hostcategory',
                'memberhost',
                'servicecategory',
                'memberservice',
                'ipauniqueid',
                'objectclass',
                'member',
            },
        },
        'System: Add CA ACL': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Add CA ACL";allow (add) groupdn = "ldap:///cn=Add CA ACL,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'CA Administrator'},
        },
        'System: Delete CA ACL': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Delete CA ACL";allow (delete) groupdn = "ldap:///cn=Delete CA ACL,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'CA Administrator'},
        },
        'System: Manage CA ACL Membership': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'ipacacategory', 'ipamemberca', 'ipacertprofilecategory',
                'ipamembercertprofile', 'usercategory', 'memberuser',
                'hostcategory', 'memberhost', 'servicecategory',
                'memberservice'
            },
            'replaces': [
                '(targetattr = "ipamemberca || ipamembercertprofile || memberuser || memberservice || memberhost || ipacacategory || ipacertprofilecategory || usercategory || hostcategory || servicecategory")(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Manage CA ACL membership";allow (write) groupdn = "ldap:///cn=Manage CA ACL membership,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'CA Administrator'},
        },
        'System: Modify CA ACL': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'cn',
                'description',
                'ipaenabledflag',
            },
            'replaces': [
                '(targetattr = "cn || description || ipaenabledflag")(target = "ldap:///ipauniqueid=*,cn=caacls,cn=ca,$SUFFIX")(version 3.0;acl "permission:Modify CA ACL";allow (write) groupdn = "ldap:///cn=Modify CA ACL,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'CA Administrator'},
        },
    }

    label = _('CA ACLs')
    label_singular = _('CA ACL')

    takes_params = (
        Str(
            'cn',
            cli_name='name',
            label=_('ACL name'),
            primary_key=True,
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
        ),
        Bool(
            'ipaenabledflag?',
            label=_('Enabled'),
            flags=['no_option'],
        ),
        # Commented until subca plugin arrives
        #StrEnum('ipacacategory?',
        #    cli_name='cacat',
        #    label=_('CA category'),
        #    doc=_('CA category the ACL applies to'),
        #    values=(u'all', ),
        #),
        StrEnum(
            'ipacertprofilecategory?',
            cli_name='profilecat',
            label=_('Profile category'),
            doc=_('Profile category the ACL applies to'),
            values=(u'all', ),
        ),
        StrEnum(
            'usercategory?',
            cli_name='usercat',
            label=_('User category'),
            doc=_('User category the ACL applies to'),
            values=(u'all', ),
        ),
        StrEnum(
            'hostcategory?',
            cli_name='hostcat',
            label=_('Host category'),
            doc=_('Host category the ACL applies to'),
            values=(u'all', ),
        ),
        StrEnum(
            'servicecategory?',
            cli_name='servicecat',
            label=_('Service category'),
            doc=_('Service category the ACL applies to'),
            values=(u'all', ),
        ),
        # Commented until subca plugin arrives
        #Str('ipamemberca_subca?',
        #    label=_('CAs'),
        #    flags=['no_create', 'no_update', 'no_search'],
        #),
        Str(
            'ipamembercertprofile_certprofile?',
            label=_('Profiles'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberuser_user?',
            label=_('Users'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberuser_group?',
            label=_('User Groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberhost_host?',
            label=_('Hosts'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberhost_hostgroup?',
            label=_('Host Groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str(
            'memberservice_service?',
            label=_('Services'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
    )
Пример #7
0
class vault_add(Local):
    __doc__ = _('Create a new vault.')

    takes_options = (
        Str(
            'password?',
            cli_name='password',
            doc=_('Vault password'),
        ),
        Str(  # TODO: use File parameter
            'password_file?',
            cli_name='password_file',
            doc=_('File containing the vault password'),
        ),
        Str(  # TODO: use File parameter
            'public_key_file?',
            cli_name='public_key_file',
            doc=_('File containing the vault public key'),
        ),
    )

    @classmethod
    def __NO_CLI_getter(cls):  # pylint: disable=unused-private-member, #4756
        return (api.Command.get_plugin('vault_add_internal') is
                _fake_vault_add_internal)

    NO_CLI = classproperty(__NO_CLI_getter)

    @property
    def api_version(self):
        return self.api.Command.vault_add_internal.api_version

    def get_args(self):
        for arg in self.api.Command.vault_add_internal.args():
            yield arg
        for arg in super(vault_add, self).get_args():
            yield arg

    def get_options(self):
        for option in self.api.Command.vault_add_internal.options():
            if option.name not in ('ipavaultsalt', 'version'):
                yield option
        for option in super(vault_add, self).get_options():
            yield option

    def get_output_params(self):
        for param in self.api.Command.vault_add_internal.output_params():
            yield param
        for param in super(vault_add, self).get_output_params():
            yield param

    def _iter_output(self):
        return self.api.Command.vault_add_internal.output()

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

        vault_type = options.get('ipavaulttype')

        if vault_type is None:
            internal_cmd = self.api.Command.vault_add_internal
            vault_type = internal_cmd.params.ipavaulttype.default

        password = options.get('password')
        password_file = options.get('password_file')
        public_key = options.get('ipavaultpublickey')
        public_key_file = options.get('public_key_file')

        # don't send these parameters to server
        if 'password' in options:
            del options['password']
        if 'password_file' in options:
            del options['password_file']
        if 'public_key_file' in options:
            del options['public_key_file']

        if vault_type != u'symmetric' and (password or password_file):
            raise errors.MutuallyExclusiveError(
                reason=_('Password can be specified only for '
                         'symmetric vault'))

        if vault_type != u'asymmetric' and (public_key or public_key_file):
            raise errors.MutuallyExclusiveError(
                reason=_('Public key can be specified only for '
                         'asymmetric vault'))

        if self.api.env.in_server:
            backend = self.api.Backend.ldap2
        else:
            backend = self.api.Backend.rpcclient
        if not backend.isconnected():
            backend.connect()

        if vault_type == u'standard':

            pass

        elif vault_type == u'symmetric':

            # get password
            if password and password_file:
                raise errors.MutuallyExclusiveError(
                    reason=_('Password specified multiple times'))

            elif password:
                pass

            elif password_file:
                password = validated_read('password-file',
                                          password_file,
                                          encoding='utf-8')
                password = password.rstrip('\n')

            else:
                password = self.api.Backend.textui.prompt_password(
                    'New password')

            # generate vault salt
            options['ipavaultsalt'] = os.urandom(16)

        elif vault_type == u'asymmetric':

            # get new vault public key
            if public_key and public_key_file:
                raise errors.MutuallyExclusiveError(
                    reason=_('Public key specified multiple times'))

            elif public_key:
                pass

            elif public_key_file:
                public_key = validated_read('public-key-file',
                                            public_key_file,
                                            mode='rb')

                # store vault public key
                options['ipavaultpublickey'] = public_key

            else:
                raise errors.ValidationError(
                    name='ipavaultpublickey',
                    error=_('Missing vault public key'))

            # validate public key and prevent users from accidentally
            # sending a private key to the server.
            try:
                load_pem_public_key(data=public_key, backend=default_backend())
            except ValueError as e:
                raise errors.ValidationError(
                    name='ipavaultpublickey',
                    error=_('Invalid or unsupported vault public key: %s') % e,
                )

        # create vault
        response = self.api.Command.vault_add_internal(*args, **options)

        # prepare parameters for archival
        opts = options.copy()
        if 'description' in opts:
            del opts['description']
        if 'ipavaulttype' in opts:
            del opts['ipavaulttype']

        if vault_type == u'symmetric':
            opts['password'] = password
            del opts['ipavaultsalt']

        elif vault_type == u'asymmetric':
            del opts['ipavaultpublickey']

        # archive blank data
        self.api.Command.vault_archive(*args, **opts)

        return response
Пример #8
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']
    possible_objectclasses = ['ipadomainidrange', 'ipatrustedaddomainrange']
    default_attributes = [
        'cn', 'ipabaseid', 'ipaidrangesize', 'ipabaserid',
        'ipasecondarybaserid', 'ipanttrusteddomainsid', 'iparangetype'
    ]

    label = _('ID Ranges')
    label_singular = _('ID 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',
                        label=_('Domain SID of the trusted domain'),
                    ),
                    Str(
                        'iparangetype?',
                        label=_('Range type'),
                        flags=['no_option'],
                    ))

    def handle_iparangetype(self,
                            entry_attrs,
                            options,
                            keep_objectclass=False):
        if not options.get('pkey_only', False):
            if 'ipatrustedaddomainrange' in entry_attrs.get('objectclass', []):
                entry_attrs['iparangetype'] = [
                    unicode(_('Active Directory domain range'))
                ]
            else:
                entry_attrs['iparangetype'] = [
                    unicode(_(u'local domain range'))
                ]
        if not keep_objectclass:
            if not options.get('all', False) or options.get(
                    'pkey_only', False):
                entry_attrs.pop('objectclass', 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:
            (objects, truncated) = 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 validate_trusted_domain_sid(self, sid):
        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'
            ))
        if not domain_validator.is_trusted_sid_valid(sid):
            raise errors.ValidationError(
                name='domain SID',
                error=_(
                    'SID is not recognized as a valid SID for a trusted domain'
                ))
Пример #9
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=(
                r'^(([a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?'
                r'(;q\=((0(\.[0-9]{0,3})?)|(1(\.0{0,3})?)))?'
                r'(\s*,\s*[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?'
                r'(;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"',
        ),
        Certificate('usercertificate*',
            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, str):
                    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
Пример #10
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
Пример #11
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'),
        ),
    )
Пример #12
0
class automember_rebuild(Method):
    __doc__ = _('Rebuild auto membership.')

    obj_name = 'automember_task'
    attr_name = 'rebuild'

    # TODO: Add a --dry-run option:
    # https://fedorahosted.org/freeipa/ticket/3936
    takes_options = (
        group_type[0].clone(
            required=False,
            label=_('Rebuild membership for all members of a grouping')),
        Str(
            'users*',
            label=_('Users'),
            doc=_('Rebuild membership for specified users'),
        ),
        Str(
            'hosts*',
            label=_('Hosts'),
            doc=_('Rebuild membership for specified hosts'),
        ),
        Flag(
            'no_wait?',
            default=False,
            label=_('No wait'),
            doc=_("Don't wait for rebuilding membership"),
        ),
    )
    has_output = output.standard_entry

    def validate(self, **kw):
        """
        Validation rules:
        - at least one of 'type', 'users', 'hosts' is required
        - 'users' and 'hosts' cannot be combined together
        - if 'users' and 'type' are specified, 'type' must be 'group'
        - if 'hosts' and 'type' are specified, 'type' must be 'hostgroup'
        """
        super(automember_rebuild, self).validate(**kw)
        users, hosts, gtype = kw.get('users'), kw.get('hosts'), kw.get('type')

        if not (gtype or users or hosts):
            raise errors.MutuallyExclusiveError(
                reason=_('at least one of options: type, users, hosts must be '
                         'specified'))

        if users and hosts:
            raise errors.MutuallyExclusiveError(
                reason=_("users and hosts cannot both be set"))
        if gtype == 'group' and hosts:
            raise errors.MutuallyExclusiveError(
                reason=_("hosts cannot be set when type is 'group'"))
        if gtype == 'hostgroup' and users:
            raise errors.MutuallyExclusiveError(
                reason=_("users cannot be set when type is 'hostgroup'"))

    def execute(self, *keys, **options):
        ldap = self.api.Backend.ldap2
        cn = str(uuid.uuid4())

        gtype = options.get('type')
        if not gtype:
            gtype = 'group' if options.get('users') else 'hostgroup'

        types = {
            'group':
            ('user', 'users', DN(api.env.container_user, api.env.basedn)),
            'hostgroup':
            ('host', 'hosts', DN(api.env.container_host, api.env.basedn)),
        }

        obj_name, opt_name, basedn = types[gtype]
        obj = self.api.Object[obj_name]

        names = options.get(opt_name)
        if names:
            for name in names:
                try:
                    obj.get_dn_if_exists(name)
                except errors.NotFound:
                    raise obj.handle_not_found(name)
            search_filter = ldap.make_filter_from_attr(obj.primary_key.name,
                                                       names,
                                                       rules=ldap.MATCH_ANY)
        else:
            search_filter = '(%s=*)' % obj.primary_key.name

        task_dn = DN(('cn', cn), REBUILD_TASK_CONTAINER)

        entry = ldap.make_entry(task_dn,
                                objectclass=['top', 'extensibleObject'],
                                cn=[cn],
                                basedn=[basedn],
                                filter=[search_filter],
                                scope=['sub'],
                                ttl=[3600])
        ldap.add_entry(entry)

        summary = _('Automember rebuild membership task started')
        result = {'dn': task_dn}

        if not options.get('no_wait'):
            summary = _('Automember rebuild membership task completed')
            result = {}
            start_time = time.time()

            while True:
                try:
                    task = ldap.get_entry(task_dn)
                except errors.NotFound:
                    break

                if 'nstaskexitcode' in task:
                    if str(task.single_value['nstaskexitcode']) == '0':
                        summary = task.single_value['nstaskstatus']
                        break
                    raise errors.DatabaseError(
                        desc=task.single_value['nstaskstatus'],
                        info=_("Task DN = '%s'" % task_dn))
                time.sleep(1)
                if time.time() > (start_time + 60):
                    raise errors.TaskTimeout(task=_('Automember'),
                                             task_dn=task_dn)

        return dict(result=result,
                    summary=unicode(summary),
                    value=pkey_to_value(None, options))
Пример #13
0
class automember_add_condition(LDAPUpdate):
    __doc__ = _("""
    Add conditions to an automember rule.
    """)
    has_output_params = (Str(
        'failed',
        label=_('Failed to add'),
        flags=['suppress_empty'],
    ), )

    takes_options = regex_attrs + regex_key + group_type
    msg_summary = _('Added condition(s) to "%(value)s"')

    # Prepare the output to expect failed results
    has_output = (
        output.summary,
        output.Entry('result'),
        output.value,
        output.Output(
            'failed',
            type=dict,
            doc=_('Conditions that could not be added'),
        ),
        output.Output(
            'completed',
            type=int,
            doc=_('Number of conditions added'),
        ),
    )

    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
                     **options):
        assert isinstance(dn, DN)
        # Check to see if the automember rule exists
        try:
            dn = ldap.get_entry(dn, []).dn
        except errors.NotFound:
            raise errors.NotFound(
                reason=_(u'Auto member rule: %s not found!') % keys[0])
        # Define container key
        key = options['key']
        # Check to see if the attribute is valid
        self.obj.check_attr(key)

        key = '%s=' % key
        completed = 0
        failed = {'failed': {}}

        for attr in (INCLUDE_RE, EXCLUDE_RE):
            failed['failed'][attr] = []
            if attr in options and options[attr]:
                entry_attrs[attr] = [
                    key + condition for condition in options[attr]
                ]
                completed += len(entry_attrs[attr])
                try:
                    old_entry = ldap.get_entry(dn, [attr])
                    for regex in old_entry.keys():
                        if not isinstance(entry_attrs[regex], (list, tuple)):
                            entry_attrs[regex] = [entry_attrs[regex]]
                        duplicate = set(old_entry[regex]) & set(
                            entry_attrs[regex])
                        if len(duplicate) > 0:
                            completed -= 1
                        else:
                            entry_attrs[regex] = list(
                                entry_attrs[regex]) + old_entry[regex]
                except errors.NotFound:
                    failed['failed'][attr].append(regex)

        entry_attrs = entry_to_dict(entry_attrs, **options)

        # Set failed and completed to they can be harvested in the execute super
        setattr(context, 'failed', failed)
        setattr(context, 'completed', completed)
        setattr(context, 'entry_attrs', entry_attrs)

        # Make sure to returned the failed results if there is nothing to remove
        if completed == 0:
            ldap.get_entry(dn, attrs_list)
            raise errors.EmptyModlist
        return dn

    def execute(self, *keys, **options):
        __doc__ = _("""
        Override this so we can add completed and failed to the return result.
        """)
        try:
            result = super(automember_add_condition,
                           self).execute(*keys, **options)
        except errors.EmptyModlist:
            result = {
                'result': getattr(context, 'entry_attrs'),
                'value': keys[-1]
            }
        result['failed'] = getattr(context, 'failed')
        result['completed'] = getattr(context, 'completed')
        result['value'] = pkey_to_value(keys[-1], options)
        return result
Пример #14
0
class automember(LDAPObject):
    """
    Bring automember to a hostgroup with an Auto Membership Rule.
    """

    container_dn = api.env.container_automember

    object_name = 'Automember rule'
    object_name_plural = 'Automember rules'
    object_class = ['top', 'automemberregexrule']
    permission_filter_objectclasses = ['automemberregexrule']
    default_attributes = [
        'automemberinclusiveregex', 'automemberexclusiveregex', 'cn',
        'automembertargetgroup', 'description', 'automemberdefaultgroup'
    ]
    managed_permissions = {
        'System: Read Automember Definitions': {
            'non_object': True,
            'ipapermlocation': DN(container_dn, api.env.basedn),
            'ipapermtargetfilter': {'(objectclass=automemberdefinition)'},
            'replaces_global_anonymous_aci': True,
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'cn',
                'automemberscope',
                'automemberfilter',
                'automembergroupingattr',
                'automemberdefaultgroup',
                'automemberdisabled',
            },
            'default_privileges':
            {'Automember Readers', 'Automember Task Administrator'},
        },
        'System: Read Automember Rules': {
            'replaces_global_anonymous_aci': True,
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'cn',
                'objectclass',
                'automembertargetgroup',
                'description',
                'automemberexclusiveregex',
                'automemberinclusiveregex',
            },
            'default_privileges':
            {'Automember Readers', 'Automember Task Administrator'},
        },
        'System: Read Automember Tasks': {
            'non_object': True,
            'ipapermlocation': DN('cn=tasks', 'cn=config'),
            'ipapermtarget': DN('cn=*', REBUILD_TASK_CONTAINER),
            'replaces_global_anonymous_aci': True,
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {'*'},
            'default_privileges': {'Automember Task Administrator'},
        },
    }

    label = _('Auto Membership Rule')

    takes_params = (
        Str(
            'cn',
            cli_name='automember_rule',
            label=_('Automember Rule'),
            doc=_('Automember Rule'),
            primary_key=True,
            normalizer=lambda value: value.lower(),
            flags={'no_search'},
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('A description of this auto member rule'),
        ),
        Str('automemberdefaultgroup?',
            cli_name='default_group',
            label=_('Default (fallback) Group'),
            doc=_('Default group for entries to land'),
            flags=['no_create', 'no_update', 'no_search']),
    ) + regex_attrs

    def dn_exists(self, otype, oname):
        ldap = self.api.Backend.ldap2
        dn = self.api.Object[otype].get_dn(oname)
        try:
            entry = ldap.get_entry(dn, [])
        except errors.NotFound:
            raise errors.NotFound(
                reason=_(u'%(otype)s "%(oname)s" not found') %
                dict(otype=otype, oname=oname))
        return entry.dn

    def get_dn(self, *keys, **options):
        if self.parent_object:
            parent_dn = self.api.Object[self.parent_object].get_dn(*keys[:-1])
        else:
            parent_dn = DN(self.container_dn, api.env.basedn)
        grouptype = options['type']
        try:
            ndn = DN(('cn', keys[-1]), ('cn', grouptype), parent_dn)
        except IndexError:
            ndn = DN(('cn', grouptype), parent_dn)
        return ndn

    def check_attr(self, attr):
        """
        Verify that the user supplied key is a valid attribute in the schema
        """
        ldap = self.api.Backend.ldap2
        obj = ldap.schema.get_obj(_ldap.schema.AttributeType, attr)
        if obj is not None:
            return obj
        else:
            raise errors.NotFound(reason=_('%s is not a valid attribute.') %
                                  attr)
Пример #15
0
class hbacrule(LDAPObject):
    """
    HBAC object.
    """
    container_dn = api.env.container_hbac
    object_name = _('HBAC rule')
    object_name_plural = _('HBAC rules')
    object_class = ['ipaassociation', 'ipahbacrule']
    permission_filter_objectclasses = ['ipahbacrule']
    default_attributes = [
        'cn', 'ipaenabledflag',
        'description', 'usercategory', 'hostcategory',
        'servicecategory', 'ipaenabledflag',
        'memberuser', 'sourcehost', 'memberhost', 'memberservice',
        'externalhost',
    ]
    uuid_attribute = 'ipauniqueid'
    rdn_attribute = 'ipauniqueid'
    attribute_members = {
        'memberuser': ['user', 'group'],
        'memberhost': ['host', 'hostgroup'],
        'sourcehost': ['host', 'hostgroup'],
        'memberservice': ['hbacsvc', 'hbacsvcgroup'],
    }
    managed_permissions = {
        'System: Read HBAC Rules': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'accessruletype', 'accesstime', 'cn', 'description',
                'externalhost', 'hostcategory', 'ipaenabledflag',
                'ipauniqueid', 'memberhost', 'memberservice', 'memberuser',
                'servicecategory', 'sourcehost', 'sourcehostcategory',
                'usercategory', 'objectclass', 'member',
            },
        },
        'System: Add HBAC Rule': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Add HBAC rule";allow (add) groupdn = "ldap:///cn=Add HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'HBAC Administrator'},
        },
        'System: Delete HBAC Rule': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Delete HBAC rule";allow (delete) groupdn = "ldap:///cn=Delete HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'HBAC Administrator'},
        },
        'System: Manage HBAC Rule Membership': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'externalhost', 'memberhost', 'memberservice', 'memberuser'
            },
            'replaces': [
                '(targetattr = "memberuser || externalhost || memberservice || memberhost")(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Manage HBAC rule membership";allow (write) groupdn = "ldap:///cn=Manage HBAC rule membership,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'HBAC Administrator'},
        },
        'System: Modify HBAC Rule': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'accessruletype', 'accesstime', 'cn', 'description',
                'hostcategory', 'ipaenabledflag', 'servicecategory',
                'sourcehost', 'sourcehostcategory', 'usercategory'
            },
            'replaces': [
                '(targetattr = "servicecategory || sourcehostcategory || cn || description || ipaenabledflag || accesstime || usercategory || hostcategory || accessruletype || sourcehost")(target = "ldap:///ipauniqueid=*,cn=hbac,$SUFFIX")(version 3.0;acl "permission:Modify HBAC rule";allow (write) groupdn = "ldap:///cn=Modify HBAC rule,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'HBAC Administrator'},
        },
    }

    label = _('HBAC Rules')
    label_singular = _('HBAC Rule')

    takes_params = (
        Str('cn',
            cli_name='name',
            label=_('Rule name'),
            primary_key=True,
        ),
        StrEnum('accessruletype', validate_type,
            cli_name='type',
            doc=_('Rule type (allow)'),
            label=_('Rule type'),
            values=(u'allow', u'deny'),
            default=u'allow',
            autofill=True,
            exclude='webui',
            flags=['no_option', 'no_output'],
        ),
        # FIXME: {user,host,service}categories should expand in the future
        StrEnum('usercategory?',
            cli_name='usercat',
            label=_('User category'),
            doc=_('User category the rule applies to'),
            values=(u'all', ),
        ),
        StrEnum('hostcategory?',
            cli_name='hostcat',
            label=_('Host category'),
            doc=_('Host category the rule applies to'),
            values=(u'all', ),
        ),
        StrEnum('sourcehostcategory?',
            deprecated=True,
            cli_name='srchostcat',
            label=_('Source host category'),
            doc=_('Source host category the rule applies to'),
            values=(u'all', ),
            flags={'no_option'},
        ),
        StrEnum('servicecategory?',
            cli_name='servicecat',
            label=_('Service category'),
            doc=_('Service category the rule applies to'),
            values=(u'all', ),
        ),
#        AccessTime('accesstime?',
#            cli_name='time',
#            label=_('Access time'),
#        ),
        Str('description?',
            cli_name='desc',
            label=_('Description'),
        ),
        Bool('ipaenabledflag?',
             label=_('Enabled'),
             flags=['no_option'],
        ),
        Str('memberuser_user?',
            label=_('Users'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str('memberuser_group?',
            label=_('User Groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str('memberhost_host?',
            label=_('Hosts'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str('memberhost_hostgroup?',
            label=_('Host Groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str('sourcehost_host?',
            deprecated=True,
            label=_('Source Hosts'),
            flags=['no_create', 'no_update', 'no_search', 'no_option'],
        ),
        Str('sourcehost_hostgroup?',
            deprecated=True,
            label=_('Source Host Groups'),
            flags=['no_create', 'no_update', 'no_search', 'no_option'],
        ),
        Str('memberservice_hbacsvc?',
            label=_('Services'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        Str('memberservice_hbacsvcgroup?',
            label=_('Service Groups'),
            flags=['no_create', 'no_update', 'no_search'],
        ),
        external_host_param,
    )
Пример #16
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',
    ]
    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'},
        ),
    )

    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',
                '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'},
        },
    }
Пример #17
0
            raise errors.MutuallyExclusiveError(reason=_(
                "services cannot be added when service category='all'"))
        return dn


@register()
class caacl_remove_service(LDAPRemoveMember):
    __doc__ = _('Remove services from a CA ACL.')

    member_attributes = ['memberservice']
    member_count_out = (_('%i service removed.'), _('%i services removed.'))


caacl_output_params = global_output_params + (
    Str(
        'ipamembercertprofile',
        label=_('Failed profiles'),
    ),
    # Commented until caacl plugin arrives
    #Str('ipamemberca',
    #    label=_('Failed CAs'),
    #),
)


@register()
class caacl_add_profile(LDAPAddMember):
    __doc__ = _('Add profiles to a CA ACL.')

    has_output_params = caacl_output_params

    member_attributes = ['ipamembercertprofile']
Пример #18
0
 Generate and retrieve a keytab for an IPA service:
   ipa-getkeytab -s ipa.example.com -p HTTP/web.example.com -k /etc/httpd/httpd.keytab

""")

logger = logging.getLogger(__name__)

register = Registry()

output_params = (
    Flag(
        'has_keytab',
        label=_('Keytab'),
    ),
    Str(
        'managedby_host',
        label='Managed by',
    ),
    Str(
        'ipaallowedtoperform_read_keys_user',
        label=_('Users allowed to retrieve keytab'),
    ),
    Str(
        'ipaallowedtoperform_read_keys_group',
        label=_('Groups allowed to retrieve keytab'),
    ),
    Str(
        'ipaallowedtoperform_read_keys_host',
        label=_('Hosts allowed to retrieve keytab'),
    ),
    Str(
        'ipaallowedtoperform_read_keys_hostgroup',
Пример #19
0
class migrate_ds(Command):
    __doc__ = _('Migrate users and groups from DS to IPA.')

    migrate_objects = {
        # OBJECT_NAME: (search_filter, pre_callback, post_callback)
        #
        # OBJECT_NAME - is the name of an LDAPObject subclass
        # search_filter - is the filter to retrieve objects from DS
        # pre_callback - is called for each object just after it was
        #                retrieved from DS and before being added to IPA
        # post_callback - is called for each object after it was added to IPA
        # exc_callback - is called when adding entry to IPA raises an exception
        #
        # {pre, post}_callback parameters:
        #  ldap - ldap2 instance connected to IPA
        #  pkey - primary key value of the object (uid for users, etc.)
        #  dn - dn of the object as it (will be/is) stored in IPA
        #  entry_attrs - attributes of the object
        #  failed - a list of so-far failed objects
        #  config - IPA config entry attributes
        #  ctx - object context, used to pass data between callbacks
        #
        # If pre_callback return value evaluates to False, migration
        # of the current object is aborted.
        'user': {
            'filter_template': '(&(|%s)(uid=*))',
            'oc_option': 'userobjectclass',
            'oc_blocklist_option': 'userignoreobjectclass',
            'attr_blocklist_option': 'userignoreattribute',
            'pre_callback': _pre_migrate_user,
            'post_callback': _post_migrate_user,
            'exc_callback': None
        },
        'group': {
            'filter_template': '(&(|%s)(cn=*))',
            'oc_option': 'groupobjectclass',
            'oc_blocklist_option': 'groupignoreobjectclass',
            'attr_blocklist_option': 'groupignoreattribute',
            'pre_callback': _pre_migrate_group,
            'post_callback': None,
            'exc_callback': _group_exc_callback,
        },
    }
    migrate_order = ('user', 'group')

    takes_args = (
        Str(
            'ldapuri',
            validate_ldapuri,
            cli_name='ldap_uri',
            label=_('LDAP URI'),
            doc=_('LDAP URI of DS server to migrate from'),
        ),
        Password(
            'bindpw',
            cli_name='password',
            label=_('Password'),
            confirm=False,
            doc=_('bind password'),
        ),
    )

    takes_options = (
        DNParam('binddn?',
            cli_name='bind_dn',
            label=_('Bind DN'),
            default=DN(('cn', 'directory manager')),
            autofill=True,
        ),
        DNParam('usercontainer',
            cli_name='user_container',
            label=_('User container'),
            doc=_('DN of container for users in DS relative to base DN'),
            default=DN(('ou', 'people')),
            autofill=True,
        ),
        DNParam('groupcontainer',
            cli_name='group_container',
            label=_('Group container'),
            doc=_('DN of container for groups in DS relative to base DN'),
            default=DN(('ou', 'groups')),
            autofill=True,
        ),
        Str('userobjectclass+',
            cli_name='user_objectclass',
            label=_('User object class'),
            doc=_('Objectclasses used to search for user entries in DS'),
            default=(u'person',),
            autofill=True,
        ),
        Str('groupobjectclass+',
            cli_name='group_objectclass',
            label=_('Group object class'),
            doc=_('Objectclasses used to search for group entries in DS'),
            default=(u'groupOfUniqueNames', u'groupOfNames'),
            autofill=True,
        ),
        Str('userignoreobjectclass*',
            cli_name='user_ignore_objectclass',
            label=_('Ignore user object class'),
            doc=_('Objectclasses to be ignored for user entries in DS'),
            default=tuple(),
            autofill=True,
        ),
        Str('userignoreattribute*',
            cli_name='user_ignore_attribute',
            label=_('Ignore user attribute'),
            doc=_('Attributes to be ignored for user entries in DS'),
            default=tuple(),
            autofill=True,
        ),
        Str('groupignoreobjectclass*',
            cli_name='group_ignore_objectclass',
            label=_('Ignore group object class'),
            doc=_('Objectclasses to be ignored for group entries in DS'),
            default=tuple(),
            autofill=True,
        ),
        Str('groupignoreattribute*',
            cli_name='group_ignore_attribute',
            label=_('Ignore group attribute'),
            doc=_('Attributes to be ignored for group entries in DS'),
            default=tuple(),
            autofill=True,
        ),
        Flag('groupoverwritegid',
            cli_name='group_overwrite_gid',
            label=_('Overwrite GID'),
            doc=_('When migrating a group already existing in IPA domain overwrite the '\
                  'group GID and report as success'),
        ),
        StrEnum('schema?',
            cli_name='schema',
            label=_('LDAP schema'),
            doc=_('The schema used on the LDAP server. Supported values are RFC2307 and RFC2307bis. The default is RFC2307bis'),
            values=_supported_schemas,
            default=_supported_schemas[0],
            autofill=True,
        ),
        Flag('continue?',
            label=_('Continue'),
            doc=_('Continuous operation mode. Errors are reported but the process continues'),
            default=False,
        ),
        DNParam('basedn?',
            cli_name='base_dn',
            label=_('Base DN'),
            doc=_('Base DN on remote LDAP server'),
        ),
        Flag('compat?',
            cli_name='with_compat',
            label=_('Ignore compat plugin'),
            doc=_('Allows migration despite the usage of compat plugin'),
            default=False,
        ),
        Str('cacertfile?',
            cli_name='ca_cert_file',
            label=_('CA certificate'),
            doc=_('Load CA certificate of LDAP server from FILE'),
            default=None,
            noextrawhitespace=False,
            ),
        Bool('use_def_group?',
             cli_name='use_default_group',
             label=_('Add to default group'),
             doc=_('Add migrated users without a group to a default group '
                   '(default: true)'),
             default=True,
             autofill=True,
             ),
        StrEnum('scope',
                cli_name='scope',
                label=_('Search scope'),
                doc=_('LDAP search scope for users and groups: base, '
                      'onelevel, or subtree. Defaults to onelevel'),
                values=sorted(_supported_scopes),
                default=_default_scope,
                autofill=True,
                ),
    )

    has_output = (
        output.Output(
            'result',
            type=dict,
            doc=_('Lists of objects migrated; categorized by type.'),
        ),
        output.Output(
            'failed',
            type=dict,
            doc=
            _('Lists of objects that could not be migrated; categorized by type.'
              ),
        ),
        output.Output(
            'enabled',
            type=bool,
            doc=_('False if migration mode was disabled.'),
        ),
        output.Output(
            'compat',
            type=bool,
            doc=
            _('False if migration fails because the compatibility plug-in is enabled.'
              ),
        ),
    )

    exclude_doc = _('%s to exclude from migration')

    truncated_err_msg = _('''\
search results for objects to be migrated
have been truncated by the server;
migration process might be incomplete\n''')

    def get_options(self):
        """
        Call get_options of the baseclass and add "exclude" options
        for each type of object being migrated.
        """
        for option in super(migrate_ds, self).get_options():
            yield option
        for ldap_obj_name in self.migrate_objects:
            ldap_obj = self.api.Object[ldap_obj_name]
            name = 'exclude_%ss' % to_cli(ldap_obj_name)
            doc = self.exclude_doc % ldap_obj.object_name_plural
            yield Str('%s*' % name,
                      cli_name=name,
                      doc=doc,
                      default=tuple(),
                      autofill=True)

    def normalize_options(self, options):
        """
        Convert all "exclude" option values to lower-case.

        Also, empty List parameters are converted to None, but the migration
        plugin doesn't like that - convert back to empty lists.
        """
        names = [
            'userobjectclass', 'groupobjectclass', 'userignoreobjectclass',
            'userignoreattribute', 'groupignoreobjectclass',
            'groupignoreattribute'
        ]
        names.extend('exclude_%ss' % to_cli(n) for n in self.migrate_objects)
        for name in names:
            if options[name]:
                options[name] = tuple(v.lower() for v in options[name])
            else:
                options[name] = tuple()

    def _get_search_bases(self, options, ds_base_dn, migrate_order):
        search_bases = dict()
        for ldap_obj_name in migrate_order:
            container = options.get('%scontainer' % to_cli(ldap_obj_name))
            if container:
                # Don't append base dn if user already appended it in the container dn
                if container.endswith(ds_base_dn):
                    search_base = container
                else:
                    search_base = DN(container, ds_base_dn)
            else:
                search_base = ds_base_dn
            search_bases[ldap_obj_name] = search_base
        return search_bases

    def migrate(self, ldap, config, ds_ldap, ds_base_dn, options):
        """
        Migrate objects from DS to LDAP.
        """
        assert isinstance(ds_base_dn, DN)
        migrated = {}  # {'OBJ': ['PKEY1', 'PKEY2', ...], ...}
        failed = {}  # {'OBJ': {'PKEY1': 'Failed 'cos blabla', ...}, ...}
        search_bases = self._get_search_bases(options, ds_base_dn,
                                              self.migrate_order)
        migration_start = datetime.datetime.now()

        scope = _supported_scopes[options.get('scope')]

        for ldap_obj_name in self.migrate_order:
            ldap_obj = self.api.Object[ldap_obj_name]

            template = self.migrate_objects[ldap_obj_name]['filter_template']
            oc_list = options[to_cli(
                self.migrate_objects[ldap_obj_name]['oc_option'])]
            search_filter = construct_filter(template, oc_list)

            exclude = options['exclude_%ss' % to_cli(ldap_obj_name)]
            context = dict(ds_ldap=ds_ldap)

            migrated[ldap_obj_name] = []
            failed[ldap_obj_name] = {}

            try:
                entries, truncated = ds_ldap.find_entries(
                    search_filter, ['*'],
                    search_bases[ldap_obj_name],
                    scope,
                    time_limit=0,
                    size_limit=-1)
            except errors.NotFound:
                if not options.get('continue', False):
                    raise errors.NotFound(
                        reason=
                        _('%(container)s LDAP search did not return any result '
                          '(search base: %(search_base)s, '
                          'objectclass: %(objectclass)s)') % {
                              'container': ldap_obj_name,
                              'search_base': search_bases[ldap_obj_name],
                              'objectclass': ', '.join(oc_list)
                          })
                else:
                    truncated = False
                    entries = []
            if truncated:
                logger.error('%s: %s', ldap_obj.name, self.truncated_err_msg)

            blocklists = {}
            for blocklist in ('oc_blocklist', 'attr_blocklist'):
                blocklist_option = (
                    self.migrate_objects[ldap_obj_name][blocklist + '_option'])
                if blocklist_option is not None:
                    blocklists[blocklist] = options.get(
                        blocklist_option, tuple())
                else:
                    blocklists[blocklist] = tuple()

            # get default primary group for new users
            if 'def_group_dn' not in context and options.get('use_def_group'):
                def_group = config.get('ipadefaultprimarygroup')
                context['def_group_dn'] = api.Object.group.get_dn(def_group)
                try:
                    ldap.get_entry(context['def_group_dn'],
                                   ['gidnumber', 'cn'])
                except errors.NotFound:
                    error_msg = _('Default group for new users not found')
                    raise errors.NotFound(reason=error_msg)

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

            valid_gids = set()
            invalid_gids = set()
            migrate_cnt = 0
            context['migrate_cnt'] = 0
            for entry_attrs in entries:
                context['migrate_cnt'] = migrate_cnt
                s = datetime.datetime.now()

                ava = entry_attrs.dn[0][0]
                if ava.attr == ldap_obj.primary_key.name:
                    # In case if pkey attribute is in the migrated object DN
                    # and the original LDAP is multivalued, make sure that
                    # we pick the correct value (the unique one stored in DN)
                    pkey = ava.value.lower()
                else:
                    pkey = entry_attrs[ldap_obj.primary_key.name][0].lower()

                if pkey in exclude:
                    continue

                entry_attrs.dn = ldap_obj.get_dn(pkey)
                entry_attrs['objectclass'] = list(
                    set(
                        config.get(ldap_obj.object_class_config,
                                   ldap_obj.object_class) +
                        [o.lower() for o in entry_attrs['objectclass']]))
                entry_attrs[ldap_obj.primary_key.name][0] = entry_attrs[
                    ldap_obj.primary_key.name][0].lower()

                callback = self.migrate_objects[ldap_obj_name]['pre_callback']
                if callable(callback):
                    try:
                        entry_attrs.dn = callback(ldap,
                                                  pkey,
                                                  entry_attrs.dn,
                                                  entry_attrs,
                                                  failed[ldap_obj_name],
                                                  config,
                                                  context,
                                                  schema=options['schema'],
                                                  search_bases=search_bases,
                                                  valid_gids=valid_gids,
                                                  invalid_gids=invalid_gids,
                                                  **blocklists)
                        if not entry_attrs.dn:
                            continue
                    except errors.NotFound as e:
                        failed[ldap_obj_name][pkey] = unicode(e.reason)
                        continue

                try:
                    ldap.add_entry(entry_attrs)
                except errors.ExecutionError as e:
                    callback = self.migrate_objects[ldap_obj_name][
                        'exc_callback']
                    if callable(callback):
                        try:
                            callback(ldap, entry_attrs.dn, entry_attrs, e,
                                     options)
                        except errors.ExecutionError as e2:
                            failed[ldap_obj_name][pkey] = unicode(e2)
                            continue
                    else:
                        failed[ldap_obj_name][pkey] = unicode(e)
                        continue

                migrated[ldap_obj_name].append(pkey)

                callback = self.migrate_objects[ldap_obj_name]['post_callback']
                if callable(callback):
                    callback(ldap, pkey, entry_attrs.dn, entry_attrs,
                             failed[ldap_obj_name], config, context)
                e = datetime.datetime.now()
                d = e - s
                total_dur = e - migration_start
                migrate_cnt += 1
                if migrate_cnt > 0 and migrate_cnt % 100 == 0:
                    logger.info("%d %ss migrated. %s elapsed.", migrate_cnt,
                                ldap_obj_name, total_dur)
                logger.debug("%d %ss migrated, duration: %s (total %s)",
                             migrate_cnt, ldap_obj_name, d, total_dur)

        if 'def_group_dn' in context:
            _update_default_group(ldap, context, True)

        return (migrated, failed)

    def execute(self, ldapuri, bindpw, **options):
        ldap = self.api.Backend.ldap2
        self.normalize_options(options)
        config = ldap.get_ipa_config()

        ds_base_dn = options.get('basedn')
        if ds_base_dn is not None:
            assert isinstance(ds_base_dn, DN)

        # check if migration mode is enabled
        if config.get('ipamigrationenabled', ('FALSE', ))[0] == 'FALSE':
            return dict(result={}, failed={}, enabled=False, compat=True)

        # connect to DS
        if options.get('cacertfile') is not None:
            # store CA cert into file
            tmp_ca_cert_f = write_tmp_file(options['cacertfile'])
            cacert = tmp_ca_cert_f.name

            # start TLS connection or STARTTLS
            ds_ldap = LDAPClient(ldapuri, cacert=cacert, start_tls=True)
            ds_ldap.simple_bind(options['binddn'], bindpw)

            tmp_ca_cert_f.close()
        else:
            ds_ldap = LDAPClient(ldapuri)
            ds_ldap.simple_bind(options['binddn'], bindpw, insecure_bind=True)

        # check whether the compat plugin is enabled
        if not options.get('compat'):
            try:
                ldap.get_entry(
                    DN(('cn', 'users'), ('cn', 'compat'), (api.env.basedn)))
                return dict(result={}, failed={}, enabled=True, compat=False)
            except errors.NotFound:
                pass

        if not ds_base_dn:
            # retrieve base DN from remote LDAP server
            entries, _truncated = ds_ldap.find_entries(
                '',
                ['namingcontexts', 'defaultnamingcontext'],
                DN(''),
                ds_ldap.SCOPE_BASE,
                size_limit=-1,
                time_limit=0,
            )
            if 'defaultnamingcontext' in entries[0]:
                ds_base_dn = DN(entries[0]['defaultnamingcontext'][0])
                assert isinstance(ds_base_dn, DN)
            else:
                try:
                    ds_base_dn = DN(entries[0]['namingcontexts'][0])
                    assert isinstance(ds_base_dn, DN)
                except (IndexError, KeyError) as e:
                    raise Exception(str(e))

        # migrate!
        (migrated, failed) = self.migrate(ldap, config, ds_ldap, ds_base_dn,
                                          options)

        return dict(result=migrated, failed=failed, enabled=True, compat=True)
Пример #20
0
class service(LDAPObject):
    """
    Service object.
    """
    container_dn = api.env.container_service
    object_name = _('service')
    object_name_plural = _('services')
    object_class = [
        'krbprincipal', 'krbprincipalaux', 'krbticketpolicyaux', 'ipaobject',
        'ipaservice', 'pkiuser'
    ]
    possible_objectclasses = ['ipakrbprincipal', 'ipaallowedoperations']
    permission_filter_objectclasses = ['ipaservice']
    search_attributes = ['krbprincipalname', 'managedby', 'ipakrbauthzdata']
    default_attributes = [
        'krbprincipalname', 'krbcanonicalname', 'usercertificate', 'managedby',
        'ipakrbauthzdata', 'memberof', 'ipaallowedtoperform',
        'krbprincipalauthind'
    ]
    uuid_attribute = 'ipauniqueid'
    attribute_members = {
        'managedby': ['host'],
        'memberof': ['role'],
        'ipaallowedtoperform_read_keys':
        ['user', 'group', 'host', 'hostgroup'],
        'ipaallowedtoperform_write_keys':
        ['user', 'group', 'host', 'hostgroup'],
    }
    bindable = True
    relationships = {
        'managedby': ('Managed by', 'man_by_', 'not_man_by_'),
        'ipaallowedtoperform_read_keys':
        ('Allow to retrieve keytab by', 'retrieve_keytab_by_',
         'not_retrieve_keytab_by_'),
        'ipaallowedtoperform_write_keys':
        ('Allow to create keytab by', 'write_keytab_by_',
         'not_write_keytab_by'),
    }
    password_attributes = [('krbprincipalkey', 'has_keytab')]
    managed_permissions = {
        'System: Read Services': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'ipauniqueid',
                'managedby',
                'memberof',
                'usercertificate',
                'krbprincipalname',
                'krbcanonicalname',
                'krbprincipalaliases',
                'krbprincipalexpiration',
                'krbpasswordexpiration',
                'krblastpwdchange',
                'ipakrbauthzdata',
                'ipakrbprincipalalias',
                'krbobjectreferences',
                'krbprincipalauthind',
            },
        },
        'System: Add Services': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Services";allow (add) groupdn = "ldap:///cn=Add Services,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Service Administrators'},
        },
        'System: Manage Service Keytab': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'krblastpwdchange', 'krbprincipalkey'},
            'replaces': [
                '(targetattr = "krbprincipalkey || krblastpwdchange")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Manage service keytab";allow (write) groupdn = "ldap:///cn=Manage service keytab,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges':
            {'Service Administrators', 'Host Administrators'},
        },
        'System: Manage Service Keytab Permissions': {
            'ipapermright': {'read', 'search', 'compare', 'write'},
            'ipapermdefaultattr': {
                'ipaallowedtoperform;write_keys',
                'ipaallowedtoperform;read_keys', 'objectclass'
            },
            'default_privileges':
            {'Service Administrators', 'Host Administrators'},
        },
        'System: Modify Services': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'usercertificate', 'krbprincipalauthind'},
            'replaces': [
                '(targetattr = "usercertificate")(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Services";allow (write) groupdn = "ldap:///cn=Modify Services,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Service Administrators'},
        },
        'System: Manage Service Principals': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'krbprincipalname', 'krbcanonicalname'},
            'default_privileges': {
                'Service Administrators',
            },
        },
        'System: Remove Services': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///krbprincipalname=*,cn=services,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Services";allow (delete) groupdn = "ldap:///cn=Remove Services,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Service Administrators'},
        },
        'System: Read POSIX details of SMB services': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'cn',
                'uid',
                'gecos',
                'gidnumber',
                'homedirectory',
                'loginshell',
                'uidnumber',
                'ipantsecurityidentifier',
            },
        }
    }

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

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

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

        if not new_value:
            return

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

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

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

        key = unicode(normalize_principal(key))

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

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

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

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

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

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

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

        entry_attrs.setdefault('krbcanonicalname',
                               entry_attrs['krbprincipalname'])
Пример #21
0
class vault_mod(Local):
    __doc__ = _('Modify a vault.')

    takes_options = (
        Flag(
            'change_password?',
            doc=_('Change password'),
        ),
        Str(
            'old_password?',
            cli_name='old_password',
            doc=_('Old vault password'),
        ),
        Str(  # TODO: use File parameter
            'old_password_file?',
            cli_name='old_password_file',
            doc=_('File containing the old vault password'),
        ),
        Str(
            'new_password?',
            cli_name='new_password',
            doc=_('New vault password'),
        ),
        Str(  # TODO: use File parameter
            'new_password_file?',
            cli_name='new_password_file',
            doc=_('File containing the new vault password'),
        ),
        Bytes(
            'private_key?',
            cli_name='private_key',
            doc=_('Old vault private key'),
        ),
        Str(  # TODO: use File parameter
            'private_key_file?',
            cli_name='private_key_file',
            doc=_('File containing the old vault private key'),
        ),
        Str(  # TODO: use File parameter
            'public_key_file?',
            cli_name='public_key_file',
            doc=_('File containing the new vault public key'),
        ),
    )

    @classmethod
    def __NO_CLI_getter(cls):  # pylint: disable=unused-private-member, #4756
        return (api.Command.get_plugin('vault_mod_internal') is
                _fake_vault_mod_internal)

    NO_CLI = classproperty(__NO_CLI_getter)

    @property
    def api_version(self):
        return self.api.Command.vault_mod_internal.api_version

    def get_args(self):
        for arg in self.api.Command.vault_mod_internal.args():
            yield arg
        for arg in super(vault_mod, self).get_args():
            yield arg

    def get_options(self):
        for option in self.api.Command.vault_mod_internal.options():
            if option.name != 'version':
                yield option
        for option in super(vault_mod, self).get_options():
            yield option

    def get_output_params(self):
        for param in self.api.Command.vault_mod_internal.output_params():
            yield param
        for param in super(vault_mod, self).get_output_params():
            yield param

    def _iter_output(self):
        return self.api.Command.vault_mod_internal.output()

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

        vault_type = options.pop('ipavaulttype', False)
        salt = options.pop('ipavaultsalt', False)
        change_password = options.pop('change_password', False)

        old_password = options.pop('old_password', None)
        old_password_file = options.pop('old_password_file', None)
        new_password = options.pop('new_password', None)
        new_password_file = options.pop('new_password_file', None)

        old_private_key = options.pop('private_key', None)
        old_private_key_file = options.pop('private_key_file', None)
        new_public_key = options.pop('ipavaultpublickey', None)
        new_public_key_file = options.pop('public_key_file', None)

        if self.api.env.in_server:
            backend = self.api.Backend.ldap2
        else:
            backend = self.api.Backend.rpcclient
        if not backend.isconnected():
            backend.connect()

        # determine the vault type based on parameters specified
        if vault_type:
            pass

        elif change_password or new_password or new_password_file or salt:
            vault_type = u'symmetric'

        elif new_public_key or new_public_key_file:
            vault_type = u'asymmetric'

        # if vault type is specified, retrieve existing secret
        if vault_type:
            opts = options.copy()
            opts.pop('description', None)

            opts['password'] = old_password
            opts['password_file'] = old_password_file
            opts['private_key'] = old_private_key
            opts['private_key_file'] = old_private_key_file

            response = self.api.Command.vault_retrieve(*args, **opts)
            data = response['result']['data']

        opts = options.copy()

        # if vault type is specified, update crypto attributes
        if vault_type:
            opts['ipavaulttype'] = vault_type

            if vault_type == u'standard':
                opts['ipavaultsalt'] = None
                opts['ipavaultpublickey'] = None

            elif vault_type == u'symmetric':
                if salt:
                    opts['ipavaultsalt'] = salt
                else:
                    opts['ipavaultsalt'] = os.urandom(16)

                opts['ipavaultpublickey'] = None

            elif vault_type == u'asymmetric':

                # get new vault public key
                if new_public_key and new_public_key_file:
                    raise errors.MutuallyExclusiveError(
                        reason=_('New public key specified multiple times'))

                elif new_public_key:
                    pass

                elif new_public_key_file:
                    new_public_key = validated_read('public_key_file',
                                                    new_public_key_file,
                                                    mode='rb')

                else:
                    raise errors.ValidationError(
                        name='ipavaultpublickey',
                        error=_('Missing new vault public key'))

                opts['ipavaultsalt'] = None
                opts['ipavaultpublickey'] = new_public_key

        response = self.api.Command.vault_mod_internal(*args, **opts)

        # if vault type is specified, rearchive existing secret
        if vault_type:
            opts = options.copy()
            opts.pop('description', None)

            opts['data'] = data
            opts['password'] = new_password
            opts['password_file'] = new_password_file
            opts['override_password'] = True

            self.api.Command.vault_archive(*args, **opts)

        return response
Пример #22
0
class service_add_smb(LDAPCreate):
    __doc__ = _('Add a new SMB service.')

    msg_summary = _('Added service "%(value)s"')
    member_attributes = ['managedby']
    has_output_params = LDAPCreate.has_output_params + output_params
    smb_takes_args = (
        Str(
            'fqdn',
            util.hostname_validator,
            cli_name='hostname',
            label=_('Host name'),
            primary_key=True,
            normalizer=util.normalize_hostname,
            flags={
                'virtual_attribute', 'no_display', 'no_update', 'no_search'
            },
        ),
        Str(
            'ipantflatname?',
            cli_name='netbiosname',
            label=_('SMB service NetBIOS name'),
            flags={
                'virtual_attribute', 'no_display', 'no_update', 'no_search'
            },
        ),
    )

    takes_options = LDAPCreate.takes_options

    def get_args(self):
        """
        Rewrite arguments to service-add-smb command to make sure we accept
        hostname instead of a principal as we'll be constructing the principal
        ourselves
        """
        for arg in self.smb_takes_args:
            yield arg
        for arg in super(service_add_smb, self).get_args():
            if arg not in self.smb_takes_args and not arg.primary_key:
                yield arg

    def get_options(self):
        """
        Rewrite options to service-add-smb command to filter out cannonical
        principal which is autoconstructed. Also filter out options which
        make no sense for SMB service.
        """
        excluded = ('ipakrbauthzdata', 'krbprincipalauthind',
                    'ipakrbrequirespreauth')
        for arg in self.takes_options:
            yield arg
        for arg in super(service_add_smb, self).get_options():
            check = all([
                arg not in self.takes_options, not arg.primary_key, arg.name
                not in excluded
            ])
            if check:
                yield arg

    def pre_callback(self, ldap, dn, entry_attrs, attrs_list, *keys,
                     **options):
        assert isinstance(dn, DN)
        hostname = keys[0]
        if len(keys) == 2:
            netbiosname = keys[1]
        else:
            # By default take leftmost label from the host name
            netbiosname = DNSName.from_text(hostname)[0].decode().upper()

        # SMB service requires existence of the host object
        # because DCE RPC calls authenticated with GSSAPI are using
        # host/.. principal by default for validation
        try:
            hostresult = self.api.Command['host_show'](hostname)['result']
        except errors.NotFound:
            raise errors.NotFound(
                reason=_("The host '%s' does not exist to add a service to.") %
                hostname)

        # We cannot afford the host not being resolvable even for
        # clustered environments with CTDB because the target name
        # has to exist even in that case
        util.verify_host_resolvable(hostname)

        smbaccount = '{name}$'.format(name=netbiosname)
        smbprincipal = 'cifs/{hostname}'.format(hostname=hostname)

        entry_attrs['krbprincipalname'] = [
            str(kerberos.Principal(smbprincipal, realm=self.api.env.realm)),
            str(kerberos.Principal(smbaccount, realm=self.api.env.realm))
        ]

        entry_attrs['krbcanonicalname'] = entry_attrs['krbprincipalname'][0]

        # Rewrite DN using proper rdn and new canonical name because when
        # LDAPCreate.execute() was called, it set DN to krbcanonicalname=$value
        dn = DN(('krbprincipalname', entry_attrs['krbcanonicalname']),
                DN(self.obj.container_dn, api.env.basedn))

        # Enforce ipaKrbPrincipalAlias to aid case-insensitive searches as
        # krbPrincipalName/krbCanonicalName are case-sensitive in Kerberos
        # schema
        entry_attrs['ipakrbprincipalalias'] = entry_attrs['krbcanonicalname']

        for o in ('ipakrbprincipal', 'ipaidobject', 'krbprincipalaux',
                  'posixaccount'):
            if o not in entry_attrs['objectclass']:
                entry_attrs['objectclass'].append(o)

        entry_attrs['uid'] = [
            '/'.join(kerberos.Principal(smbprincipal).components)
        ]
        entry_attrs['uid'].append(smbaccount)
        entry_attrs['cn'] = netbiosname
        entry_attrs['homeDirectory'] = '/dev/null'
        entry_attrs['uidNumber'] = DNA_MAGIC
        entry_attrs['gidNumber'] = DNA_MAGIC

        self.obj.validate_ipakrbauthzdata(entry_attrs)

        if 'managedby' not in entry_attrs:
            entry_attrs['managedby'] = hostresult['dn']

        update_krbticketflags(ldap, entry_attrs, attrs_list, options, False)

        return dn

    def post_callback(self, ldap, dn, entry_attrs, *keys, **options):
        set_kerberos_attrs(entry_attrs, options)
        rename_ipaallowedtoperform_from_ldap(entry_attrs, options)
        self.obj.populate_krbcanonicalname(entry_attrs, options)
        return dn
Пример #23
0
class vault_retrieve(ModVaultData):
    __doc__ = _('Retrieve a data from a vault.')

    takes_options = (
        Str(
            'out?',
            doc=_('File to store retrieved data'),
        ),
        Str(
            'password?',
            cli_name='password',
            doc=_('Vault password'),
        ),
        Str(  # TODO: use File parameter
            'password_file?',
            cli_name='password_file',
            doc=_('File containing the vault password'),
        ),
        Bytes(
            'private_key?',
            cli_name='private_key',
            doc=_('Vault private key'),
        ),
        Str(  # TODO: use File parameter
            'private_key_file?',
            cli_name='private_key_file',
            doc=_('File containing the vault private key'),
        ),
    )

    has_output_params = (Bytes(
        'data',
        label=_('Data'),
    ), )

    @classmethod
    def __NO_CLI_getter(cls):  # pylint: disable=unused-private-member, #4756
        return (api.Command.get_plugin('vault_retrieve_internal') is
                _fake_vault_retrieve_internal)

    NO_CLI = classproperty(__NO_CLI_getter)

    @property
    def api_version(self):
        return self.api.Command.vault_retrieve_internal.api_version

    def get_args(self):
        for arg in self.api.Command.vault_retrieve_internal.args():
            yield arg
        for arg in super(vault_retrieve, self).get_args():
            yield arg

    def get_options(self):
        for option in self.api.Command.vault_retrieve_internal.options():
            if option.name not in ('session_key', 'version'):
                yield option
        for option in super(vault_retrieve, self).get_options():
            yield option

    def get_output_params(self):
        for param in self.api.Command.vault_retrieve_internal.output_params():
            yield param
        for param in super(vault_retrieve, self).get_output_params():
            yield param

    def _iter_output(self):
        return self.api.Command.vault_retrieve_internal.output()

    def _unwrap_response(self, algo, nonce, vault_data):
        cipher = Cipher(algo, modes.CBC(nonce), backend=default_backend())
        # decrypt
        decryptor = cipher.decryptor()
        padded_data = decryptor.update(vault_data)
        padded_data += decryptor.finalize()
        # remove padding
        unpadder = PKCS7(algo.block_size).unpadder()
        json_vault_data = unpadder.update(padded_data)
        json_vault_data += unpadder.finalize()
        # load JSON
        return json.loads(json_vault_data.decode('utf-8'))

    def forward(self, *args, **options):
        output_file = options.get('out')

        password = options.get('password')
        password_file = options.get('password_file')
        private_key = options.get('private_key')
        private_key_file = options.get('private_key_file')

        # don't send these parameters to server
        if 'out' in options:
            del options['out']
        if 'password' in options:
            del options['password']
        if 'password_file' in options:
            del options['password_file']
        if 'private_key' in options:
            del options['private_key']
        if 'private_key_file' in options:
            del options['private_key_file']

        if self.api.env.in_server:
            backend = self.api.Backend.ldap2
        else:
            backend = self.api.Backend.rpcclient
        if not backend.isconnected():
            backend.connect()

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

        # get config
        transport_cert, wrapping_algo = self._get_vaultconfig()
        # let options override wrapping algo
        # For backwards compatibility do not send old legacy wrapping algo
        # to server. Only send the option when non-3DES is used.
        wrapping_algo = options.pop('wrapping_algo', wrapping_algo)
        if wrapping_algo != constants.VAULT_WRAPPING_3DES:
            options['wrapping_algo'] = wrapping_algo

        # generate session key
        algo = self._generate_session_key(wrapping_algo)
        # send retrieval request to server
        response = self.internal(algo, transport_cert, *args, **options)
        # unwrap data with session key
        vault_data = self._unwrap_response(algo, response['result']['nonce'],
                                           response['result']['vault_data'])
        del algo

        data = base64.b64decode(vault_data[u'data'].encode('utf-8'))
        encrypted_key = None

        if 'encrypted_key' in vault_data:
            encrypted_key = base64.b64decode(
                vault_data[u'encrypted_key'].encode('utf-8'))

        if vault_type == u'standard':

            pass

        elif vault_type == u'symmetric':

            salt = vault['ipavaultsalt'][0]

            # get encryption key from vault password
            if password and password_file:
                raise errors.MutuallyExclusiveError(
                    reason=_('Password specified multiple times'))

            elif password:
                pass

            elif password_file:
                password = validated_read('password-file',
                                          password_file,
                                          encoding='utf-8')
                password = password.rstrip('\n')

            else:
                password = self.api.Backend.textui.prompt_password(
                    'Password', confirm=False)

            # generate encryption key from password
            encryption_key = generate_symmetric_key(password, salt)

            # decrypt data with encryption key
            data = decrypt(data, symmetric_key=encryption_key)

        elif vault_type == u'asymmetric':

            # get encryption key with vault private key
            if private_key and private_key_file:
                raise errors.MutuallyExclusiveError(
                    reason=_('Private key specified multiple times'))

            elif private_key:
                pass

            elif private_key_file:
                private_key = validated_read('private-key-file',
                                             private_key_file,
                                             mode='rb')

            else:
                raise errors.ValidationError(
                    name='private_key', error=_('Missing vault private key'))

            # decrypt encryption key with private key
            encryption_key = decrypt(encrypted_key, private_key=private_key)

            # decrypt data with encryption key
            data = decrypt(data, symmetric_key=encryption_key)

        else:
            raise errors.ValidationError(name='vault_type',
                                         error=_('Invalid vault type'))

        if output_file:
            with open(output_file, 'wb') as f:
                f.write(data)

        else:
            response['result'] = {'data': data}

        return response
Пример #24
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

        role_config = backend.config_retrieve(role_name)
        for key, value in role_config.items():
            if value:
                entry_attrs.update({key: value})

    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)
Пример #25
0
class location(LDAPObject):
    """
    IPA locations
    """
    container_dn = api.env.container_locations
    object_name = _('location')
    object_name_plural = _('locations')
    object_class = ['top', 'ipaLocationObject']
    search_attributes = ['idnsName']
    default_attributes = ['idnsname', 'description']
    label = _('IPA Locations')
    label_singular = _('IPA Location')

    permission_filter_objectclasses = ['ipaLocationObject']
    managed_permissions = {
        'System: Read IPA Locations': {
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'objectclass',
                'idnsname',
                'description',
            },
            'default_privileges': {'DNS Administrators'},
        },
        'System: Add IPA Locations': {
            'ipapermright': {'add'},
            'default_privileges': {'DNS Administrators'},
        },
        'System: Remove IPA Locations': {
            'ipapermright': {'delete'},
            'default_privileges': {'DNS Administrators'},
        },
        'System: Modify IPA Locations': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'description',
            },
            'default_privileges': {'DNS Administrators'},
        },
    }

    takes_params = (
        DNSNameParam(
            'idnsname',
            cli_name='name',
            primary_key=True,
            label=_('Location name'),
            doc=_('IPA location name'),
            # dns name must be relative, we will put it into middle of
            # location domain name for location records
            only_relative=True,
        ),
        Str(
            'description?',
            label=_('Description'),
            doc=_('IPA Location description'),
        ),
        Str(
            'servers_server*',
            label=_('Servers'),
            doc=_('Servers that belongs to the IPA location'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
        Str(
            'dns_server*',
            label=_('Advertised by servers'),
            doc=_('List of servers which advertise the given location'),
            flags={'virtual_attribute', 'no_create', 'no_update', 'no_search'},
        ),
    )

    def get_dn(self, *keys, **options):
        loc = keys[0]
        assert isinstance(loc, DNSName)
        loc_a = loc.ToASCII()

        return super(location, self).get_dn(loc_a, **options)
Пример #26
0
class privilege(LDAPObject):
    """
    Privilege object.
    """
    container_dn = api.env.container_privilege
    object_name = _('privilege')
    object_name_plural = _('privileges')
    object_class = ['nestedgroup', 'groupofnames']
    permission_filter_objectclasses = ['groupofnames']
    default_attributes = ['cn', 'description', 'member', 'memberof']
    attribute_members = {
        'member': ['role'],
        'memberof': ['permission'],
    }
    reverse_members = {
        'member': ['permission'],
    }
    allow_rename = True
    managed_permissions = {
        'System: Read Privileges': {
            'replaces_global_anonymous_aci': True,
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'businesscategory',
                'cn',
                'description',
                'member',
                'memberof',
                'o',
                'objectclass',
                'ou',
                'owner',
                'seealso',
                'memberuser',
                'memberhost',
            },
            'default_privileges': {'RBAC Readers'},
        },
        'System: Add Privileges': {
            'ipapermright': {'add'},
            'default_privileges': {'Delegation Administrator'},
        },
        'System: Modify Privileges': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {
                'businesscategory',
                'cn',
                'description',
                'o',
                'ou',
                'owner',
                'seealso',
            },
            'default_privileges': {'Delegation Administrator'},
        },
        'System: Remove Privileges': {
            'ipapermright': {'delete'},
            'default_privileges': {'Delegation Administrator'},
        },
    }

    label = _('Privileges')
    label_singular = _('Privilege')

    takes_params = (
        Str(
            'cn',
            cli_name='name',
            label=_('Privilege name'),
            primary_key=True,
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('Privilege description'),
        ),
    )
Пример #27
0
class json_metadata(Command):
    """
    Export plugin meta-data for the webUI.
    """
    NO_CLI = True

    takes_args = (
        Str(
            'objname?',
            doc=_('Name of object to export'),
        ),
        Str(
            'methodname?',
            doc=_('Name of method to export'),
        ),
    )

    takes_options = (
        Str(
            'object?',
            doc=_('Name of object to export'),
        ),
        Str(
            'method?',
            doc=_('Name of method to export'),
        ),
        Str(
            'command?',
            doc=_('Name of command to export'),
        ),
    )

    has_output = (
        Output('objects', dict, doc=_('Dict of JSON encoded IPA Objects')),
        Output('methods', dict, doc=_('Dict of JSON encoded IPA Methods')),
        Output('commands', dict, doc=_('Dict of JSON encoded IPA Commands')),
    )

    def execute(self, objname, methodname, **options):
        objects = dict()
        methods = dict()
        commands = dict()

        empty = True

        try:
            if not objname:
                objname = options['object']
            if objname in self.api.Object:
                o = self.api.Object[objname]
                objects = dict([(o.name, json_serialize(o))])
            elif objname == "all":
                objects = dict(
                    (o.name, json_serialize(o)) for o in self.api.Object())
            empty = False
        except KeyError:
            pass

        try:
            if not methodname:
                methodname = options['method']
            if methodname in self.api.Method:
                m = self.api.Method[methodname]
                methods = dict([(m.name, json_serialize(m))])
            elif methodname == "all":
                methods = dict(
                    (m.name, json_serialize(m)) for m in self.api.Method())
            empty = False
        except KeyError:
            pass

        try:
            cmdname = options['command']
            if cmdname in self.api.Command:
                c = self.api.Command[cmdname]
                commands = dict([(c.name, json_serialize(c))])
            elif cmdname == "all":
                commands = dict(
                    (c.name, json_serialize(c)) for c in self.api.Command())
            empty = False
        except KeyError:
            pass

        if empty:
            objects = dict(
                (o.name, json_serialize(o)) for o in self.api.Object())
            methods = dict(
                (m.name, json_serialize(m)) for m in self.api.Method())
            commands = dict(
                (c.name, json_serialize(c)) for c in self.api.Command())

        retval = dict([
            ("objects", objects),
            ("methods", methods),
            ("commands", commands),
        ])

        return retval

    def output_for_cli(self, textui, result, *args, **options):
        print(json.dumps(result, default=json_serialize))
Пример #28
0
class passwd(Command):
    __doc__ = _("Set a user's password.")

    takes_args = (
        Str(
            'principal',
            validate_principal,
            cli_name='user',
            label=_('User name'),
            primary_key=True,
            autofill=True,
            default_from=lambda: util.get_current_principal(),
            normalizer=lambda value: normalize_principal(value),
        ),
        Password(
            'password',
            label=_('New Password'),
        ),
        Password(
            'current_password',
            label=_('Current Password'),
            confirm=False,
            default_from=lambda principal: get_current_password(principal),
            autofill=True,
            sortorder=-1,
        ),
    )

    takes_options = (Password(
        'otp?',
        label=_('OTP'),
        doc=_('One Time Password'),
        confirm=False,
    ), )

    has_output = output.standard_value
    msg_summary = _('Changed password for "%(value)s"')

    def execute(self, principal, password, current_password, **options):
        """
        Execute the passwd operation.

        The dn should not be passed as a keyword argument as it is constructed
        by this method.

        Returns the entry

        :param principal: The login name or principal of the user
        :param password: the new password
        :param current_password: the existing password, if applicable
        """
        ldap = self.api.Backend.ldap2

        entry_attrs = ldap.find_entry_by_attr(
            'krbprincipalname', principal, 'posixaccount', [''],
            DN(api.env.container_user, api.env.basedn))

        if principal == getattr(context, 'principal') and \
            current_password == MAGIC_VALUE:
            # No cheating
            self.log.warn(
                'User attempted to change password using magic value')
            raise errors.ACIError(info=_('Invalid credentials'))

        if current_password == MAGIC_VALUE:
            ldap.modify_password(entry_attrs.dn, password)
        else:
            otp = options.get('otp')
            ldap.modify_password(entry_attrs.dn, password, current_password,
                                 otp)

        return dict(
            result=True,
            value=principal,
        )
Пример #29
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'
    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,
                                             })
Пример #30
0
class hostgroup(LDAPObject):
    """
    Hostgroup object.
    """
    container_dn = api.env.container_hostgroup
    object_name = _('host group')
    object_name_plural = _('host groups')
    object_class = ['ipaobject', 'ipahostgroup']
    permission_filter_objectclasses = ['ipahostgroup']
    search_attributes = ['cn', 'description', 'member', 'memberof']
    default_attributes = [
        'cn',
        'description',
        'member',
        'memberof',
        'memberindirect',
        'memberofindirect',
        'membermanager',
    ]
    uuid_attribute = 'ipauniqueid'
    allow_rename = True
    attribute_members = {
        'member': ['host', 'hostgroup'],
        'membermanager': ['user', 'group'],
        'memberof': ['hostgroup', 'netgroup', 'hbacrule', 'sudorule'],
        'memberindirect': ['host', 'hostgroup'],
        'memberofindirect': ['hostgroup', 'hbacrule', 'sudorule'],
    }
    managed_permissions = {
        'System: Read Hostgroups': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'businesscategory',
                'cn',
                'description',
                'ipauniqueid',
                'o',
                'objectclass',
                'ou',
                'owner',
                'seealso',
                'membermanager',
            },
        },
        'System: Read Hostgroup Membership': {
            'replaces_global_anonymous_aci': True,
            'ipapermbindruletype': 'all',
            'ipapermright': {'read', 'search', 'compare'},
            'ipapermdefaultattr': {
                'member',
                'memberof',
                'memberuser',
                'memberhost',
            },
        },
        'System: Add Hostgroups': {
            'ipapermright': {'add'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Add Hostgroups";allow (add) groupdn = "ldap:///cn=Add Hostgroups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Host Group Administrators'},
        },
        'System: Modify Hostgroup Membership': {
            'ipapermright': {'write'},
            'ipapermtargetfilter': [
                '(objectclass=ipahostgroup)',
                '(!(cn=ipaservers))',
            ],
            'ipapermdefaultattr': {'member'},
            'replaces': [
                '(targetattr = "member")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Modify Hostgroup membership";allow (write) groupdn = "ldap:///cn=Modify Hostgroup membership,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Host Group Administrators'},
        },
        'System: Modify Hostgroups': {
            'ipapermright': {'write'},
            'ipapermdefaultattr': {'cn', 'description', 'membermanager'},
            'replaces': [
                '(targetattr = "cn || description")(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0; acl "permission:Modify Hostgroups";allow (write) groupdn = "ldap:///cn=Modify Hostgroups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Host Group Administrators'},
        },
        'System: Remove Hostgroups': {
            'ipapermright': {'delete'},
            'replaces': [
                '(target = "ldap:///cn=*,cn=hostgroups,cn=accounts,$SUFFIX")(version 3.0;acl "permission:Remove Hostgroups";allow (delete) groupdn = "ldap:///cn=Remove Hostgroups,cn=permissions,cn=pbac,$SUFFIX";)',
            ],
            'default_privileges': {'Host Group Administrators'},
        },
    }

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

    takes_params = (
        Str(
            'cn',
            pattern=NETGROUP_PATTERN,
            pattern_errmsg=NETGROUP_PATTERN_ERRMSG,
            cli_name='hostgroup_name',
            label=_('Host-group'),
            doc=_('Name of host-group'),
            primary_key=True,
            normalizer=lambda value: value.lower(),
        ),
        Str(
            'description?',
            cli_name='desc',
            label=_('Description'),
            doc=_('A description of this host-group'),
        ),
    )

    def suppress_netgroup_memberof(self, ldap, dn, entry_attrs):
        """
        We don't want to show managed netgroups so remove them from the
        memberOf list.
        """
        hgdn = DN(dn)
        for member in list(entry_attrs.get('memberof', [])):
            ngdn = DN(member)
            if ngdn['cn'] != hgdn['cn']:
                continue

            filter = ldap.make_filter({'objectclass': 'mepmanagedentry'})
            try:
                ldap.get_entries(ngdn, ldap.SCOPE_BASE, filter, [''])
            except errors.NotFound:
                pass
            else:
                entry_attrs['memberof'].remove(member)